2 # KIX server version 0.99.3
3 # To compile run: sh kix.c
4 # Help is then available: ./kix -h
6 # Network configuration options background:
7 # -----------------------------------------
8 # Each argument on command-line specifies the net adress of the peer
9 # where to send all the packets to. In the simplest configuration
10 # where you have only two hosts (with arbitrary network between them):
12 # BOX_A <-> .. {some TCP/IP network} .. <-> BOX_B
14 # There will be the following configuration:
15 # On BOX_A: ./kix BOX_B
16 # On BOX_B: ./kix BOX_A
18 # You can also specify the network broadcast address - in network
19 # 192.168.1.xxx you have the netmask 255.255.255.0:
21 # BOX_A (192.168.1.1) BOX_B (192.168.1.2) BOX_C (192.168.1.10)
23 # \------{Ethernet}------+------{Ethernet}-------/
25 # There will be the following configuration:
26 # On BOX_A, BOX_B and BOX_C: ./kix 192.168.1.255
28 # Advanced networking - packet forwarding:
30 # !!! NOT TESTED YET !!! - Please send me <short@ucw.cz> some
31 # success/failure report.
33 # !!! Warning: You can very easily configure packet loops by using
34 # forwarding options (':' sign). You have been warned.
36 # To optimize broadcasting behaviour you can direct some of KIX servers
37 # to forward the packets to distant/firewalled hosts. The standard
38 # behaviour of KIX when it receives the remote data broadcast packet
39 # is to distribute it to all its LOCAL clients but to never pass it
40 # further. Bu specifying some host(s) after the colon (':'):
42 # HOST_TO_FORWARD_TO:SOURCE_HOST(S)
44 # This line says: When I receive packet from SOURCE_HOST, I should
45 # pass it to HOST_TO_FORWARD_TO. Some example:
47 # BOX_X <-> .. {some TCP/IP network} <-> BOX_A (192.168.1.1)
49 # /-{Ethernet}-+-{Ethernet}-\
51 # BOX_B (192.168.1.2) BOX_C (192.168.1.10)
53 # Setup with direct TCP/IP broadcasting through the network (recommended):
54 # On BOX_X : ./kix 192.168.1.255
55 # On BOX_A : ./kix BOX_X:196.168.1.0/24
56 # On BOX_B/C: ./kix 192.168.1.255
58 # Setup with KIX-manual forwaring (more interesting but unneeded/wasteful):
59 # On BOX_X : ./kix BOX_A
60 # On BOX_A : ./kix 192.168.1.255:KIX_A KIX_X:192.168.1.0/24
61 # On BOX_B/C: ./kix 192.168.1.255
64 # Copyright (C) 1998 Jan Kratochvil <short@ucw.cz>
65 # Special thanks to Vojtech Pavlik <vojtech@ucw.cz>
66 # for testing and suggestions.
68 # This program is free software; you can redistribute it and/or modify
69 # it under the terms of the GNU General Public License as published by
70 # the Free Software Foundation; you must use exactly version 2.
72 # This program is distributed in the hope that it will be useful,
73 # but WITHOUT ANY WARRANTY; without even the implied warranty of
74 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
75 # GNU General Public License for more details.
77 # You may download a copy of the GNU General Public License from URL
78 # http://www.opensource.org/gpl-license.html
79 # If not, write to the Free Software Foundation,
80 # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
82 echo "Compiling KIX server..."
84 b="-s -Wall -O6 -fexpensive-optimizations -fomit-frame-pointer"
85 c="-o `basename "$0" .c` $0"
87 if $a $b $c;then echo -n
90 else echo "Failed - please check the output.";exit
98 /* MULTI_LOCAL: Support multiple localhost clients & PID detection
100 * - needed to be able to run multiple clients on this single host
101 * communicating each other
103 * - probably supported only under Linux (/proc needed to be mounted!)
104 * (see kaddrmapper(): UDP port -> PID mapping function)
106 * - requires "root" permissions for this KIX server to use this feature
107 * (under normal-user will KIX behave as w/o this feature compiled in)
109 * - isn't 100% rock solid as w/D1X it has to complete the search under 100ms!
112 #define QUIET_PIDFAIL
113 /* QUIET_PIDFAIL: Don't report errors on PID detection
115 * - don't report errors if the requested process couldn't be found
116 * - probably good to be enabled as error dumping will slowdown KIX and
117 * the search will so much more fail during the next attempted search
120 #define IDLE_TIMEOUT 30*60
121 /* IDLE_TIMEOUT: Idle time in seconds to terminate if run from inetd
124 #define SYSLOG_NAMES 1
125 #define _GNU_SOURCE 1
129 #include <sys/types.h>
130 #include <sys/socket.h>
131 #include <netinet/in.h>
140 #include <sys/resource.h>
149 #define VERSION "0.99.3"
150 #define SERVICE_PORT 4213
152 #define HOSTNAME_RESOLVE
153 #define SETPRIORITY -50
154 #define INETD_SOCKET 0
155 #define PATH_PROC "/proc"
156 #define PATH_PROC_NET_UDP PATH_PROC "/net/udp"
157 #define PATH_PROC_X_FD PATH_PROC "/%s/fd"
158 /* NOT working as of glibc-2.0.7: */
159 #undef DIRENT_HAVE_D_TYPE_WORKS
175 #define __NORETURN __attribute__((__noreturn__))
182 #define LINE_MAX 4096
185 #define TOSTRING(x) #x
186 #define ARRSIZE(x) (sizeof((x))/sizeof(*(x)))
188 int mainudp,bufl,peerstot,sendoffs;
190 unsigned char buf[BUFSIZE];
197 kaddrt mykaddr,remkaddr,*shipaddr=&remkaddr;
203 unsigned a,m; /* host byte-order! */
210 } *logfs,**logfsp=&logfs;
212 const kaddrt kbroad={{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
221 #ifdef HOSTNAME_RESOLVE
227 char quiet=0,debug=0,mapperfail=0,noportprint=0,logsyslog=0,logfsdone=0;
231 kaddrt kaddr; /* [0..3]=IN addr, [4..5]=XORed PID */
232 kaddrt gwaddr; /* remote gateway w/SERVICE_PORT or "mykaddr" w/current UDP port */
233 unsigned short kport; /* KIX socket */
234 pid_t clpid; /* PID */
235 char *clname; /* process name */
236 char opened; /* bool, informational */
240 const unsigned char iKIX[3]={'K','I','X'};
242 void (*errouth)(void);
246 #define MSGSIZECHK() do { if (msgi>=sizeof(msg)-2) return; } while (0)
248 #define minit() msgi=0
250 static void moutf(FILE *f)
251 { fprintf(f,"%s: %s\n",pname,msg); }
253 static void mout(int level)
260 if (!logfsdone || (!logfs && !logsyslog)) moutf(stdout);
262 for (lf=logfs;lf;lf=lf->next) moutf(lf->f);
263 if (logsyslog) syslog(level,"%s",msg);
267 static void mvprintf(const char *fmt,va_list ap) __attribute__((format(printf,1,0)));
268 static void mvprintf(const char *fmt,va_list ap)
272 if ((i=vsnprintf(msg+msgi,sizeof(msg)-1-msgi,fmt,ap))>=0) msgi+=i;
274 static void mprintf(const char *fmt,...) __attribute__((format(printf,1,2)));
275 static void mprintf(const char *fmt,...)
276 { va_list ap; va_start(ap,fmt); mvprintf(fmt,ap); va_end(ap); }
278 static void mputchar(char c)
279 { MSGSIZECHK(); msg[msgi++]=c; }
281 static void verrout(const char *fmt,va_list ap) __attribute__((format(printf,1,0)));
282 static void verrout(const char *fmt,va_list ap)
284 char fatal=0,showerr=0;
287 if (*fmt=='^') { fatal =1; fmt++; }
288 if (!fatal && quiet) return;
289 if (*fmt=='&') { showerr=1; fmt++; waserr=errno; }
291 if (fatal) mprintf("FATAL: ");
292 if (errouth) errouth();
294 if (showerr) mprintf(" (%s)",strerror(waserr));
295 if (fatal) mputchar('!');
297 if (fatal) exit(EXIT_FAILURE);
300 static void errout(const char *fmt,...)
308 static void chk(void *p)
311 errout("^Out of memory");
313 #define chknew(a) chk((a)=malloc(sizeof(*(a))))
315 static void addrdump(const kaddrt *kap)
320 he=gethostbyaddr((char *)(kap->a+0),4,AF_INET);
321 if (he) mprintf("%s",he->h_name);
323 mprintf("[%u.%u.%u.%u]",kap->a[0],kap->a[1],kap->a[2],kap->a[3]);
324 if (!noportprint) mprintf(":%u",ntohs(*(unsigned short *)(kap->a+4)));
327 static void pkterrh(void)
336 mprintf("%d/",bufl-sendoffs);
338 for (i=sendoffs;i<bufl;i++) {
339 mprintf("%c%02X",sep,buf[i]);
343 for (i=sendoffs;i<bufl;i++) {
344 if (isprint(buf[i])) mputchar(buf[i]);
352 static void pkterr(char *fmt,...)
363 #define addreq(a,b) ((a).sin_port==(b).sin_port&&(a).sin_addr.s_addr==(b).sin_addr.s_addr)
365 #define getclipk(k) getclipoffs((k),offsetof(struct cli, kaddr))
366 #define getclipgw(k) getclipoffs((k),offsetof(struct cli,gwaddr))
367 static struct cli **getclipoffs(const kaddrt *kap,size_t offs)
369 struct cli **clip,*cli;
370 for (clip=&clis;(cli=*clip);clip=&cli->next)
371 if (!memcmp(kap,((char *)cli)+offs,6)) break;
375 static void shipout(void)
378 struct sockaddr_in sin;
380 if (debug) pkterr("Sending...");
381 sin.sin_family=AF_INET;
382 if (!memcmp(shipaddr->a+0,mykaddr.a+0,4))
383 sin.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
384 else memcpy(&sin.sin_addr,shipaddr->a+0,4);
385 memcpy(&sin.sin_port,shipaddr->a+4,2);
386 if (fcntl(mainudp,F_SETFL,O_NONBLOCK)) errout("&fcntl(mainudp,O_NONBLOCK)");
387 if ((got=sendto(mainudp,buf+sendoffs,bufl-sendoffs,0,(struct sockaddr *)&sin,sizeof(sin)))!=bufl-sendoffs)
388 if (errno!=ECONNREFUSED) pkterr("&sendto(%d) error, wrote %d",bufl-sendoffs,got);
389 if (fcntl(mainudp,F_SETFL,0 )) errout("&fcntl(mainudp,0)" );
392 static void fillhost(const char *hname,kaddrt *kap)
395 if (!(he=gethostbyname(hname))) errout("^&gethostbyname(\"%s\")",hname);
396 if (he->h_addrtype!=AF_INET || he->h_length!=4)
397 errout("^\"%s\": addrtype!=AF_INET || length!=4",hname);
398 if (!*he->h_addr_list)
399 errout("^\"%s\": empty address list",hname);
400 assert(sizeof(*kap)==6);
401 memcpy(kap->a+0,*he->h_addr_list,4);
402 *((unsigned short *)(kap->a+4))=htons(SERVICE_PORT);
405 static void kaddrdump(const kaddrt *kap)
411 for (i=0;i<6;i++) mprintf("%02X",kap->a[i]);
415 static void clistate(struct cli *cli,const char *fmt,...)
422 va_start(ap,fmt); mvprintf(fmt,ap); va_end(ap);
424 dbg(mprintf("(cli=%p) ",cli));
425 if ((local=!memcmp(&cli->gwaddr,mykaddr.a+0,4))) mprintf("local ");
427 kaddrdump(&cli->kaddr);
428 if (!local) { mprintf(" via "); addrdump(&cli->gwaddr); }
429 mprintf(", kixport %u, process \"%s\"/%lu, %sed",ntohs(cli->kport),cli->clname,(unsigned long)ntohl(cli->clpid),
430 (cli->opened?"open":"clos"));
434 static void iKIXregister(void)
435 {/* KIXrDDDDDDkpPID_[NAME] */
436 struct cli **clip,*cli;
437 struct sockaddr_in addr;
440 addr.sin_family=AF_INET;
441 if (!(cli=*(clip=getclipk((kaddrt *)(buf+4))))) {
442 chknew(cli); *clip=cli;
444 cli->kaddr=*(kaddrt *)(buf+4);
451 cli->gwaddr=remkaddr;
452 memcpy(&cli->kport,buf+10,2);
453 memcpy(&cli->clpid,buf+12,4);
454 chk(cli->clname=malloc(bufl-16+1));
455 memcpy(cli->clname,buf+16,bufl-16);
456 cli->clname[bufl-16]='\0';
458 clistate(cli,"iKIXregister%s%s ",
459 (ost==1?",socket opened again" :""),
460 (ost==0?",socket opened after being closed":""));
463 static void iKIXunregister(void)
465 struct cli **clip,*cli;
467 for (clip=&clis;(cli=*clip);clip=&cli->next) {
468 if (memcmp(&cli->kaddr,buf+4,6)) continue;
469 clistate(cli,"iKIXunregister%s",
470 (!cli->opened?",already closed!":""));
475 static void iKIXdata(void)
476 {/* KIXdDDDDDDssssssDKskDATA... */
478 char isbroad=!memcmp(buf+4,&kbroad,6);
479 unsigned char obyte=buf[9];
482 buf[9]=0x03; /* net data */
483 for (tocli=clis;tocli;tocli=tocli->next) {
484 if (tocli==cli) continue; /* Do not echo packets back */
485 if (memcmp(tocli->gwaddr.a+0,mykaddr.a+0,4)) continue;
486 if (memcmp(&tocli->kport,buf+16,2)) continue;
488 (memcmp(tocli->kaddr.a+0,buf+4 ,5) || tocli->kaddr.a[5]!=obyte)) continue;
489 shipaddr=&tocli->gwaddr;
497 static void iKIXforward(void)
500 unsigned remha=(unsigned)ntohl(*(unsigned long *)(remkaddr.a+0));
502 for (i=0;i<peerstot;i++) {
503 struct peersrc *ps=peers[i]->src;
504 for (j=0;j<peers[i]->cnt;ps++,j++)
505 if (ps->a==(remha&ps->m)) {
506 shipaddr=&peers[i]->dst;
514 static void shippeers(void)
518 for (i=0;i<peerstot;i++) {
519 shipaddr=&peers[i]->dst;
525 static void sigalarm(int signo)
529 mprintf("Exiting due to communications inactivity.");
537 #define KAM_LOCAL_ADDRESS "local_address"
538 #define KAM_INODE "inode"
539 #define KAM_SOCKET_X "socket:[%s]"
541 static pid_t kaddrmapper(const kaddrt *kap)
545 int procfdlen,findsklen;
546 char c,*s,*s2,*serr,*ixla,*ixin;
548 char findla[14],findsk[20],cmpsk[sizeof(findsk)];
550 const char *kamfailerr;
551 DIR *dirproc=NULL,*dirfd=NULL;
552 struct dirent *direproc,*direfd;
554 __NORETURN void kamfail(const char *why)
555 { errout(kamfailerr+(*why!='&'),why+(*why=='&')); mapperfail=1; longjmp(jmp,1); }
558 if (dirproc) { if (closedir(dirproc)) errout("&closedir(\"" PATH_PROC "\")"); dirproc=NULL; }
559 if (dirfd ) { if (closedir(dirfd )) errout("&closedir(\"" PATH_PROC_X_FD "\")","<unknown>"); dirfd =NULL; }
565 r=!fgets(line,sizeof(line),f);
566 if (errno) kamfail("&fgets");
569 void walkerinit(void) { c=*(s2=line); }
573 while (*s!='\n'&&isspace(*s)) s++;
574 for (s2=s;!isspace(*s2)&&*s2&&*s2!='\n';s2++);
575 if (!(c=*s2)) kamfail("No EOL NL");
576 if (c=='\n') return(1);
581 if (mapperfail) return(-1);
586 kamfailerr="&%s(\"" PATH_PROC_NET_UDP "\",r/o) (multi-local disabled)";
587 if (snprintf(findla,14,"%08lX:%04X",
588 *(unsigned long *)(kap->a+0) , /* !ntohl() is IMHO kernel bug */
589 (unsigned short)ntohs(*(unsigned short *)(kap->a+4)))!=13)
590 kamfail("Internal - snprintf()");
591 if (!(f=fopen(PATH_PROC_NET_UDP,"rt"))) kamfail("&fopen");
592 if (nextline()) kamfail("No header line");
593 ixla=NULL; ixin=NULL;
597 if (!ixla && !strcmp(s,KAM_LOCAL_ADDRESS)) ixla=s;
598 if (!ixin && !strcmp(s,KAM_INODE )) ixin=s;
600 if (!ixla) kamfail("\"" KAM_LOCAL_ADDRESS "\" not found");
601 if (!ixin) kamfail("\"" KAM_INODE "\" not found");
603 while (!nextline()) {
605 while (s2<=ixla || s2<=ixin) {
606 if (walker()) kamfail("Not enough columns");
607 if (ixla==s && strcmp(s,findla)) { findsklen=-1; break; }
609 findsklen=snprintf(findsk,sizeof(findsk),KAM_SOCKET_X,s);
610 if (findsklen<=0 || findsklen>=sizeof(findsk)-1) kamfail("&\"" KAM_INODE "\" parse error");
614 if (findsklen>=0) break;
616 if (findsklen<0) strcpy(findsk,"<unknown>");
618 kamfailerr="&%s(\"" PATH_PROC "\" scanning) (multi-local disabled)";
619 if (!(dirproc=opendir(PATH_PROC))) kamfail("&opendir");
620 while (errno=0,direproc=readdir(dirproc)) {
621 #ifdef DIRENT_HAVE_D_TYPE_WORKS
622 if (direproc->d_type!=DT_DIR) continue;
624 pidn=strtol(direproc->d_name,&serr,10);
625 if (pidn<=0 || pidn>=LONG_MAX || *serr) continue;
626 procfdlen=snprintf(line,sizeof(line),PATH_PROC_X_FD,direproc->d_name);
627 if (procfdlen<=0 || procfdlen>=sizeof(line)-5) continue;
629 if (!(dirfd=opendir(line))) {
630 if (errno==EPERM || errno==EACCES) kamfail("&opendir");
634 while ((direfd=readdir(dirfd))) {
635 #ifdef DIRENT_HAVE_D_TYPE_WORKS
636 if (direfd->d_type!=DT_LNK) continue;
638 if (procfdlen+1+strlen(direfd->d_name)+1>sizeof(line)) continue;
639 strcpy(line+procfdlen+1,direfd->d_name);
640 if (readlink(line,cmpsk,findsklen+1)!=findsklen) continue;
641 if (memcmp(findsk,cmpsk,findsklen)) continue;
647 if (!direproc && errno) kamfail("&readdir");
649 #ifndef QUIET_PIDFAIL
652 mprintf("Process PID not found for ");
654 mprintf(" (la=\"%s\", sk=\"%s\")!",findla,findsk);
664 static void doversion(void)
667 I'm KIX, version " VERSION " compiled on \""__DATE__" "__TIME__"\" from \""__FILE__"\" by \""__VERSION__"\"\n\
668 Copyright (C) 1998 Jan Kratochvil <short@ucw.cz>\n\
669 This is free software with ABSOLUTELY NO WARRANTY. See the sources for details:\n\
670 http://atrey.karlin.mff.cuni.cz/~short/sw/kix.c.gz\n\
674 const char *longdesc[]={
675 "display this help and exit",
676 "display just version number and exit",
677 "only serious errors are reported",
678 "send all the messages (also) to this file\n\
679 " "defaults to stdout (\"-\"), multiple occurences allowed",
680 "send all the messages to syslog as the specified facility\n\
681 " "see openlog(3): \"daemon\", \"user\", \"local0\", ...",
682 "dump all the packets being communicated",
684 "disable support of multiple localhost clients",
686 "don't resolve hostnames",
687 "set such process priority (x<0 runs faster!)\n\
688 " "value \"-\" will leave the priority untouched",
689 "terminate when such seconds idle, defaults to:\n\
690 " "infinity(=0) if as standalone, IDLE_TIMEOUT if from inetd",
693 const struct option longopts[]={
708 static __NORETURN void dohelp(void)
714 Syntax: kix [-h] [-V] [-q] [-l <filename>] [-s <facility>]\n\
719 " [-n] [-p <pri>] [-t <timeout>]\n\
720 [<to peer>[{:|,}<from peer>[/{netbits|netmask}]]...]...\n\
722 for (i=0;i<ARRSIZE(longopts);i++) {
724 printf(" -%c,--%-7s ",longopts[i].val,longopts[i].name);
725 for (cs=longdesc[i];;cs=cse+1)
726 if (!(cse=strchr(cs,'\n'))) {
732 snprintf(fbuf,sizeof(fbuf),"%%.%ds\n%%16s",cse-cs);
737 <to peer> host to also send all the packets to\n\
738 <from peer> forward packets if received from this peer\n\
739 packets are forwarded to the <to peer>\n\
740 netmask \"255.255.255.0\" equals netbits \"24\"\n\
742 inetd - For automatic run add the next line to /etc/inetd.conf:\n\
743 4213 dgram udp wait root /usr/bin/kix kix -s daemon PEER_ARGUMENTS\n\
748 int main(int argc,char **argv)
751 unsigned sotl=sizeof(sot);
752 char localaddr,remremote;
753 struct sockaddr_in anyaddr,remaddr;
757 assert(sizeof(remkaddr)==6);
758 assert(sizeof(unsigned)==4);
763 if (gethostname((char *)buf,sizeof(buf))) errout("^&gethostname()");
764 fillhost((char *)buf,&mykaddr);
766 while ((optc=getopt_long(argc,argv,"hVql:s:d"
770 "np:t:",longopts,NULL))!=EOF) switch (optc) {
771 case 'V': doversion(); exit(EXIT_FAILURE);
772 case 'q': quiet=1; break;
776 if (!(lf->f=fopen(optarg,"at"))) errout("^&fopen(\"%s\",append)",optarg);
783 for (i=0;i<ARRSIZE(facilitynames);i++)
784 if (!strcasecmp(optarg,facilitynames[i].c_name)) break;
785 if (i>=ARRSIZE(facilitynames)) errout("^Unknown syslog facility \"%s\"",optarg);
786 openlog("kix",LOG_PID,facilitynames[i].c_val);
789 case 'd': debug=1; break;
791 case '1': mapperfail=1; break;
793 case 'n': noresolve=1; break;
794 #define NUMPARSE_ERR "^\"-%c\" number \"%s\" parse error, offending: %s"
797 if (!strcmp(optarg,"-")) { setprio=LONG_MAX; break; }
798 setprio=strtol(optarg,&serr,10);
799 if (setprio<=INT_MIN || setprio >=INT_MAX || *serr) errout(NUMPARSE_ERR,'p',optarg,serr);
803 idletmout=strtol(optarg,&serr,10);
804 if (idletmout<0 || idletmout>=INT_MAX || *serr) errout(NUMPARSE_ERR,'t',optarg,serr);
806 default: /* also 'h' */
810 if ((peerstot=(argc-optind))) {
811 chk(peers=malloc(sizeof(*peers)*(argc-optind)));
812 for (i=0;i<peerstot;i++) {
815 chk(s=strdup(argv[optind+i]));
816 for (s2=s;*s2;s2++) if (*s2==':' || *s2==',') { *s2='\0'; comps++; }
817 chk(peers[i]=malloc(sizeof(**peers)+sizeof(struct peersrc)*(comps-1)));
818 fillhost(s,&peers[i]->dst);
819 if ((peers[i]->cnt=comps)) {
820 struct peersrc *ps=peers[i]->src;
826 for (s2=s;*s2;s2++) if (*s2=='/') { mask=0; *s2++='\0'; break; }
827 fillhost(s,&fakehost);
828 ps->a=(unsigned)ntohl(*(unsigned long *)(fakehost.a+0));
832 ll=strtol(s2,&serr,10);
833 if (ll>=0 && ll<=32) while (ll--) mask=(mask>>1U)|(1U<<31U);
835 fillhost(s2,&fakehost);
836 mask=(unsigned)ntohl(*(unsigned long *)(fakehost.a+0));
841 while (mask&(1U<<31U)) mask<<=1U;
842 if (mask) errout("^Specified netmask (0x%08X) is invalid",ps->m);
852 getsockopt(INETD_SOCKET,SOL_SOCKET,SO_TYPE,&sot,&sotl);
853 if (errno && errno!=ENOTSOCK) errout("&getsockopt(" TOSTRING(INETD_SOCKET) ",SO_TYPE)");
854 if (!errno && sotl==sizeof(sot) && sot==SOCK_DGRAM) mainudp=INETD_SOCKET;
856 mainudp=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
857 if (mainudp==-1 || mainudp==INETD_SOCKET) errout("^&socket()");
859 anyaddr.sin_family=AF_INET;
860 anyaddr.sin_addr.s_addr=htonl(INADDR_ANY);
861 anyaddr.sin_port=htons(SERVICE_PORT);
862 if (bind(mainudp,(struct sockaddr *)&anyaddr,sizeof(anyaddr))) errout("^&bind(%d)",SERVICE_PORT);
864 if (!setidletmout) idletmout=(mainudp==INETD_SOCKET?IDLE_TIMEOUT:0);
867 mprintf("KIX v" VERSION " on ");
869 mprintf(", pri %d",getpriority(PRIO_PROCESS,0));
871 if (setprio!=LONG_MAX) {
872 if (setpriority(PRIO_PROCESS,0,SETPRIORITY))
873 { if (!quiet) mprintf(" left - %s",strerror(errno)); }
874 else if (!quiet) mprintf(" -> %d",getpriority(PRIO_PROCESS,0));
878 mprintf(", %s, ",(mainudp==INETD_SOCKET?"inetd":"standalone"));
879 if ((rtm=idletmout)) {
880 mprintf("timeout is");
881 if (rtm>=3600) { mprintf(" %dhrs",rtm/3600); rtm%=3600; }
882 if (rtm>= 60) { mprintf(" %dmin",rtm/ 60); rtm%= 60; }
883 if (rtm>= 1) mprintf(" %dsec",rtm );
885 else mprintf("no timeout");
891 mprintf("InterKIX to<from>:");
892 for (i=0;i<peerstot;i++) {
893 struct peersrc *ps=peers[i]->src;
895 addrdump(&peers[i]->dst);
896 for (j=0;j<peers[i]->cnt;ps++,j++) {
900 *(unsigned long *)(fakehost.a+0)=(unsigned long)htonl(ps->a);
902 if ((mask=ps->m)==-1) continue;
903 for (mcnt=0;mask;mcnt++) mask<<=1U;
906 if (j) mputchar('>');
912 if (setsockopt(mainudp,SOL_SOCKET,SO_BROADCAST,&val_one,sizeof(val_one)))
913 errout("&setsockopt(mainudp,SO_BROADCAST)");
914 signal(SIGALRM,sigalarm);
918 remaddrl=sizeof(remaddr);
920 bufl=recvfrom(mainudp,&buf,sizeof(buf),0,(struct sockaddr *)&remaddr,&remaddrl);
922 if (bufl==-1) { if (errno!=ECONNREFUSED) errout("&recvfrom: bufl=-1"); goto pktfail; }
923 if (remaddr.sin_family!=AF_INET)
924 { errout("recvfrom: sin_family %u!=AF_INET (%u)",remaddr.sin_family,AF_INET); goto pktfail; }
925 localaddr=(ntohl(remaddr.sin_addr.s_addr)==INADDR_LOOPBACK || !memcmp(&remaddr.sin_addr,mykaddr.a+0,4));
926 remremote=(ntohs(remaddr.sin_port)==SERVICE_PORT);
927 if (localaddr && remremote) goto pktfail; /* Talking to yourself, Graham? */
928 if (!localaddr && !remremote) { errout("Alien packet discarded"); goto pktfail; }
929 memcpy(remkaddr.a+0,(remremote?(void *)&remaddr.sin_addr:(void *)(mykaddr.a+0)),4);
930 memcpy(remkaddr.a+4,&remaddr.sin_port,2);
931 if (debug) pkterr("received.");
932 if (!bufl) { pkterr("Empty!"); goto pktfail; }
933 if (bufl>=4 && !memcmp(buf,iKIX,3)) {
934 if (!remremote) { errout("InterKIX packets not allowed from localhost"); goto pktfail; }
936 case 'r': /* register: KIXrDDDDDDkpPID_[NAME] */
937 if (bufl<16) { pkterr("InterKIX Register len < 16"); goto pktfail; }
941 case 'u': /* unregister: KIXuDDDDDD */
942 if (bufl!=10) { pkterr("InterKIX Unregister len != 10"); goto pktfail; }
946 case 'd': /* data: KIXdDDDDDDssssssDKskDATA... */
947 if (bufl <21) { pkterr("InterKIX Data" " len < 21" ); goto pktfail; }
953 pkterr("Unrecognized InterKIX command code 0x%02X",buf[3]);
958 if (remremote) { errout("LocalKIX packets not allowed from remote"); goto pktfail; }
960 case 0x01: /* open socket */
961 if (bufl<7) { pkterr("OpenSocket len < 7!"); goto pktfail; }
963 us=memchr(buf+7,0,bufl-7);
964 bufl+=-1+10-(us?(buf+bufl)-us:0);
966 memmove(buf+10,buf+1,bufl-10);
967 memcpy(buf+4,mykaddr.a+0,4);
968 *(unsigned short *)(buf+8)=
970 (mapperfail?0:(*(unsigned short *)(buf+12))^(*(unsigned short *)(buf+14)))
978 memcpy(buf,iKIX,3); buf[3]='r';
982 buf[0]=0x06; /* open response */
983 memset(buf+1,0,2); /* ??? g_LastPort */
987 case 0x02: /* close socket */
988 if (bufl<3) { pkterr("Close socket len <3!"); goto pktfail; }
989 cli=*getclipgw(&remkaddr);
990 if (!cli) { pkterr("Unregister() but before Register()!"); goto pktfail; }
991 memcpy(buf+4,&cli->kaddr,6);
995 memcpy(buf,iKIX,3); buf[3]='u';
1000 buf[0]=0x07; /* close response */
1001 memset(buf+1,0,2); /* ??? g_LastPort */
1005 case 0x03: /* net data: 3ddddddDK??DATA... -> KIXdDDDDDDssssssDKskDATA... */
1006 if (bufl<11) { pkterr("Net data len < 11!"); goto pktfail; }
1007 if (!(cli=*(clip=getclipgw(&remkaddr))))
1008 { pkterr("Got net data before socket open!"); goto pktfail; }
1009 memmove(buf+20,buf+11,bufl-1);
1011 memcpy(buf+18,&cli->kport,2); /* sport */
1012 memcpy(buf+16,buf+7 ,2); /* dport */
1013 memcpy(buf+10,&cli->kaddr,6); /* saddr */
1014 memmove(buf+4,buf+1 ,6); /* daddr */
1015 memcpy(buf,iKIX,3); buf[3]='d';
1017 if (!memcmp(buf+4,&kbroad,6)) shippeers();
1018 else if (memcmp(buf+4,mykaddr.a+0,4)) /* not local */
1019 for (cli=clis;cli;cli=cli->next) {
1020 if (memcmp(&cli->kaddr,buf+4,6)) continue;
1021 shipaddr=&cli->gwaddr;
1026 case 0x05: /* Get Address */
1027 buf[0]=0x04; /* myipxaddress */
1029 { pid_t rempid; kaddrt mapkaddr;
1030 *(unsigned long *)(mapkaddr.a+0)=(unsigned long)htonl(INADDR_LOOPBACK);
1031 memcpy(mapkaddr.a+4,remkaddr.a+4,2);
1032 if ((rempid=kaddrmapper(&mapkaddr))==-2) {
1033 #ifndef QUIET_PIDFAIL
1034 pkterr("GetAddress: no PID!");
1037 *(unsigned short *)(buf+5)=(rempid==-1?0:htons(rempid^(rempid>>16)));
1041 memcpy(buf+1,mykaddr.a+0,4);
1044 mprintf("GetAddress: For ");
1045 addrdump(&remkaddr);
1047 kaddrdump((kaddrt *)(buf+1));
1050 if (rempid==-1) mprintf(" detection failed");
1051 else mprintf("=%d",rempid);
1062 pkterr("Unrecognized command code 0x%02X",buf[0]);
1066 return(EXIT_SUCCESS);