]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - sbounce.patch
rename patch files
[irc/quakenet/snircd-patchqueue.git] / sbounce.patch
CommitLineData
edb26b39
P
1# HG changeset patch
2# Parent e319e618448fe7163635b08206f48d214e59d738
3
4diff -r e319e618448f tools/sbounce/Makefile
5--- /dev/null Thu Jan 01 00:00:00 1970 +0000
6+++ b/tools/sbounce/Makefile Sun Jul 14 18:14:29 2013 +0100
7@@ -0,0 +1,54 @@
8+#
9+# Makefile for sbounce
10+#
11+
12+CC=gcc
13+CFLAGS=-O3 -Wall -pedantic
14+
15+PROG=sbounce
16+PREFIX=/opt/ircd
17+DEFINES=-DSETTINGSFILE=\"${PREFIX}/lib/bounce.conf\"\
18+ -DLOGFILE=\"${PREFIX}/lib/${PROG}.log\"\
19+ -DPIDFILE=\"${PREFIX}/lib/${PROG}.pid\"
20+
21+all: ${PROG} logrotate.conf
22+
23+${PROG}: ${PROG}.o
24+ gcc -O3 -lz -o ${PROG} ${PROG}.o
25+
26+sbounce.o:
27+ gcc ${DEFINES} -c ${PROG}.c
28+
29+logrotate.conf: logrotate.conf.in
30+ @sed -e 's,LOGFILE,${PREFIX}/lib/${PROG}.log,g'\
31+ -e 's,PIDFILE,${PREFIX}/lib/${PROG}.pid,g' <logrotate.conf.in >logrotate.conf
32+
33+install: all
34+ @if [ ! -d ${PREFIX} -a ! -f ${PREFIX} ]; then \
35+ echo "Creating directory ${PREFIX}"; \
36+ mkdir ${PREFIX}; \
37+ chmod 555 ${PREFIX}; \
38+ fi
39+
40+ @if [ ! -d ${PREFIX}/bin -a ! -f ${PREFIX}/bin ]; then \
41+ echo "Creating directory ${PREFIX}/bin"; \
42+ mkdir ${PREFIX}/bin; \
43+ chmod 555 ${PREFIX}/bin; \
44+ fi
45+
46+ @if [ -f ${PREFIX}/bin/${PROG} ]; then \
47+ echo "Saving existing ${PREFIX}/bin/${PROG} as .old"; \
48+ mv ${PREFIX}/bin/${PROG} ${PREFIX}/bin/${PROG}.old; \
49+ fi
50+
51+ cp ${PROG} ${PREFIX}/bin
52+ chmod 555 ${PREFIX}/bin/${PROG}
53+
54+ @if [ -d /etc/logrotate.d ]; then \
55+ echo "Installing /etc/logrotate.d/sbounce"; \
56+ cp logrotate.conf /etc/logrotate.d/sbounce; \
57+ chmod 444 /etc/logrotate.d/sbounce; \
58+ fi
59+
60+clean:
61+ rm -f ${PROG}.o ${PROG} logrotate.conf
62diff -r e319e618448f tools/sbounce/logrotate.conf.in
63--- /dev/null Thu Jan 01 00:00:00 1970 +0000
64+++ b/tools/sbounce/logrotate.conf.in Sun Jul 14 18:14:29 2013 +0100
65@@ -0,0 +1,12 @@
66+LOGFILE {
67+ size 5M
68+ rotate 7
69+ missingok
70+ notifempty
71+ postrotate
72+ [ -f PIDFILE ] && kill -HUP `cat PIDFILE`
73+ endscript
74+ compress
75+ delaycompress
76+ notifempty
77+}
78diff -r e319e618448f tools/sbounce/sbounce.c
79--- /dev/null Thu Jan 01 00:00:00 1970 +0000
80+++ b/tools/sbounce/sbounce.c Sun Jul 14 18:14:29 2013 +0100
81@@ -0,0 +1,932 @@
82+/* sbounce: splidge's zBounce alike.
83+ *
84+ * Version 1.2
85+ *
86+ * Copyright (C) 2003 David Mansell.
87+ *
88+ * Redistribution and use in source and binary forms, with or without
89+ * modification, are permitted provided that redistributions of source code
90+ * retain the above copyright notice, this condition and the following
91+ * disclaimer.
92+ *
93+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
94+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
95+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
96+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
97+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
98+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
99+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
100+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
101+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
102+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
103+ */
104+
105+#include <zlib.h>
106+#include <assert.h>
107+#include <errno.h>
108+#include <unistd.h>
109+#include <stdio.h>
110+#include <stdlib.h>
111+#include <netdb.h>
112+#include <signal.h>
113+#include <stdarg.h>
114+#include <fcntl.h>
115+#include <time.h>
116+#include <string.h>
117+#include <sys/types.h>
118+#include <sys/socket.h>
119+#include <sys/poll.h>
120+#include <sys/ioctl.h>
121+#include <sys/types.h>
122+#include <sys/stat.h>
123+#include <sys/time.h>
124+#include <netinet/in.h>
125+
126+/*
127+ * Various settings and constants that CAN be tweaked if you so desire..
128+ */
129+
130+/* Buffer / network settings */
131+#define BUFSIZE 65536
132+#define MAXFDS 100
133+#define LISTEN_RECVBUF 61440
134+#define RECVBUF 61440
135+#define SENDBUF 61440
136+
137+/* File settings */
138+#ifndef SETTINGSFILE
139+#define SETTINGSFILE "/opt/ircd/lib/bounce.conf"
140+#endif
141+#ifndef LOGFILE
142+#define LOGFILE "/opt/ircd/lib/sbounce.log"
143+#endif
144+#ifndef PIDFILE
145+#define PIDFILE "/opt/ircd/lib/sbounce.pid"
146+#endif
147+
148+#define STATSINTERVAL 300 /* How frequently to write compression stats to a file */
149+
150+/* These two directly affect the lag induced by the bouncer.. */
151+#define POLLTIMEOUT 100 /* The main poll timeout */
152+#define FLUSHTIMEOUT 80000 /* How long (in uSec) between last output and forcing a flush */
153+
154+#undef DONTDETACH /* Define this to make it not detach */
155+
156+/* Magic constants and macros etc. - these should NOT be tweaked :) */
157+#define SST_IDLE 0x00000
158+#define SST_LISTEN_COMP 0x10001
159+#define SST_LISTEN_DECOMP 0x10002
160+#define SST_COMP 0x20001
161+#define SST_DECOMP 0x20002
162+
163+#define IsListenSocket(x) (ssa[(x)].type & 0x10000)
164+#define IsActiveSocket(x) (ssa[(x)].type & 0x20000)
165+
166+#define IsCompressSocket(x) (ssa[(x)].type & 0x1)
167+#define IsDecompressSocket(x) (ssa[(x)].type & 0x2)
168+
169+/* Function prototypes */
170+void handlefd(int fd, short events);
171+void handlelistenfd(int fd, short events);
172+
173+int logfd;
174+
175+typedef struct ssock {
176+ int type;
177+
178+ /* poll() stuff - valid for all types */
179+ int pollfdpos;
180+ short events;
181+
182+ /* Address stuff - valid for listen types only */
183+ unsigned int listenaddr;
184+ unsigned short listenport;
185+ unsigned int remoteaddr;
186+ unsigned short remoteport;
187+ int marker;
188+
189+ /* Things valid for connected sockets only */
190+ z_stream zs;
191+ int companion;
192+ unsigned char *inbuf;
193+ unsigned char *outbuf;
194+ unsigned char *overflow;
195+ int overflowsize;
196+ struct timeval lastoutput;
197+ int dirty;
198+ time_t lastdump;
199+} ssock;
200+
201+typedef struct validip {
202+ unsigned int IPaddress;
203+ struct validip *next;
204+} validip;
205+
206+ssock ssa[MAXFDS];
207+struct pollfd pfd[MAXFDS];
208+int cur_pfds;
209+validip *okhosts;
210+int needrehash;
211+char configfile[512];
212+
213+void init() {
214+ int i;
215+ FILE *f;
216+
217+ memset(ssa, 0, MAXFDS * sizeof(ssock));
218+ memset(pfd, 0, MAXFDS * sizeof(struct pollfd));
219+
220+ /* Non-zero init here */
221+ for(i=0;i<MAXFDS;i++) {
222+ ssa[i].pollfdpos = -1;
223+ ssa[i].companion = -1;
224+ }
225+
226+ cur_pfds=0;
227+ okhosts=NULL;
228+ needrehash=0;
229+
230+#ifndef DONTDETACH
231+ if ((logfd=open(LOGFILE, O_CREAT | O_WRONLY | O_APPEND,00660)) < 0) {
232+ printf("ERROR: can't open logfile.\n");
233+ exit(1);
234+ }
235+
236+ if (fork())
237+ exit(0);
238+
239+ if (fork())
240+ exit(0);
241+#endif
242+
243+ f = fopen(PIDFILE, "w");
244+ if (f == NULL) {
245+ fprintf(stderr, "Couldn't create pid file \"%s\": %s",
246+ PIDFILE, strerror(errno));
247+ } else {
248+ fprintf(f, "%ld\n", (long) getpid());
249+ fclose(f);
250+ }
251+}
252+
253+long usecdiff(struct timeval *tv1, struct timeval *tv2) {
254+ long secdiff = tv2->tv_sec - tv1->tv_sec;
255+ long usecdiff = tv2->tv_usec - tv1->tv_usec;
256+
257+ return (secdiff * 1000000) + usecdiff;
258+}
259+
260+void logwrite(char *message, ...) {
261+ char buf[512];
262+ char buf2[512];
263+ char buf3[512];
264+ struct tm *tmp;
265+ time_t now;
266+ int len;
267+
268+ va_list va;
269+
270+ va_start(va,message);
271+ vsnprintf(buf,512,message,va);
272+ va_end(va);
273+
274+ now=time(NULL);
275+ tmp=localtime(&now);
276+ strftime(buf2, 512, "%Y-%m-%d %H:%M",tmp);
277+#ifdef DONTDETACH
278+ printf("[%s] %s",buf2,buf);
279+#else
280+ len=snprintf(buf3,512,"[%s] %s",buf2,buf);
281+
282+ write(logfd, buf3, len);
283+#endif
284+}
285+
286+char *IPtostr(unsigned int ip) {
287+ static char buf1[15];
288+ static char buf2[15];
289+ char *buf;
290+ static int count=0;
291+
292+ if ((count++)%2)
293+ buf=buf1;
294+ else
295+ buf=buf2;
296+
297+ sprintf(buf,"%d.%d.%d.%d",ip&255,(ip>>8)&255,(ip>>16)&255,(ip>>24)&255);
298+
299+ return buf;
300+}
301+
302+/* setpoll(): Set the specified fd to be checked for the specified events.
303+ * If events==0, remove the fd from the array.
304+ */
305+
306+void setpoll(int fd, short events) {
307+ if (events) {
308+ if (ssa[fd].pollfdpos > -1) {
309+ /* Already in the array.. */
310+ assert(pfd[ssa[fd].pollfdpos].fd == fd);
311+ pfd[ssa[fd].pollfdpos].events=events;
312+ ssa[fd].events=events;
313+ return;
314+ } else {
315+ /* Not in the array, add to the end */
316+ ssa[fd].pollfdpos=cur_pfds;
317+ pfd[cur_pfds].fd=fd;
318+ pfd[cur_pfds].events=events;
319+ pfd[cur_pfds].revents=0;
320+ ssa[fd].events=events;
321+ cur_pfds++;
322+
323+ return;
324+ }
325+ } else {
326+ if (ssa[fd].pollfdpos==-1) {
327+ /* This FD wasn't in the array */
328+ return;
329+ } else {
330+ cur_pfds--;
331+ if (ssa[fd].pollfdpos!=cur_pfds) {
332+ /* We need to swap the entry from the end in here */
333+ pfd[ssa[fd].pollfdpos].fd = pfd[cur_pfds].fd;
334+ pfd[ssa[fd].pollfdpos].events = pfd[cur_pfds].events;
335+ pfd[ssa[fd].pollfdpos].revents = pfd[cur_pfds].revents;
336+
337+ ssa[pfd[cur_pfds].fd].pollfdpos = ssa[fd].pollfdpos;
338+ }
339+
340+ ssa[fd].pollfdpos=-1;
341+ ssa[fd].events=0;
342+ return;
343+ }
344+ }
345+}
346+
347+/*
348+ * dopoll(): Calls poll(), and then calls handlefd() for each fd that had
349+ * events.
350+ */
351+
352+int dopoll(int timeout) {
353+ int i,ret;
354+
355+ if ((ret=poll(pfd, cur_pfds, timeout))) {
356+ if (ret<0 && errno!=EINTR) {
357+ logwrite("poll() error: %d\n",errno);
358+ return 0;
359+ }
360+ for(i=0;i<cur_pfds;i++) {
361+ if (pfd[i].revents) {
362+ handlefd(pfd[i].fd, pfd[i].revents);
363+ }
364+ }
365+ return 1;
366+ } else {
367+ return 0;
368+ }
369+}
370+
371+/*
372+ * initconnection(): Set up to compressor/decompressor for the specified socket.
373+ * Allocate buffers and set socket options.
374+ */
375+
376+void initconnection(int fd) {
377+ unsigned int rbuf=RECVBUF, sbuf=SENDBUF, opt=1;
378+
379+ ssa[fd].inbuf =(unsigned char *)malloc(BUFSIZE);
380+ ssa[fd].outbuf=(unsigned char *)malloc(BUFSIZE);
381+ memset(&(ssa[fd].zs), 0, sizeof(z_stream));
382+
383+ if (IsCompressSocket(fd)) {
384+ if (deflateInit(&(ssa[fd].zs), 6) != Z_OK) {
385+ logwrite("Error initialising deflate!\n");
386+ }
387+ } else {
388+ if (inflateInit(&(ssa[fd].zs)) != Z_OK) {
389+ logwrite("Error initialising inflate!\n");
390+ }
391+ }
392+
393+ ssa[fd].zs.next_in=ssa[fd].inbuf;
394+ ssa[fd].zs.avail_in=0;
395+ ssa[fd].zs.next_out=ssa[fd].outbuf;
396+ ssa[fd].zs.avail_out=0;
397+
398+ ssa[fd].dirty=0;
399+ ssa[fd].lastdump=time(NULL);
400+
401+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*) &rbuf, sizeof(rbuf)) ||
402+ setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*) &sbuf, sizeof(sbuf))) {
403+ logwrite("Error setting socket buffers on fd %d\n",fd);
404+ }
405+
406+ if (ioctl(fd, FIONBIO, &opt) == -1) {
407+ logwrite("Error setting socket non-blocking on fd %d\n",fd);
408+ }
409+
410+ ssa[fd].overflowsize=0;
411+}
412+
413+/*
414+ * killconnection(): Kills off the compressor/decompressor and frees all buffers
415+ */
416+
417+void killconnection(int fd) {
418+ close(fd);
419+ setpoll(fd,0);
420+ free(ssa[fd].inbuf);
421+ free(ssa[fd].outbuf);
422+ if (IsCompressSocket(fd)) {
423+ deflateEnd(&(ssa[fd].zs));
424+ } else {
425+ inflateEnd(&(ssa[fd].zs));
426+ }
427+ ssa[fd].type=SST_IDLE;
428+}
429+
430+/*
431+ * flushdata(): Flushes all data from the specified fd.
432+ * Returns 0 if all data was written.
433+ * Returns 1 if there is some data left.
434+ * Returns -1 if there was a socket error.
435+ */
436+
437+int flushdata(int fd) {
438+ int genbytes,bytesout;
439+ int companionfd=ssa[fd].companion;
440+
441+ if ((genbytes=ssa[fd].overflowsize)==0)
442+ return 0; /* nothing there */
443+
444+ bytesout=write(companionfd, ssa[fd].overflow, genbytes);
445+
446+ if (bytesout!=genbytes) {
447+ /* It didn't all get written */
448+ if (bytesout==-1) {
449+ if (errno==EAGAIN) {
450+ return 1;
451+ } else {
452+ logwrite("Error writing to fd %d: %d\n",companionfd,errno);
453+ return -1;
454+ }
455+ }
456+
457+ /* Short write - I'm ASSUMING this is cos the socket buffer filled up */
458+ ssa[fd].overflowsize-=bytesout;
459+ ssa[fd].overflow+=bytesout;
460+ return 1;
461+ }
462+
463+ /* Clear the overflow and return */
464+ ssa[fd].overflowsize=0;
465+
466+ return 0;
467+}
468+
469+/*
470+ * handledata(): Handles data outstanding on the specified fd.
471+ * Returns 0 if everything went OK
472+ * Returns 1 if there was an error
473+ *
474+ * This function will manipulate the poll() array as necessary if sockets become blocked.
475+ */
476+
477+int handledata(int fd, int forceflush) {
478+ int ret;
479+ int companionfd = ssa[fd].companion;
480+ struct timezone tz;
481+
482+ /* Check we don't have outstanding data to write.. */
483+ if ((ret=flushdata(fd))) {
484+ if (ret==1) {
485+ return 0;
486+ } else {
487+ return 1;
488+ }
489+ }
490+
491+ if (ssa[fd].dirty == 0) {
492+ gettimeofday(&(ssa[fd].lastoutput), &tz);
493+ }
494+
495+ if (ssa[fd].zs.avail_in || forceflush) {
496+ for(;;) {
497+ ssa[fd].zs.next_out=ssa[fd].outbuf;
498+ ssa[fd].zs.avail_out=BUFSIZE;
499+
500+ if (IsCompressSocket(fd)) {
501+ ret=deflate(&(ssa[fd].zs), forceflush ? Z_SYNC_FLUSH : 0);
502+ } else {
503+ ret=inflate(&(ssa[fd].zs), Z_SYNC_FLUSH);
504+ }
505+
506+ if (ret != Z_OK && ret != Z_BUF_ERROR) {
507+ logwrite("Compression error %d on fd %d.\n",ret,fd);
508+ return 1;
509+ }
510+
511+ /* Mark all generated data as overflow */
512+ ssa[fd].overflowsize = (BUFSIZE - ssa[fd].zs.avail_out);
513+ ssa[fd].overflow = ssa[fd].outbuf;
514+
515+ /* If it actually produced anything, make a note.. */
516+ if (ssa[fd].overflowsize) {
517+ gettimeofday(&(ssa[fd].lastoutput), &tz);
518+
519+ /* And flush */
520+ if ((ret=flushdata(fd))) {
521+ if (ret==1) {
522+ /* It's full - swap the poll() stuff around */
523+ setpoll(fd, ssa[fd].events & ~POLLIN);
524+ setpoll(companionfd, ssa[companionfd].events | POLLOUT);
525+ ssa[fd].dirty=0;
526+ return 0;
527+ } else {
528+ /* It broke, return error */
529+ return 1;
530+ }
531+ }
532+ }
533+
534+ if (ssa[fd].zs.avail_in == 0)
535+ break;
536+ }
537+ }
538+
539+ /* OK, we dealt with everything */
540+ if (!(ssa[fd].events & POLLIN)) {
541+ /* We need to swap poll() things back */
542+ setpoll(fd, ssa[fd].events | POLLIN);
543+ setpoll(companionfd, ssa[companionfd].events & ~POLLOUT);
544+ ssa[fd].dirty=1;
545+ }
546+
547+ return 0;
548+}
549+
550+/*
551+ * handlefd(): Deals with events occuring on the specified fd.
552+ */
553+
554+void handlefd(int fd, short events) {
555+ /* Palm off listen sockets elsewhere */
556+ int bytes;
557+ int companionfd;
558+
559+ companionfd=ssa[fd].companion;
560+
561+ if (IsListenSocket(fd)) {
562+ handlelistenfd(fd, events);
563+ return;
564+ }
565+
566+ if (events & POLLIN) {
567+ /* Input data to be handled by the [de]compressor - read all data, compress
568+ and send to companion socket. If the companion blocks, we make the companion
569+ poll for POLLOUT and stop this socket polling for POLLIN. */
570+
571+ /* It's an INVARIANT that if we were polling for POLLIN there is nothing in the input OR output buffers
572+ * from this socket. */
573+
574+ if (ssa[fd].overflowsize || ssa[fd].zs.avail_in || !(ssa[fd].events & POLLIN)) {
575+ logwrite("Unexpected input data on fd %d. - overflowsize=%d avail_in=%d ev=%d pfdev=%d rev=%d\n",fd,ssa[fd].overflowsize,
576+ ssa[fd].zs.avail_in, pfd[ssa[fd].pollfdpos].events, ssa[fd].events, events);
577+ } else {
578+ if ((bytes=read(fd, ssa[fd].inbuf, BUFSIZE))<=0) {
579+ if (bytes==0) {
580+ /* EOF */
581+ logwrite("Connection closed (EOF) - closing fds %d and %d.\n",fd,companionfd);
582+ killconnection(companionfd);
583+ killconnection(fd);
584+ return;
585+ } else if (errno==EAGAIN) {
586+ /* Just EAGAIN.. return and come back later */
587+ return;
588+ } else {
589+ logwrite("Connection close (Read error - %s) - closing fds %d and %d.\n",strerror(errno),fd,companionfd);
590+ killconnection(companionfd);
591+ killconnection(fd);
592+ return;
593+ }
594+ }
595+
596+ ssa[fd].zs.next_in=ssa[fd].inbuf;
597+ ssa[fd].zs.avail_in=bytes;
598+
599+ if (handledata(fd, 0)) {
600+ /* Error return - close connection */
601+ logwrite("Connection closed (ERROR) - closing fds %d and %d.\n",fd,companionfd);
602+ killconnection(companionfd);
603+ killconnection(fd);
604+ return;
605+ }
606+ ssa[fd].dirty=1;
607+ if (time(NULL) - ssa[fd].lastdump > STATSINTERVAL) {
608+ ssa[fd].lastdump=time(NULL);
609+ logwrite("fd %d Stats: %d bytes in, %d bytes out.\n",fd,ssa[fd].zs.total_in,ssa[fd].zs.total_out);
610+ }
611+ }
612+ }
613+
614+ if (events & POLLOUT) {
615+ /* We can write - need to grab output data from companion socket and write it out.
616+ If we manage to empty the buffer, we should set the companion socket to wait
617+ for POLLIN again -- handledata() does ALL this for us */
618+
619+ if (handledata(companionfd, 0)) {
620+ /* Error return - close connection */
621+ logwrite("Connection closed (ERROR) - closing fds %d and %d.\n",fd,companionfd);
622+ killconnection(companionfd);
623+ killconnection(fd);
624+ return;
625+ }
626+ }
627+
628+ if (events & (POLLERR|POLLHUP|POLLNVAL)) {
629+ /* Something has broken - close this socket and companion and clean everything up */
630+ logwrite("Connection error - closing fds %d and %d.\n",fd,ssa[fd].companion);
631+ killconnection(ssa[fd].companion);
632+ killconnection(fd);
633+ }
634+}
635+
636+/*
637+ * handlelistenfd(): Deals with activity on a listening FD (i.e. incoming connection)
638+ */
639+
640+void handlelistenfd(int fd, short events) {
641+ int newfd, companionfd;
642+ struct sockaddr_in sin;
643+ unsigned int len=sizeof(struct sockaddr_in);
644+ validip *vip;
645+ int res;
646+
647+ if (events & POLLIN) {
648+ /* We have a connection - need to accept(), initialise the [de]compressor and set up
649+ * a companion socket, initiating a non-blocking connect() to the remote address. */
650+
651+ newfd=accept(fd, (struct sockaddr *) &sin, &len);
652+
653+ if (newfd >= MAXFDS) {
654+ logwrite("FD %d out of range - closing connection. Recompile with larger MAXFDS\n",newfd);
655+ close(newfd);
656+ return;
657+ }
658+
659+ /* Check that this host is authorised to connect */
660+ for (vip=okhosts;vip;vip=vip->next) {
661+ if (vip->IPaddress == sin.sin_addr.s_addr)
662+ break;
663+ }
664+
665+ if (!vip) {
666+ logwrite("Rejecting unauthorised connection from %d.%d.%d.%d\n",sin.sin_addr.s_addr & 255,
667+ (sin.sin_addr.s_addr >> 8) & 255, (sin.sin_addr.s_addr >> 16) & 255,
668+ (sin.sin_addr.s_addr >> 24) & 255);
669+ close(newfd);
670+ return;
671+ }
672+
673+ /* Set the type */
674+ ssa[newfd].type = ssa[fd].type+0x10000;
675+ initconnection(newfd);
676+
677+ /* By default we listen on the NEW socket we open only.. */
678+ setpoll(newfd,0);
679+
680+ /* Now set up the companion socket */
681+ if ((companionfd=socket(AF_INET,SOCK_STREAM,0))==-1) {
682+ logwrite("Error creating companion socket!\n");
683+ killconnection(newfd);
684+ return;
685+ }
686+
687+ if (companionfd >= MAXFDS) {
688+ logwrite("FD %d out of range - closing connection. Recompile with larger MAXFDS.\n",companionfd);
689+ close(companionfd);
690+ killconnection(newfd);
691+ return;
692+ }
693+
694+ logwrite("Accepted connection from %d.%d.%d.%d. fd=%d, companion=%d\n",sin.sin_addr.s_addr & 255,
695+ (sin.sin_addr.s_addr >> 8) & 255, (sin.sin_addr.s_addr >> 16) & 255,
696+ (sin.sin_addr.s_addr >> 24) & 255, newfd, companionfd);
697+
698+ if (ssa[newfd].type == SST_COMP)
699+ ssa[companionfd].type = SST_DECOMP;
700+ else
701+ ssa[companionfd].type = SST_COMP;
702+
703+ initconnection(companionfd);
704+
705+ sin.sin_addr.s_addr=ssa[fd].remoteaddr;
706+ sin.sin_port = htons(ssa[fd].remoteport);
707+ if ((res=connect(companionfd, (struct sockaddr *) &sin, sizeof(struct sockaddr)))) {
708+ if (errno != EINPROGRESS) {
709+ logwrite("Error connecting companion socket: %d\n",errno);
710+ killconnection(newfd);
711+ killconnection(companionfd);
712+ return;
713+ }
714+ }
715+
716+ setpoll(companionfd, POLLIN|POLLOUT);
717+
718+ /* Set the companion fields up */
719+ ssa[companionfd].companion = newfd;
720+ ssa[newfd].companion = companionfd;
721+ }
722+
723+ if (events & (POLLERR|POLLHUP|POLLNVAL)) {
724+ /* Something has broken - this shouldn't happen (famous last words)
725+ * but clean up the listen socket */
726+ ssa[fd].type = SST_IDLE;
727+ close(fd);
728+ setpoll(fd, 0);
729+ }
730+}
731+
732+/*
733+ * openlistenfd(): Creates a listening socket
734+ */
735+
736+int openlistenfd(int type, unsigned int listenip, unsigned short listenport,
737+ unsigned int remoteip, unsigned short remoteport) {
738+ struct sockaddr_in sin;
739+ int fd;
740+ unsigned int opt=1;
741+
742+ if ((fd=socket(AF_INET,SOCK_STREAM,0))==-1) {
743+ logwrite("openlistenfd(): Error creating socket\n");
744+ return 1;
745+ }
746+
747+ logwrite("Creating %s listener on %s:%d forwarding to %s:%d\n",
748+ type==SST_LISTEN_COMP ? "compressing" : "decompressing", IPtostr(listenip),listenport,IPtostr(remoteip),remoteport);
749+
750+ if (fd>=MAXFDS) {
751+ logwrite("openlistenfd(): fd out of range - recompile with larger MAXFDS\n");
752+ close(fd);
753+ return 1;
754+ }
755+
756+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &opt, sizeof(opt))!=0) {
757+ logwrite("openlistenfd(): Error setting SO_REUSEADDR\n");
758+ close(fd);
759+ return 1;
760+ }
761+
762+ /* Initialiase the addresses */
763+ memset(&sin,0,sizeof(sin));
764+ sin.sin_family=AF_INET;
765+ sin.sin_port=htons(listenport);
766+ sin.sin_addr.s_addr=listenip;
767+
768+ if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) {
769+ logwrite("openlistenfd(): Unable to bind socket.\n");
770+ close(fd);
771+ return 1;
772+ }
773+
774+ opt = LISTEN_RECVBUF;
775+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*) &opt, sizeof(opt))) {
776+ logwrite("openlistenfd(): Error setting socket buffer size.\n");
777+ }
778+
779+ if (listen(fd,5)) {
780+ logwrite("openlistenfd(): Unable to listen.\n");
781+ close(fd);
782+ return 1;
783+ }
784+
785+ /* Now do the specific setup - only the following fields are relevant for listeners */
786+ ssa[fd].type = type;
787+ ssa[fd].listenaddr = listenip;
788+ ssa[fd].listenport = listenport;
789+ ssa[fd].remoteaddr = remoteip;
790+ ssa[fd].remoteport = remoteport;
791+ ssa[fd].marker = 1;
792+
793+ setpoll(fd, POLLIN);
794+
795+ return 0;
796+}
797+
798+/*
799+ * parseconfig(): Reads the config file, setting up and destroying listeners as necessary
800+ */
801+
802+int parseconfig(const char *filename) {
803+ validip *vip, *nvip;
804+ FILE *fp;
805+ char buf[512];
806+ int i;
807+ unsigned int ip1,ip2;
808+ unsigned short port1, port2;
809+ unsigned int type;
810+ struct hostent *hep;
811+ char *cp,*cp2;
812+ int found;
813+
814+ /* Check that we can open the file before we blow away the old state.. */
815+ if (!(fp=fopen(filename,"r"))) {
816+ logwrite("parseconfig(): Can't open config file!\n");
817+ return 1;
818+ }
819+
820+ /* Clear out the list of trusted IPs */
821+ for (vip=okhosts;vip;vip=nvip) {
822+ nvip=vip->next;
823+ free(vip);
824+ }
825+ okhosts=NULL;
826+
827+ /* Clear all markers */
828+ for (i=0;i<MAXFDS;i++) {
829+ ssa[i].marker=0;
830+ }
831+
832+ while(!feof(fp)) {
833+ fgets(buf, 512, fp);
834+
835+ if (feof(fp))
836+ break;
837+
838+ /* Check for valid config types.. */
839+ if (*buf=='A') {
840+ if (buf[1]!=':') {
841+ logwrite("parseconfig(): malformed config line %s\n",buf);
842+ continue;
843+ }
844+
845+ for (cp=buf+2;*cp;cp++) {
846+ if (*cp=='\n') {
847+ *cp='\0';
848+ break;
849+ }
850+ }
851+
852+ hep=gethostbyname(buf+2);
853+ if (hep && hep->h_addr) {
854+ vip=malloc(sizeof(struct validip));
855+ vip->IPaddress=*(unsigned int *)hep->h_addr;
856+ vip->next=okhosts;
857+ okhosts=vip;
858+ } else {
859+ logwrite("parseconfig(): unable to parse: %s\n",buf+2);
860+ }
861+ }
862+
863+ if (*buf=='p' || *buf=='P') {
864+ type=(*buf=='p'?SST_LISTEN_DECOMP:SST_LISTEN_COMP);
865+
866+ if (buf[1]!=':') {
867+ logwrite("parseconfig(): malformed config line %s\n",buf);
868+ continue;
869+ }
870+
871+ /* P:212.115.48.227:4480:212.115.48.164:4410 */
872+ cp2=buf+2;
873+ for (cp=buf+2;*cp && *cp!=':';cp++);
874+ if (!*cp) {
875+ logwrite("parseconfig(): malformed config line %s\n",buf);
876+ continue;
877+ }
878+
879+ *cp++='\0';
880+ hep=gethostbyname(cp2);
881+ if (!hep || !(ip1=*(unsigned int *)hep->h_addr)) {
882+ logwrite("parseconfig(): Invalid host %s\n",cp2);
883+ continue;
884+ }
885+
886+ if (!(port1=strtol(cp, &cp, 10))) {
887+ logwrite("parseconfig(): Invalid config line\n");
888+ continue;
889+ }
890+
891+ if (*cp++!=':') {
892+ logwrite("parseconfig(): Malformed config line\n");
893+ continue;
894+ }
895+
896+ cp2=cp;
897+ for (;*cp && *cp!=':';cp++);
898+ if (!cp) {
899+ logwrite("parseconfig(): malformed config line.\n");
900+ continue;
901+ }
902+
903+ *cp++='\0';
904+ hep=gethostbyname(cp2);
905+ if (!hep || !(ip2=*((unsigned int *)hep->h_addr))) {
906+ logwrite("parseconfig(): Invalid host %s\n",cp2);
907+ continue;
908+ }
909+
910+ if (!(port2=strtol(cp, &cp, 10))) {
911+ logwrite("parseconfig(): Invalid config line\n");
912+ continue;
913+ }
914+
915+ /* Check for matching listeners.. */
916+ found=0;
917+ for (i=0;i<MAXFDS;i++) {
918+ if (IsListenSocket(i) && ssa[i].listenaddr==ip1 && ssa[i].listenport==port1 &&
919+ ssa[i].remoteaddr==ip2 && ssa[i].remoteport==port2) {
920+ /* Found one, just set the type (allows p: <-> P: rehashes) */
921+ ssa[i].type=type;
922+ ssa[i].marker=1;
923+ found=1;
924+ break;
925+ }
926+ }
927+ if (!found)
928+ openlistenfd(type, ip1, port1, ip2, port2);
929+ }
930+ }
931+
932+ fclose(fp);
933+
934+ /* Kill off dead listeners */
935+ for (i=0;i<MAXFDS;i++) {
936+ if (IsListenSocket(i) && ssa[i].marker==0) {
937+ logwrite("Closing extinct listen socket %d\n",i);
938+ setpoll(i,0);
939+ ssa[i].type=SST_IDLE;
940+ close(i);
941+ }
942+ }
943+
944+ return 0;
945+}
946+
947+void handlehup(int x) {
948+ needrehash=1;
949+}
950+
951+void dorehash() {
952+ close(logfd);
953+ if ((logfd=open(LOGFILE, O_CREAT | O_WRONLY | O_APPEND,00660)) < 0) {
954+ printf("ERROR: can't reopen logfile.\n");
955+ exit(1);
956+ }
957+ logwrite("Received SIGHUP - reloading config file.\n");
958+ parseconfig(configfile);
959+ needrehash=0;
960+}
961+
962+int main(int argc, char **argv) {
963+ struct sigaction sa;
964+ int i;
965+ struct timezone tz;
966+ struct timeval tv;
967+
968+ sa.sa_handler=handlehup;
969+ sigemptyset(&(sa.sa_mask));
970+ sa.sa_flags=0;
971+
972+ strncpy(configfile, (argc > 1 ? argv[1] : SETTINGSFILE), 511);
973+
974+ init();
975+ sigaction(SIGHUP, &sa, NULL);
976+ sa.sa_handler=SIG_IGN;
977+ sigaction(SIGPIPE, &sa, NULL);
978+
979+ if (parseconfig(configfile)) {
980+ return 1;
981+ }
982+
983+ for(;;) {
984+ if (!dopoll(POLLTIMEOUT)) {
985+ for (i=0;i<MAXFDS;i++) {
986+ if (ssa[i].dirty==1 && IsActiveSocket(i)) {
987+ /* Flush everything */
988+ handledata(i,1);
989+ ssa[i].dirty=0;
990+ }
991+ }
992+ while (!dopoll(1000)) {
993+ if (needrehash)
994+ dorehash();
995+ }
996+ } else {
997+ /* something happened - do a more detailed dirty check */
998+ gettimeofday(&tv, &tz);
999+ for (i=0;i<MAXFDS;i++) {
1000+ if (ssa[i].dirty==1 && IsActiveSocket(i)) {
1001+ if (usecdiff(&(ssa[i].lastoutput), &tv) > FLUSHTIMEOUT) {
1002+ handledata(i,1);
1003+ ssa[i].dirty=0;
1004+ }
1005+ }
1006+ }
1007+ }
1008+ if (needrehash)
1009+ dorehash();
1010+ }
1011+
1012+ return 0;
1013+}