]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blob - sbounce.patch
rename patch files
[irc/quakenet/snircd-patchqueue.git] / sbounce.patch
1 # HG changeset patch
2 # Parent e319e618448fe7163635b08206f48d214e59d738
3
4 diff -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
62 diff -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 +}
78 diff -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 +}