and added files
[bcm963xx.git] / userapps / opensource / reaim / reaim.c
1 /*
2  * Project: ReAim
3  *
4  * Release: 0.8 pre
5  *
6  * Homepage:  http://reaim.sourceforge.net/
7  *
8  * Copyright: Mark Cooke, November 2001.  All Rights Reserved.
9  * 
10  * License: GNU General Public License, Version 2.
11  *
12  * CVS Data: $Id: reaim.c,v 1.30 2003/03/25 12:35:31 mark-c Exp $
13  *
14  * Description:
15  *
16  * ReAIM is a simple transparent AIM proxy.  It sits between a local area
17  * network, and the internet, usually running on the firewall / NAT server.
18  *
19  * It also has a filter module for MSN Messenger file transfer support.
20  *
21  * It accepts transparently redirected port 5190 (AIM server communications)
22  * traffic, and transparently forwards this to the usual destination with one
23  * caveat.
24  *
25  * The direct-communications setup packet is mangled to use the (routable)
26  * internet-visible IP address, rather than the client's NAT / private network
27  * address.
28  *
29  * Given the change in more recent clients to allow the user to set a source
30  * port, instead of just using 4443/5566, the proxy also forces the port to
31  * be 4443 as part of the DCC address mangling.
32  *
33  * This allows the second part of this proxy - a port 4443/5566
34  * forwarding service - to catch the remote party DCC connection, and forward
35  * it to the internal host.  It is slightly cludgy, as the AIM clients do not
36  * send a 'hello, it's me' packet when they direct-connect, so the proxy can't
37  * tell where to forward the connection to until the remote party sends a
38  * message.  Fortunately, just starting to type sends a message we can use
39  * to make the onward part of the proxied connection.
40  *
41  * To make this less cludgy, it is possible to open a range of incoming ports,
42  * and for the proxy to use the next unused port in this range for each DCC.
43  * This is a 'TODO' high on my list of things to do to ReAIM.
44  *
45  * As a compile option, setting LAX_SECURITY will allow a DCC to match at the
46  * initial connection point if there is only 1 pending DCC request.
47  * 
48  * As a compile option, setting LOOSE_CLIENT_IP will disable the paranoid
49  * checking that the IP address being overwritten in the DCC setup packet is
50  * the same as the source IP address of the client socket.  This allows
51  * multi-homed hosts to work, and also network topologies that include
52  * multiple-NAT devices.
53  *
54  * Usage:
55  *
56  * reaim [optional dotted quad for routable IP]
57  *
58  * Notes:
59  *
60  * This proxy requires knowledge of the external IP address, and also for the
61  * original destination to be available.  Using iptables allows us to use
62  * SO_ORIGINAL_DST to retrieve this.  Hence, this proxy is a 2.4.x / iptables
63  * only proxy.  More specifically, it does -not- work with 2.4.x / ipchains
64  * support.  Suitable modifications to the gettranssockname function may
65  * permit this to work with ipchains on 2.2.x, where the getsockname() call
66  * is overridden to be the original destination (not confirmed).
67  *
68  * Example usage where eth0 is LAN, ppp0 is internet:
69  *
70  * 1. Redirect eth0 traffic to eth0 port 5190, and make sure it's accepted.
71  * iptables -t nat    -A PREROUTING -i eth0 -p tcp --dport 5190 -j REDIRECT --to-ports 5190
72  * iptables -t filter -A INPUT      -i eth0 -p tcp --dport 5190 -j ACCEPT
73  *
74  * 2. Allow ppp0 to accept traffic for port 4443 (AIM DCC)
75  * iptables -t filter -A INPUT      -i ppp0 -p tcp --dport 4443 -j ACCEPT
76  *
77  * 3. Allow ppp0 to accept traffic for port 5566 (AIM Sharing)
78  * iptables -t filter -A INPUT      -i ppp0 -p tcp --dport 5566 -j ACCEPT
79  *
80  * 4. Redirect eth0 traffic to eth0 port 5190, and make sure it's accepted.
81  * iptables -t nat    -A PREROUTING -i eth0 -p tcp --dport 1863 -j REDIRECT --to-ports 1863
82  * iptables -t filter -A INPUT      -i eth0 -p tcp --dport 1863 -j ACCEPT
83  *
84  * 5. Allow ppp0 to accept traffic for port 1864 (MSN DCC)
85  * iptables -t filter -A INPUT      -i ppp0 -p tcp --dport 1864 -j ACCEPT
86  *
87  * 6. Allow dynamic dcc traffic on ports 40000 - 40099
88  * iptables -t filter -A INPUT      -i ppp0 -p tcp --dport 40000:40099 -j ACCEPT
89  *
90  * Detailed AIM Manglement Notes:
91  *
92  * The proxy keeps three lists of connections (socket pairs).
93  *
94  * 1. LAN clients connections to port 5190 (and the onward connection).
95  * 2. Established connections on port 4443 (and the onward connection).
96  * 3. Established connections on port 5566 (and the onward connection).
97  *
98  * When a client starts a connection, the proxy accepts the redirected
99  * connection on it's port 5190.  It immediately attempts to open the
100  * onward connection to the original destination, and any packets arriving
101  * in either direction are inspected, optionally modified, and then passed
102  * to the other half of the socket-pair.
103  *
104  * When a packet indicates a DC setup request, an entry is made in the
105  * pending DC setup list, and appropriate parameters from the request are
106  * recorded.  Note that the DC setup request is -mangled- to use the
107  * externally addressable IP address, and a dynamic port, so the remote
108  * party isn't trying to connect to a 10.x.x.x etc IP address.
109  *
110  * When a connection is received on the dynamic port (or 4443 for buggy
111  * clients), the proxy accepts the connection, and searches for a match
112  * in the pending DC list.  If a match is found, the onward portion of
113  * the DC is established, and unfiltered direct communications between
114  * the parties is established.
115  *
116  * Connections to port 5566 are handled virtually identically.
117  *
118  * DC Setup Packet Format:
119  *
120  * With many thanks to the people working on the reverse engineering of
121  * the AIM OSCAR protocol.
122  *
123  *
124  * EXTRA...EXTRA...
125  *
126  * Because of the nice flexibility of the filter scheme, I added support for
127  * MSN proxying too.  The MSN Messenger uses a pseudo HTTP style scheme, with
128  * headers indicating the message type, parameters, etc.
129  *
130  * For MSN DCC setup, we look for the text/xmsmsgsinvite message, and 'fix'
131  * both the port and IP address, again with a dynamic dcc port from our range.
132  *
133  * TODO:
134  *
135  * A whole lot.  This is currently little more than a complete hack that
136  * happens to work for me.  I'll be working on the code to do more error
137  * checking, structure clean up, as time permits.
138  *
139  * I have plans to add a 'filter chain' type system to both the 5190 and 4443
140  * port proxies, and eventually maybe generalise the code to be a more
141  * generic, open source licensed, proxy-based firewalling system...maybe!
142  *
143  * Final words:
144  *
145  * No warranty.  Patches, bug reports, success stories, and other contributions
146  * most welcome.
147  */
148
149 /* NOTE:  NetBSD patch provided by David Vyskocil.  Thanks!!!
150  *
151  * Compile with USE_IPF defined for NetBSD/IPF support.
152  */
153
154  /* NetBSD proxy redirect(ipnat) and firewall(ipf) setup
155  *
156  * assuming 'ne0' is the LAN device name and 'tun0' the internet connection
157  *
158  * /etc/ipnat.conf rules... (redirect for transparent proxying)
159  *
160  * rdr ne0 0/0 port 1863 -> 127.0.0.1 port 1863 tcp
161  * rdr ne0 0/0 port 5190 -> 127.0.0.1 port 5190 tcp
162  *
163  * /etc/ipf.conf rules... (firewall/logger)
164  *
165  * pass in quick log on ne0 proto tcp from any to any port = 1863
166  * pass in quick log on ne0 proto tcp from any to any port = 5190
167  * pass in quick log on tun0 proto tcp from any to any port = 1864
168  * pass in quick log on tun0 proto tcp from any to any port = 4443
169  * pass in quick log on tun0 proto tcp from any to any port = 5566
170  *
171  */
172
173 #include <stdio.h>
174 #include <stdlib.h>
175 #include <string.h>
176 #include <stdarg.h>
177 #include <math.h>
178 #include <sys/time.h>
179 #include <signal.h>
180 #include <pwd.h>
181 #include <grp.h>
182 #include <sys/types.h>
183 #include <sys/socket.h>
184 #include <netinet/in.h>
185 #include <arpa/inet.h>
186 #include <sys/ioctl.h>
187 #include <sys/poll.h>
188 #include <fcntl.h>
189 #include <errno.h>
190 #include <netdb.h>
191 #include <time.h>
192 #include <ctype.h>
193
194 #include <getopt.h>
195 #include <sys/ioctl.h>
196
197 #include <unistd.h>
198
199 // Command line options
200 #define _GNU_SOURCE
201 #include <getopt.h>
202
203 static struct option long_options[] = {
204
205   { "disable-msn", 1, 0, 'm' },
206   { "disable-aim", 1, 0, 'a' },
207   { "external-ip", 1, 0, 'e' },
208   { "help",        1, 0, 'h' },
209   { "logfile",     1, 0, 'l' },
210   { 0,0,0,0 }
211 };
212
213 #ifdef USE_IPF
214
215 #include <net/if.h>
216 #include <netinet/in.h>
217 #include <netinet/ip_compat.h>
218 #include <netinet/ip_fil.h>
219 #include <netinet/ip_nat.h>
220 #define PLATFORM "/IPF"
221
222 #else
223
224 // Nasty kernel include in a userspace program
225 // but we need the original destination information....
226 #include <linux/netfilter_ipv4.h>
227 #define PLATFORM "/NetFilter"
228
229 #endif
230
231 #define REAIM_VERSION "0.8 pre"
232
233 #define OSCAR 5190
234 #define DCC   4443
235 #define SHARE 5566
236
237 #define MSN     1863   // Where we listen for client messages
238 #define MSNRX   1864   // Where we listen for MSN DCCs
239
240 #define INC_MIN     40000   // Minimum port for incoming connections
241 #define INC_MAX     40099   // Maximum port for incoming connections
242 #define INC_TIMEOUT 60      // 60 second timeout for dynamic DCCs
243
244 #define LAX_SECURITY     1
245 #define LOOSE_CLIENT_IP  1
246 #define LOOSE_PORT_SCAN  0
247 #define DEBUG_PKT_DUMPS  1
248 #define USE_DYNAMIC_DCC  1
249 #define PERIODIC_LOG     1
250
251 int enable_msn  = 1;
252 int enable_aim  = 1;
253 int enable_fork = 1;
254 // BRCM begin
255 int enable_log  = 0;
256 // BRCM end
257
258 // Trillian headers for MSN support don't end with two \n\r pairs,
259 // but only one, so are not distinguishable from the message easily.
260 // Define this to skip the strict end-of-headers check.
261 #define TRILLIAN_HEADER_SUPPORT 1
262
263 #define TS_CLIENT 0
264 #define TS_SERVER 1
265
266 // This defines the size of the buffers used when proxying
267 // connections.  Each proxied connection uses 2 of these
268 // buffers.
269 #define PROXY_BUFFER_SIZE   4096
270
271 #ifndef LOG_FILE
272 #define LOG_FILE "/var/log/reaim.log"
273 #endif
274
275 char *log_file = LOG_FILE;
276
277 // Filter group IDs - needed for stateful storage access
278 #define GRP_AIM    1
279 #define GRP_ICQ    2
280 #define GRP_MSN    3
281
282 // Set to 1 to enable additional logging for debugging purposes
283 #define VERBOSE_LOGGING 0
284
285 // Timeout for making onward connections
286 #define CONNECT_TIMEOUT 10
287
288 // Maximum number of filters on each open socket.
289 // TODO: remove this coded limit
290 #define MAX_FILTERS 4
291
292 // Logging routine.  Borrowed from the squirm proxy.
293 int write_log(const char *logfile, const char *format, ...);
294
295
296 typedef struct _filter_chain           filter_chain;
297 typedef struct _filter_state           filter_state;
298 typedef struct _proxy_track_struct     proxy_track_struct;
299 typedef struct _user_track_struct      user_track_struct;
300 typedef struct _pending_dc_struct      pending_dc_struct;
301 typedef struct _listen_track_struct    listen_track_struct;
302 typedef struct _pending_connect_struct pending_connect_struct;
303
304 /*----------------------------------------------------------------------------
305   The filter scheme for the code is a simple procedure that takes a proxy
306   data buffer, current and maximum length, and the connection tracking
307   structure.
308
309   Each filter is called sequentially, and can mangle the provided buffer.
310 ----------------------------------------------------------------------------*/
311 typedef unsigned int (filter_proc)(unsigned char *buff,
312                                    unsigned int buff_len,
313                                    unsigned int max_len,
314                                    proxy_track_struct *pt);
315
316 typedef void (listen_proc)(listen_track_struct *lt);
317
318 typedef void (connect_proc)(pending_connect_struct *pc);
319
320
321 struct _filter_chain {
322     filter_proc    *proc[MAX_FILTERS]; // Procedures for filtering
323 };
324
325 struct _filter_state {
326     filter_state   *next;         // Next state storage
327     unsigned int    filter_group; // Filter ID number
328     void           *group_state;  // Persistent state
329 };
330
331 /*
332  * Generic proxied socket handler.
333  *
334  */
335 struct _proxy_track_struct {
336     proxy_track_struct *next;  // Next proxy connection in linked list.
337     
338     unsigned int magic;        // Magic number linking other lists.
339     unsigned int cleanup;      // Set to 1 to garbage collect this entry.
340     unsigned int user;         // Set to 1 if user connection.
341     
342     int sockets[2];                  // The rx / tx sockets
343     unsigned char *data_buff[2];     // Receive/Transmit pending data buffers
344     unsigned int   data_offset[2];   // Offset to start of data in buffers
345     unsigned int   data_len[2];      // Remaining bytes in pending buffers
346     unsigned int   data_max[2];      // Buffer sizes
347     filter_chain  *filter[2];        // Attached filters
348     filter_state   state;            // Stateful storage buffers
349 };
350
351 struct  _user_track_struct {
352     user_track_struct *next; // Next entry in the list
353
354     unsigned int magic;      // Magic connection tracking number
355     unsigned int cleanup;    // Set to 1 to clean up this entry
356
357     unsigned char *msg;      // Connection setup message
358     unsigned char *user;     // Screen name of the user
359 };
360
361 struct _pending_dc_struct {
362
363     pending_dc_struct *next; // Next pending connection
364     
365     unsigned int cleanup;    // Set to 1 to clean up this entry
366
367     unsigned short port;     // Port we're listenning on.
368     unsigned short orig_port;// Original port the client was on.
369
370     unsigned int magic;      // The user_track_struct magic number
371     unsigned char id[8];     // The DC setup message we're waiting on
372
373     struct sockaddr_in src;  // Original Client Source address
374 };
375
376 struct _listen_track_struct {
377     
378     listen_track_struct *next; // Next listenning socket
379     listen_proc         *proc; // Procedure to call
380     
381     unsigned int      cleanup; // 1 if inactive
382     int                  port; // Port this is listenning on.
383     int                socket; // Listening socket handle.
384     int               oneshot; // 1 if one-shot listener.
385     long              timeout; // One-shot timeout (0 is infinite)
386 };
387
388 struct _pending_connect_struct {
389   pending_connect_struct *next;  // Next pending connection
390   unsigned int magic;            // user_track_struct magic number
391   int          socket;           // Socket handle
392   int          client_sock;      // Client socket
393   connect_proc *proc;            // Bottom half handler
394   void         *proc_data;       // Data for the bottom half handler
395   filter_chain *filter[2];       // Establish connection filters
396   long          timeout;         // Timeout time
397   struct sockaddr_in src;        // Source address
398   struct sockaddr_in dst;        // Destination address
399 };
400
401 #define AIM_CMDSTART(buff)      buff[0]
402 #define AIM_CHANNEL(buff)       buff[1]
403 #define AIM_SEQID(buff)         ((unsigned short) buff[2]  + (buff[3] << 8))
404 #define AIM_FNAC_LEN(buff)      ((unsigned short) buff[5]  + (buff[4] << 8))
405 #define AIM_FNAC_FAMILY(buff)   ((unsigned short) buff[7]  + (buff[6] << 8))
406 #define AIM_FNAC_SUBTYPE(buff)  ((unsigned short) buff[9]  + (buff[8] << 8))
407 #define AIM_FNAC_FLAGS(buff)    ((unsigned short) buff[11] + (buff[10] << 8))
408 #define AIM_SNAC_ID(buff)       ((unsigned int)   buff[15] + (buff[14] << 8) + (buff[13] << 16) + (buff[12] << 24))
409 #define AIM_SNAC_COOKIE(buff)   (&buff[16])   // The 8 byte SNAC cookie start ptr
410 #define AIM_SNAC_CHAN(buff)     ((unsigned short) buff[25] + 256*buff[24])
411 #define AIM_BUD_NAME_LEN(buff)  buff[26]
412 #define AIM_BUD_NAME(buff)      (&buff[27])
413 #define AIM_BUD_NEXT(buff)      (27+AIM_BUD_NAME_LEN(buff))
414 #define AIM_SNAC_TLV_TYPE(buff) ((unsigned short) buff[AIM_BUD_NEXT(buff)+1] + (buff[AIM_BUD_NEXT(buff)+0] << 8))
415 #define AIM_SNAC_TLV_NEXT(buff) ((unsigned short) buff[AIM_BUD_NEXT(buff)+3] + (buff[AIM_BUD_NEXT(buff)+2] << 8))
416 #define AIM_SNAC_DATA_OFF(buff) (AIM_BUD_NEXT(buff)+4)
417 #define DCC_SNAC_COOKIE(buff)   (&buff[12])
418 #define DCC_BUD_NAME(buff)      (&buff[44])  // Appears to be null terminated this time...
419
420 /*===========================================================================*/
421 // The linked lists used to track state
422 /*===========================================================================*/
423
424 proxy_track_struct pt_list;       // Generic proxy socket list-head.
425 user_track_struct  user_list;     // List head.  User tracking information
426 listen_track_struct lt_list;      // List head.  Listenning sockets
427 pending_connect_struct pc_list;   // List head.  Pending connect()'s
428 pending_dc_struct  dc_list;       // List head.  Pending incoming connections
429
430 unsigned int       ts_magic        = 1; // Next free magic number
431
432 char *             outside_ip      = NULL;
433
434 filter_chain       oscar_tx;   // LAN client to AIM filter
435 filter_chain       oscar_rx;   // AIM to LAN client filter
436 filter_chain       share_tx;   // LAN to Remote filter
437 filter_chain       share_rx;   // Remote to LAN filter
438 filter_chain       msn_tx;     // LAN to Remote filter
439 filter_chain       msn_rx;     // Remote to LAN filter
440 filter_chain       msnrx_tx;   // LAN to Remote filter
441 filter_chain       msnrx_rx;   // Remote to LAN filter
442
443 static int pending_hup = 0; // Not zero if a HUP was received.
444
445 listen_track_struct* create_listener_between(int port_min, int port_max, listen_proc lp);
446
447 /*===========================================================================*/
448
449
450 #ifdef USE_IPF
451
452 /* 
453  * We use IP Filter on NetBSD to track original destination 
454  *
455  * Descriptions: use ioctl for /dev/ipnat to extract original destination
456  *               from kernel.
457  *    Arguments: (socket file descriptor, 
458  *                current destination address, 
459  *                the length)
460  * Side Effects: replace sa to original destination
461  * Return Value: 0 (success) or -1 (failure)
462  */
463 int
464 get_realip_from_ipf(fd, sa, salen)
465      int fd;
466      struct sockaddr *sa;
467      int *salen;
468 {
469
470     struct      sockaddr_in     sin, sloc;
471     struct      sockaddr_in     *sinp;
472     natlookup_t natlook;
473     natlookup_t *natlookp = &natlook;
474     int namelen, natfd;
475     /*  
476     * get IP# and port # of the remote end of the connection (at the
477     * origin).
478     */
479     namelen = sizeof(sin);
480     if (getpeername(fd, (struct sockaddr *)&sin, &namelen) == -1) {
481         perror("getpeername");
482         write_log(log_file, "getpeername failed: %s", strerror(errno));
483         exit(-1);
484         }
485     /*
486     * get IP# and port # of the local end of the connection (at the
487     * man-in-the-middle).
488     */
489     namelen = sizeof(sin);
490     if (getsockname(fd, (struct sockaddr *)&sloc, &namelen) == -1) {
491         perror("getsockname");
492         write_log(log_file, "getsockname failed: %s", strerror(errno));
493         exit(-1);
494         }
495     /*
496     * Build up the NAT natlookup structure.
497     */
498     bzero((char *)&natlook, sizeof(natlook));
499     natlook.nl_outip = sin.sin_addr;
500     natlook.nl_inip = sloc.sin_addr;
501     natlook.nl_flags = IPN_TCP;
502     natlook.nl_outport = sin.sin_port;
503     natlook.nl_inport = sloc.sin_port;
504     /*
505     * Open the NAT device and lookup the mapping pair.
506     */
507     natfd = open(IPL_NAT, O_RDONLY);
508     if (ioctl(natfd, SIOCGNATL, &natlookp) == -1) {
509         perror("ioctl(SIOCGNATL)");
510         write_log(log_file, "ioctl(SIOCGNATL) failed: %s", strerror(errno));
511         close(natfd);
512         exit(-1);
513         }
514     close(natfd);
515 /*
516     fprintf(stderr, "from addr:%s port:%d\n", inet_ntoa(natlook.nl_inip), ntohs(natlook.nl_inport));
517     fprintf(stderr, "as   addr:%s port:%d\n", inet_ntoa(natlook.nl_outip), ntohs(natlook.nl_outport));
518     fprintf(stderr, "real addr:%s port:%d\n", inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport));
519 */
520     sinp = (struct sockaddr_in *) sa;
521     sinp->sin_addr = natlookp->nl_realip;
522     sinp->sin_port = natlookp->nl_realport;
523     sinp->sin_family = AF_INET;
524     return(0);
525 }
526
527 #endif
528
529 /*===========================================================================*
530  *  int gettranssockname(int fd, struct sockaddr *sa, socklen_t *salen)
531  *
532  *    Query the network stack for the original destination of the socket
533  *    passed.  This is used for building the onward portion of the filter
534  *    proxy.
535  *===========================================================================*/
536
537 int gettranssockname(int fd, struct sockaddr *sa, socklen_t *salen)
538 {
539     if (*salen != sizeof(struct sockaddr_in)) {
540         errno = EINVAL;
541         return -1;
542     }
543     
544     // Try to ask for the original destination...
545 #ifdef USE_IPF
546     if (!get_realip_from_ipf(fd, sa, salen))
547         return 0;
548 #else
549     if (!getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, sa, salen))
550         return 0;
551 #endif
552     
553     // We have to explode if we can't read it back.
554     return -1;
555 }
556
557 /*===========================================================================*
558  *  void dump_packet(const char *buff, int len)
559  *
560  *    Print out the contents of the packet.
561  *===========================================================================*/
562 void dump_packet(const char *buff, int len)
563 {
564     char dump_start[32768], *dump_buff = dump_start;
565     int i, j;
566
567     for (i = 0; i < len; i ++) {
568         
569         if ((i % 16) == 0) {
570             sprintf(dump_buff, "%.4X    ", i);
571             dump_buff += 8;
572         }
573         
574         sprintf(dump_buff, "%02x ", (unsigned int) buff[i] & 0xff);
575         dump_buff += 3;
576         
577         if ((i % 16) == 15) {
578             
579             sprintf(dump_buff, "    ");
580             dump_buff += 4;
581             
582             for (j = -15; j < 1; j++) {
583                 if (isalnum(buff[i+j]))
584                     *dump_buff = buff[i+j];
585                 else
586                     *dump_buff = '.';
587
588                 dump_buff ++;
589             }
590             
591             *dump_buff++ = '\n';
592         }
593     }
594     *dump_buff++ = '\n';
595     *dump_buff++ = '\0';
596
597     write_log(log_file, "Packet Dump:\n%s", dump_start);
598 }
599
600
601 /*===========================================================================*
602  *  void dump_packet(const char *buff, int len)
603  *
604  *    Print out the contents of the packet.
605  *===========================================================================*/
606
607 int write_log(const char *logfile, const char *format, ...)
608 {
609     va_list args;
610     FILE *log_handle;
611     char *date_str;
612     char msg_buff[32768];
613     time_t current_time;
614     
615     va_start(args, format);
616     
617     if (vsprintf(msg_buff, format, args) > 32767)
618         strcpy(msg_buff, "[WARNING] Insufficient log buffer size");
619     
620     va_end(args);
621     
622     current_time = time(NULL);
623     date_str = ctime(&current_time);
624     
625 // BRCM begin
626 // Only write to log file when it's enabled, otherwise write to
627 // stderr when enable_fork == 0, otherwise throw it away.
628     if (enable_log) {
629        log_handle = fopen(logfile, "at");
630        if (log_handle == NULL) {
631           if (enable_fork == 0)
632           fprintf(stderr, "[%.*s] %s\n", (int) strlen(date_str) - 1, date_str, msg_buff);
633           return 0;
634        }
635     
636        // strlen - 1 to kill the trailing \n in the data string.
637        fprintf(log_handle, "[%.*s] %s\n", (int) strlen(date_str) - 1, date_str, msg_buff);
638        fclose(log_handle);
639        return 1;
640    }
641    else {
642        if (enable_fork == 0)
643           fprintf(stderr, "[%.*s] %s\n", (int) strlen(date_str) - 1, date_str, msg_buff);
644        return 0;
645    }
646 // BRCM end
647 }
648
649 #if PERIODIC_LOG
650 /*===========================================================================*
651  *  void periodic_log()
652  *
653  *  Print out some stats to the reaim log periodically.
654  *===========================================================================*/
655
656 void periodic_log() {
657
658   int n_pc, n_pt, n_lt, n_pdc;
659   listen_track_struct *lt;
660   pending_dc_struct *pdc;
661   proxy_track_struct *pt;
662   pending_connect_struct *pc;
663   
664   // Count listen_track_struct
665   n_lt = 0;
666   lt = lt_list.next;
667   while(lt != NULL) {
668     n_lt ++;
669     lt = lt->next;
670   }
671
672   // Count pending_dc_struct
673   n_pdc = 0;
674   pdc = dc_list.next;
675   while(pdc != NULL) {
676     n_pdc ++;
677     pdc = pdc->next;
678   }
679
680   // Count proxy_track_struct
681   n_pt = 0;
682   pt = pt_list.next;
683   while(pt != NULL) {
684     n_pt ++;
685     pt = pt->next;
686   }
687
688   // Count pending_connect_struct
689   n_pc = 0;
690   pc = pc_list.next;
691   while(pc != NULL) {
692     n_pc ++;
693     pc = pc->next;
694   }
695
696   write_log(log_file, "[STATS] Proxied Connections: %d, Pending DCCs: %d, Pending connect()s: %d, Listening Sockets: %d",
697             n_pt, n_pdc, n_pc, n_lt);
698 }
699
700 #endif
701
702 /*===========================================================================*
703  *  int net_listen(int port, char *ifs)
704  *
705  *    Open a network socket listenning on the port requested.  This function
706  *    returns the socket handle, or -1 if the socket could not be openned for
707  *    some reason.
708  *
709  *    The function binds to the address specified in the ifs parameter.
710  *===========================================================================*/
711
712 int net_listen(int port, const char *ifs)
713 {
714     int hSock;
715     struct sockaddr_in server;
716     int option;
717     
718     hSock = socket(PF_INET, SOCK_STREAM, 0);
719     if (hSock == -1) {
720         write_log(log_file, "[FATAL] Could create a socket for %s:%d",
721                   ifs, port);
722         return -1;
723     }
724     
725     option = 1;
726     if (setsockopt(hSock, SOL_SOCKET, SO_REUSEADDR, (void*) &option,
727                    sizeof(option)) < 0) {
728         write_log(log_file, "[FATAL] Could not set socket options for %s:%d",
729                   ifs, port);
730         return -1;
731     }
732     
733     server.sin_family = AF_INET;
734     server.sin_addr.s_addr = inet_addr(ifs);
735     server.sin_port = htons(port);
736     if (bind(hSock, (struct sockaddr*) &server, sizeof(server)) == -1) {
737         write_log(log_file, "[FATAL] Could not create listening socket on %s:%d",
738                   ifs, port);
739         close(hSock);
740         return -1;
741     }
742     
743     if (listen(hSock, 5) == -1) {
744         write_log(log_file, "[FATAL] Could not listen on %s:%d",
745                   ifs, port);
746         close(hSock);
747         return -1;
748     }
749     
750     /* Set the socket to non blocking, and close it if we can't */
751     if (fcntl (hSock, F_SETFL, O_NONBLOCK) == -1) {
752         write_log(log_file, "[FATAL] Could not make socket non-blocking for %s:%d",
753                   ifs, port);
754         close(hSock);
755         return -1;
756     }
757     
758     return hSock;
759 }
760
761 /*===========================================================================*
762  *  int net_listen_between(int port_min, int port_max)
763  *
764  *    Open a network socket listenning on a port in the range requested.
765  *    This function returns the socket handle, or -1 if the socket could not
766  *    be openned for some reason.
767  *
768  *    The function binds to the address specified in the ifs parameter, and
769  *    returns the port bound.
770  *===========================================================================*/
771 int net_listen_between(int port_min, int port_max, const char *ifs, int *port)
772 {
773     int hSock;
774     struct sockaddr_in server;
775     int option, i;
776     
777     hSock = socket(PF_INET, SOCK_STREAM, 0);
778     if (hSock == -1) {
779         write_log(log_file, "[FATAL] Could create a socket for %s:%d",
780                   ifs, port);
781         return -1;
782     }
783     
784     option = 1;
785     if (setsockopt(hSock, SOL_SOCKET, SO_REUSEADDR, (void*) &option,
786                    sizeof(option)) < 0) {
787         write_log(log_file, "[FATAL] Could not set socket options for %s:%d",
788                   ifs, port);
789         return -1;
790     }
791     
792     server.sin_family = AF_INET;
793     server.sin_addr.s_addr = inet_addr(ifs);
794     
795     /* Look for an unused port in our permitted range. */
796     for (i = port_min ; i <= port_max; i++) {
797       server.sin_port = htons(i);
798       if (bind(hSock, (struct sockaddr*) &server, sizeof(server)) != -1)
799         break;
800     }
801     
802     // Didn't find one.
803     if (i > port_max) {
804       write_log(log_file, "[FATAL] Could not create listening socket on %s:%d-%d",
805                 ifs, port_min, port_max);
806       close(hSock);
807       return -1;
808     }
809     
810     if (listen(hSock, 5) == -1) {
811         write_log(log_file, "[FATAL] Could not listen on %s:%d",
812                   ifs, port);
813         close(hSock);
814         return -1;
815     }
816     
817     /* Set the socket to non blocking, and close it if we can't */
818     if (fcntl (hSock, F_SETFL, O_NONBLOCK) == -1) {
819         write_log(log_file, "[FATAL] Could not make socket non-blocking for %s:%d",
820                   ifs, port);
821         close(hSock);
822         return -1;
823     }
824     
825     // Inform caller of the port we bound to.
826     *port = i;
827     
828     return hSock;
829 }
830
831
832 /*===========================================================================*
833  *  int net_connect_to(int port, const char *ifs)
834  *
835  *    Open a network socket to the port and dotted-quad address string given.
836  *    The returned socket is set to non-blocking and keep-alive if the socket
837  *    was created.  -1 is returned on failure.
838  *
839  * DEPRECIATED: This function can block.  Should be using either
840  *              net_connect_outbound_nb or net_connect_inbound_nb
841  *===========================================================================*/
842
843 int net_connect_to(int port, const char *ifs)
844 {
845     int hSock;
846     struct sockaddr_in server;
847     int option;
848     
849     hSock = socket(PF_INET, SOCK_STREAM, 0);
850     if (hSock == -1) {
851         write_log(log_file, "Connection [%s:%d] failed [create]: %s [%d]",
852                   ifs, port, strerror(errno), errno);
853         return -1;
854     }
855     
856     option = 1;
857     if (setsockopt(hSock, SOL_SOCKET, SO_REUSEADDR, (void*) &option,
858                    sizeof(option)) < 0) {
859         write_log(log_file, "Connection [%s:%d] failed [options]: %s [%d]",
860                   ifs, port, strerror(errno), errno);
861         close(hSock);
862         return -1;
863     }
864     
865     option = 1;
866     if (setsockopt(hSock, SOL_SOCKET, SO_KEEPALIVE, (void*) &option,
867                    sizeof(option)) < 0) {
868         write_log(log_file, "Connection [%s:%d] failed [options]: %s [%d]",
869                   ifs, port, strerror(errno), errno);
870         close(hSock);
871         return -1;
872     }
873     
874     server.sin_family = AF_INET;
875     server.sin_addr.s_addr = inet_addr(ifs);
876     server.sin_port = htons(port);
877     if (connect(hSock, (struct sockaddr*) &server, sizeof(server)) == -1) {
878         write_log(log_file, "Connection [%s:%d] failed [conn]: %s [%d]",
879                   ifs, port, strerror(errno), errno);
880         close(hSock);
881         return -1;
882     }
883     
884     /* Set the socket to non blocking, and close it if we can't */
885     if (fcntl (hSock, F_SETFL, O_NONBLOCK) == -1) {
886         write_log(log_file, "Connection [%s:%d] closed [options]: %s [%d]",
887                   ifs, port, strerror(errno), errno);
888         close(hSock);
889         return -1;
890     }
891     
892     return hSock;
893 }
894
895 /*-------------------------------------------------------------------------
896   void* net_open_connection(int hSock)
897   
898   Open the next connection to the socket specified.  The socket supplied
899   must be in a listenning state.  This function returns a newly created
900   socket structure with information about the new connection, or -1 if
901   the socket could not be openned for some reason.
902   
903   The returned socket is setup for non-blocking, keep-alive.
904 -------------------------------------------------------------------------*/
905 int net_open_connection(int hSock, struct sockaddr_in *addr, int *salen)
906 {
907     int hNewSock;
908     int option;
909     
910     hNewSock = accept(hSock, (struct sockaddr *) addr, salen);
911     if (hNewSock == -1) {
912         write_log(log_file, "Accept failed [accept]: %s [%d]",
913                   strerror(errno), errno);
914         return -1;
915     }
916     
917     /* Set the socket to non blocking, and close it if we can't */
918     if (fcntl (hNewSock, F_SETFL, O_NONBLOCK) == -1) {
919         write_log(log_file, "Accept failed [options] [From %s:%d]: %s [%d]",
920                   inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
921                   strerror(errno), errno);
922         close(hNewSock);
923         return -1;
924     }
925     
926     option = 1;
927     if (setsockopt(hNewSock, SOL_SOCKET, SO_KEEPALIVE, (void*) &option,
928                    sizeof(option)) < 0) {
929         write_log(log_file, "Accept failed [options] [From %s:%d]: %s [%d]",
930                   inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
931                   strerror(errno), errno);
932         close(hNewSock);
933         return -1;
934     }
935     
936     return hNewSock;
937 }
938
939 /*-------------------------------------------------------------------------
940   filter_state* find_state(proxy_track_struct *pts,
941                            unsigned int  id)
942   
943   Search the list of filter state structures for the PTS, and return a
944   pointer to the appropriate one.
945
946   Return NULL if it does not exist.
947 -------------------------------------------------------------------------*/
948
949 filter_state *find_pts_state(proxy_track_struct *pts, unsigned int group_id)
950 {
951     filter_state *scan;
952     
953     scan = pts->state.next;
954     
955     while((scan) && (scan->filter_group != group_id))
956         scan = scan->next;
957     
958     return scan;
959 }
960
961 /*-------------------------------------------------------------------------
962   int add_pts_state(proxy_track_struct *pts,
963                     unsigned int  id,
964                     filter_state *add_state)
965   
966   Search the list of filter state structures for the PTS, and if a filter
967   state structure doesn't already exist, add the provided one.
968
969   Return 0 if the new data was not added.  1 if it was.
970 -------------------------------------------------------------------------*/
971
972 int add_pts_state(proxy_track_struct *pts, unsigned int group_id, filter_state *add_state)
973 {
974     if (find_pts_state(pts, group_id))
975         return 0;
976
977     add_state->next = pts->state.next;
978     pts->state.next = add_state;
979
980     return 1;
981 }
982
983 /*-------------------------------------------------------------------------
984   filter_state* del_pts_state(proxy_track_struct *pts,
985                               unsigned int  id)
986   
987   Search the list of filter state structures for the PTS, and if a filter
988   state structure exists, remove it from the list and return it.
989
990   Return NULL if there was no pts data.
991 -------------------------------------------------------------------------*/
992
993 filter_state * del_pts_state(proxy_track_struct *pts, unsigned int group_id)
994 {
995     filter_state *scan, *prev;
996     
997     prev = &pts->state;
998     scan = pts->state.next;
999     
1000     while(scan) {
1001         
1002         if (scan->filter_group == group_id) {
1003             prev->next = scan->next;
1004             return scan;
1005         }
1006         
1007         prev = scan;
1008         scan = scan->next;
1009     }
1010     
1011     return NULL;
1012 }
1013
1014 /*-------------------------------------------------------------------------
1015   proxy_track_struct* pts_allocate()
1016   
1017   Allocate the buffers, setup counters, sizes, empty filters for a new
1018   proxy tracking structure.
1019
1020   Return NULL if we can't allocate memory for some reason.
1021 -------------------------------------------------------------------------*/
1022
1023 proxy_track_struct *pts_allocate()
1024 {
1025     proxy_track_struct *pt;
1026     int sock;
1027     
1028     // Setup the tracking structure
1029     pt = calloc(sizeof(proxy_track_struct),1);
1030     if (!pt) {
1031         write_log(log_file, "[WARNING] Memory allocation failed for "
1032                   "proxy tracking structure.");
1033         return NULL;
1034     }
1035     
1036     pt->next       = NULL;
1037     pt->cleanup    = 0;
1038     pt->user       = 0;
1039     pt->state.next = NULL;
1040     
1041     // Setup the new user socket list.
1042     for (sock = 0; sock < 2; sock ++) {
1043         pt->sockets[sock]      = -1;
1044         pt->data_max[sock]     = PROXY_BUFFER_SIZE;
1045         pt->data_offset[sock]  = 0;
1046         pt->data_len[sock]     = 0;
1047         pt->data_buff[sock]    = malloc(pt->data_max[sock]);
1048
1049         if (!pt->data_buff[sock]) {
1050
1051             int fs;
1052             
1053             for (fs = 0; fs < sock; fs ++)
1054                 free(pt->data_buff[fs]);
1055             free(pt);
1056             
1057             write_log(log_file, "[WARNING] Memory allocation failed for "
1058                       "proxy tracking data buffers.");
1059             
1060             return NULL;
1061         }
1062
1063         pt->filter[sock] = NULL;
1064     }
1065     
1066     return pt;
1067 }
1068
1069 /*-------------------------------------------------------------------------
1070   int net_connect_outbound_nb()
1071   
1072   Setup an outbound non-blocking connection attempt.
1073
1074   Return 0 on a failure.  Note that is it upto the caller to free
1075   proc_data if this function fails.
1076 -------------------------------------------------------------------------*/
1077
1078 int net_connect_outbound_nb(listen_track_struct *lt,
1079                             connect_proc         proc,
1080                             void                *proc_data,
1081                             filter_chain        *tx_filter,
1082                             filter_chain        *rx_filter,
1083                             int                  force_dst_port)
1084 {
1085     int new_client, new_server;
1086     int salen, option;
1087     pending_connect_struct *pc;
1088     char *tmpstr;
1089     struct timeval tv_now;
1090     
1091     // Allocate pending connection tracker
1092     pc = calloc(sizeof(pending_connect_struct), 1);
1093     if (!pc) {
1094       return 0;
1095     }
1096
1097     gettimeofday(&tv_now, NULL);
1098
1099     // Add to the pc list.  This will do garbage collection
1100     pc->socket      = -1;
1101     pc->client_sock = -1;
1102     pc->proc        = proc;
1103     pc->proc_data   = proc_data;
1104     pc->filter[0]   = tx_filter;
1105     pc->filter[1]   = rx_filter;
1106     pc->timeout     = tv_now.tv_sec + CONNECT_TIMEOUT;
1107     pc->next        = pc_list.next;
1108     pc_list.next    = pc;
1109     
1110     // Open the pending connection (and log any errors)
1111     salen = sizeof(pc->src);
1112     new_client = net_open_connection(lt->socket, &pc->src, &salen);
1113     if (new_client == -1) {
1114         return 0;
1115     }
1116     
1117     // Read the original destination...
1118     salen = sizeof(pc->dst);
1119     if (gettranssockname(new_client, (struct sockaddr*) &pc->dst, &salen) == -1) {
1120         write_log(log_file, "[CONN_NB] Connection [%s:%d -> ip.ip.ip.ip:port via proxy] failed "
1121                   "[Could not determine original destination]: %s [%d]",
1122                   inet_ntoa(pc->src.sin_addr), ntohs(pc->src.sin_port),
1123                   strerror(errno), errno);
1124         close(new_client);
1125         return 0;
1126     }
1127
1128     if (force_dst_port != -1) {
1129       if (force_dst_port != ntohs(pc->dst.sin_port)) {
1130
1131         tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1132         write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy]  "
1133                   "[Forcing target port to %d]",
1134                   tmpstr,                      ntohs(pc->src.sin_port),
1135                   inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1136                   force_dst_port);
1137         free(tmpstr);
1138         
1139         pc->dst.sin_port = htons(force_dst_port);
1140       }
1141     }
1142     
1143     // Create the onward socket
1144     new_server = socket(PF_INET, SOCK_STREAM, 0);
1145     if (new_server == -1) {
1146
1147         tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1148         write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy] failed "
1149                   "[Could not create onward socket]: %s [%d]",
1150                   tmpstr,                      ntohs(pc->src.sin_port),
1151                   inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1152                   strerror(errno), errno);
1153         free(tmpstr);
1154         close(new_client);
1155         return 0;
1156     }
1157
1158     // Record the socket handles in the track struct
1159     pc->socket      = new_server;
1160     pc->client_sock = new_client;
1161     
1162     option = 1;
1163     setsockopt(new_server, SOL_SOCKET, SO_REUSEADDR, (void*) &option, sizeof(option));
1164     
1165     option = 1;
1166     setsockopt(new_server, SOL_SOCKET, SO_KEEPALIVE, (void*) &option, sizeof(option));
1167     
1168     fcntl(new_server, F_SETFL, O_NONBLOCK);
1169     
1170     if (connect(new_server, (struct sockaddr*) &pc->dst, sizeof(pc->dst)) == -1) {
1171       
1172       // If it's pending, we're done, and the bottom half will be called from the
1173       // main select() loop
1174       if (errno == EINPROGRESS) {
1175
1176         tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1177         write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy] created [pending connection] (%d %d)",
1178                   tmpstr,                      ntohs(pc->src.sin_port),
1179                   inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1180                   pc->client_sock, pc->socket);
1181         free(tmpstr);
1182         return 1;
1183       }
1184       
1185       // On other errors, kill the connection.
1186       tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1187       write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy] failed "
1188                 "[Connect returned error]: %s [%d]",
1189                 tmpstr,                      ntohs(pc->src.sin_port),
1190                 inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1191                 strerror(errno), errno);
1192       free(tmpstr);
1193       
1194       // Cleanup of the pending connect struct is done in the main loop
1195       close(new_client);
1196       close(new_server);
1197       pc->socket = -1;
1198       pc->client_sock = -1;
1199       return 0;
1200     }
1201     
1202     // The connection succeeded immediately.  Aren't we lucky.
1203     tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1204     write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy] created [connection made]",
1205               tmpstr,                      ntohs(pc->src.sin_port),
1206               inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port));
1207     free(tmpstr);
1208     
1209     // As we connected immediately, call the processing routine directly.
1210     pc->proc(pc);
1211     
1212     return 1;
1213 }
1214
1215 /*-------------------------------------------------------------------------
1216   int net_connect_inbound_nb()
1217   
1218   Setup an inbound non-blocking connection attempt.
1219   
1220   Return 0 on a failure.  Note that is it upto the caller to free
1221   proc_data if this function fails.
1222 -------------------------------------------------------------------------*/
1223
1224 int net_connect_inbound_nb(listen_track_struct *lt,
1225                            connect_proc         proc,
1226                            pending_dc_struct   *pdc,
1227                            filter_chain        *tx_filter,
1228                            filter_chain        *rx_filter,
1229                            int                  force_dst_port)
1230 {
1231     int new_client, new_server;
1232     int salen, option;
1233     pending_connect_struct *pc;
1234     char *tmpstr;
1235     struct timeval tv_now;
1236
1237     // We have to clean up the pdc in here.
1238     pdc->cleanup = 1;
1239     
1240     // Allocate pending connection tracker
1241     pc = calloc(sizeof(pending_connect_struct), 1);
1242     if (!pc) {
1243       return 0;
1244     }
1245
1246     gettimeofday(&tv_now, NULL);
1247
1248     // Add to the pc list.  This will do garbage collection
1249     pc->socket      = -1;
1250     pc->client_sock = -1;
1251     pc->proc        = proc;
1252     pc->proc_data   = NULL;
1253     pc->filter[0]   = tx_filter;
1254     pc->filter[1]   = rx_filter;
1255     pc->timeout     = tv_now.tv_sec + CONNECT_TIMEOUT;
1256     pc->next        = pc_list.next;
1257     pc_list.next    = pc;
1258     
1259     // Open the pending connection (and log any errors)
1260     salen = sizeof(pc->src);
1261     new_client = net_open_connection(lt->socket, &pc->src, &salen);
1262     if (new_client == -1) {
1263         return 0;
1264     }
1265
1266     // The pdc contains the destination address / port
1267
1268     memcpy(&pc->dst, &pdc->src, sizeof(pdc->src));
1269     pc->dst.sin_port = htons(pdc->orig_port);
1270     
1271     if (force_dst_port != -1) {
1272       if (force_dst_port != ntohs(pc->dst.sin_port)) {
1273
1274         tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1275         write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy]  "
1276                   "[Forcing target port to %d]",
1277                   tmpstr,                      ntohs(pc->src.sin_port),
1278                   inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1279                   force_dst_port);
1280         free(tmpstr);
1281         
1282         pc->dst.sin_port = htons(force_dst_port);
1283       }
1284     }
1285     
1286     // Create the onward socket
1287     new_server = socket(PF_INET, SOCK_STREAM, 0);
1288     if (new_server == -1) {
1289
1290         tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1291         write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy] failed "
1292                   "[Could not create onward socket]: %s [%d]",
1293                   tmpstr,                      ntohs(pc->src.sin_port),
1294                   inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1295                   strerror(errno), errno);
1296         free(tmpstr);
1297         close(new_client);
1298         return 0;
1299     }
1300
1301     // Record the socket handles in the track struct
1302     pc->socket      = new_server;
1303     pc->client_sock = new_client;
1304     
1305     option = 1;
1306     setsockopt(new_server, SOL_SOCKET, SO_REUSEADDR, (void*) &option, sizeof(option));
1307     
1308     option = 1;
1309     setsockopt(new_server, SOL_SOCKET, SO_KEEPALIVE, (void*) &option, sizeof(option));
1310     
1311     fcntl(new_server, F_SETFL, O_NONBLOCK);
1312     
1313     if (connect(new_server, (struct sockaddr*) &pc->dst, sizeof(pc->dst)) == -1) {
1314       
1315       // If it's pending, we're done, and the bottom half will be called from the
1316       // main select() loop
1317       if (errno == EINPROGRESS) {
1318
1319         tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1320         write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy] created [pending connection] (%d %d)",
1321                   tmpstr,                      ntohs(pc->src.sin_port),
1322                   inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1323                   pc->client_sock, pc->socket);
1324         free(tmpstr);
1325         return 1;
1326       }
1327       
1328       // On other errors, kill the connection.
1329       tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1330       write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy] failed "
1331                 "[Connect returned error]: %s [%d]",
1332                 tmpstr,                      ntohs(pc->src.sin_port),
1333                 inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1334                 strerror(errno), errno);
1335       free(tmpstr);
1336       
1337       // Cleanup of the pending connect struct is done in the main loop
1338       close(new_client);
1339       close(new_server);
1340       pc->socket = -1;
1341       pc->client_sock = -1;
1342       return 0;
1343     }
1344     
1345     // The connection succeeded immediately.  Aren't we lucky.
1346     tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1347     write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy] created [connection made]",
1348               tmpstr,                      ntohs(pc->src.sin_port),
1349               inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port));
1350     free(tmpstr);
1351     
1352     // As we connected immediately, call the processing routine directly.
1353     pc->proc(pc);
1354     
1355     return 1;
1356 }
1357
1358 /*-------------------------------------------------------------------------
1359   void* conn_open_outbound_generic(pending_connect_struct *pc)
1360   
1361   The onward connection has completed.  This function cleans up if it
1362   failed, or allocates the tracking and filter structures as needed if
1363   the connection is established.
1364
1365   Either way, we have to set the pending connection structure to the
1366   cleanup state, so we can garbage collect it.
1367 -------------------------------------------------------------------------*/
1368 void conn_open_outbound_generic(pending_connect_struct *pc)
1369 {
1370   int se, sel;
1371   user_track_struct  *ts;
1372   proxy_track_struct *pt;
1373   char *tmpstr;
1374
1375   // Check if the connection succeeded or failed as we did an
1376   // asynchronous connect.
1377   if (getsockopt(pc->socket, SOL_SOCKET, SO_ERROR, &se, &sel) == -1) {
1378
1379       tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1380       write_log(log_file, "[CONN_BH] Connection [%s:%d -> %s:%d via proxy] failed "
1381                 "[Unable to get connect status]: %s [%d] (%d:%d)",
1382                 tmpstr,                      ntohs(pc->src.sin_port),
1383                 inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1384                 strerror(errno), errno,
1385                 pc->client_sock, pc->socket);
1386       free(tmpstr);
1387
1388       close(pc->client_sock);
1389       close(pc->socket);
1390       pc->socket = -1;
1391       pc->client_sock = -1;
1392       return;
1393   }
1394   
1395   // se is non zero if the connection failed.
1396   if (se != 0) {
1397
1398       tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1399       write_log(log_file, "[CONN_BH] Connection [%s:%d -> %s:%d via proxy] failed "
1400                 "[Connect returned error]: %s [%d] (%d %d)",
1401                 tmpstr,                      ntohs(pc->src.sin_port),
1402                 inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1403                 strerror(errno), errno,
1404                 pc->client_sock, pc->socket);
1405       free(tmpstr);
1406       close(pc->client_sock);
1407       close(pc->socket);
1408       pc->socket      = -1;
1409       pc->client_sock = -1;
1410       return;
1411   }
1412   
1413   // Setup the tracking structure
1414   ts = calloc(sizeof(user_track_struct), 1);
1415   ts->magic = ts_magic ++;
1416   ts->next = user_list.next;
1417   user_list.next = ts;
1418   
1419   pt = pts_allocate();
1420   if (!pt) {
1421     
1422       tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1423       write_log(log_file, "[CONN_BH] Connection [%s:%d -> %s:%d via proxy] failed "
1424                 "[Failed to allocate tracking struct] (%d %d)",
1425                 tmpstr,                      ntohs(pc->src.sin_port),
1426                 inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1427                 pc->client_sock, pc->socket);
1428       free(tmpstr);
1429     
1430       ts->cleanup = 1;
1431       close(pc->socket);
1432       close(pc->client_sock);
1433       pc->socket = -1;
1434       pc->client_sock = -1;
1435       return;
1436   }
1437   
1438   pt->sockets[0] = pc->client_sock;
1439   pt->sockets[1] = pc->socket;
1440   pt->filter[0] = pc->filter[0];
1441   pt->filter[1] = pc->filter[1];
1442   pt->user  = 1;
1443   pt->magic = ts->magic;
1444   
1445   pt->next = pt_list.next;
1446   pt_list.next = pt;
1447   
1448   tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1449   write_log(log_file, "[CONN_BH] Connection [%s:%d -> %s:%d via proxy] established "
1450             "[magic = %d] (%d %d)",
1451             tmpstr,                      ntohs(pc->src.sin_port),
1452             inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1453             pt->magic, pc->client_sock, pc->socket);
1454   free(tmpstr);
1455   
1456   // Flag the pending connection for garbage collect without
1457   // closing the connections (which we just handed off to the
1458   // pt tracking struct)
1459   pc->socket = -1;
1460   pc->client_sock = -1;
1461 }
1462
1463
1464 /*-------------------------------------------------------------------------
1465   void* conn_open_inbound_generic(pending_connect_struct *pc)
1466   
1467   The onward connection has completed.  This function cleans up if it
1468   failed, or allocates the tracking and filter structures as needed if
1469   the connection is established.
1470
1471   Either way, we have to set the pending connection structure to the
1472   cleanup state, so we can garbage collect it.
1473 -------------------------------------------------------------------------*/
1474 void conn_open_inbound_generic(pending_connect_struct *pc)
1475 {
1476   int se, sel;
1477   proxy_track_struct *pt;
1478   char *tmpstr;
1479
1480   // Check if the connection succeeded or failed as we did an
1481   // asynchronous connect.
1482   if (getsockopt(pc->socket, SOL_SOCKET, SO_ERROR, &se, &sel) == -1) {
1483
1484       tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1485       write_log(log_file, "[CONN_BH] Connection [%s:%d -> %s:%d via proxy] failed "
1486                 "[Unable to get connect status]: %s [%d] (%d:%d)",
1487                 tmpstr,                      ntohs(pc->src.sin_port),
1488                 inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1489                 strerror(errno), errno,
1490                 pc->client_sock, pc->socket);
1491       free(tmpstr);
1492
1493       close(pc->client_sock);
1494       close(pc->socket);
1495       pc->socket = -1;
1496       pc->client_sock = -1;
1497       return;
1498   }
1499   
1500   // se is non zero if the connection failed.
1501   if (se != 0) {
1502
1503       tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1504       write_log(log_file, "[CONN_BH] Connection [%s:%d -> %s:%d via proxy] failed "
1505                 "[Connect returned error]: %s [%d] (%d %d)",
1506                 tmpstr,                      ntohs(pc->src.sin_port),
1507                 inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1508                 strerror(errno), errno,
1509                 pc->client_sock, pc->socket);
1510       free(tmpstr);
1511       close(pc->client_sock);
1512       close(pc->socket);
1513       pc->socket      = -1;
1514       pc->client_sock = -1;
1515       return;
1516   }
1517   
1518   pt = pts_allocate();
1519   if (!pt) {
1520     
1521       tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1522       write_log(log_file, "[CONN_BH] Connection [%s:%d -> %s:%d via proxy] failed "
1523                 "[Failed to allocate tracking struct] (%d %d)",
1524                 tmpstr,                      ntohs(pc->src.sin_port),
1525                 inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1526                 pc->client_sock, pc->socket);
1527       free(tmpstr);
1528     
1529       close(pc->socket);
1530       close(pc->client_sock);
1531       pc->socket = -1;
1532       pc->client_sock = -1;
1533       return;
1534   }
1535   
1536   pt->sockets[0] = pc->client_sock;
1537   pt->sockets[1] = pc->socket;
1538   pt->filter[0] = pc->filter[0];
1539   pt->filter[1] = pc->filter[1];
1540   
1541   pt->next = pt_list.next;
1542   pt_list.next = pt;
1543   
1544   tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1545   write_log(log_file, "[CONN_BH] Connection [%s:%d -> %s:%d via proxy] established "
1546             "(%d %d)",
1547             tmpstr,                      ntohs(pc->src.sin_port),
1548             inet_ntoa(pc->dst.sin_addr), ntohs(pc->dst.sin_port),
1549             pc->client_sock, pc->socket);
1550   free(tmpstr);
1551   
1552   // Flag the pending connection for garbage collect without
1553   // closing the connections (which we just handed off to the
1554   // pt tracking struct)
1555   pc->socket = -1;
1556   pc->client_sock = -1;
1557 }
1558
1559
1560 /*-------------------------------------------------------------------------
1561   void net_open_aim_oscar(listen_track_struct *lt)
1562
1563   Setup a generic open and callback pair which will attach the oscar filter
1564   if the connection is successfully established.
1565
1566   This should only be called for connections heading out of the LAN to
1567   the off-site servers.
1568 -------------------------------------------------------------------------*/
1569
1570 void net_open_aim_oscar(listen_track_struct *lt)
1571 {
1572
1573   net_connect_outbound_nb(lt, conn_open_outbound_generic, NULL, &oscar_tx, &oscar_rx, lt->port);
1574
1575 }
1576
1577
1578 /*-------------------------------------------------------------------------
1579   void net_open_log_attempt(listen_track_struct *lt)
1580   
1581   This function is used for ports we are listenning to but never expecting
1582   to be connected to.  We log the attempt for diagnostic purposes.
1583 -------------------------------------------------------------------------*/
1584 void net_open_log_attempt(listen_track_struct *lt)
1585 {
1586   struct sockaddr_in src_addr;
1587   int salen;
1588   int new_remote;
1589   
1590   // Open the pending connection....
1591   salen = sizeof(src_addr);
1592   new_remote = net_open_connection(lt->socket, &src_addr, &salen);
1593   if (new_remote == -1)
1594     return;
1595   close(new_remote);
1596   
1597   write_log(log_file, "[WARNING] Unexpected connection or attempted port scan [%s:%d -> proxy:%d]",
1598             inet_ntoa(src_addr.sin_addr),
1599             ntohs(src_addr.sin_port),
1600             lt->port);
1601 }
1602
1603
1604 /*-------------------------------------------------------------------------
1605   void net_open_aim(listen_track_struct *lt)
1606   
1607   Open the direct connection attempt from the remote party, and alloc
1608   the generic proxy_track struct.
1609   
1610   This routine should be able to open a connection back to the inside as
1611   there should be only 1 pending connection for each listening port.
1612
1613   A warning is logged if this isn't the case.
1614
1615   This should only ever be called for incoming requests from offsite hosts.
1616 -------------------------------------------------------------------------*/
1617 void net_open_aim(listen_track_struct *lt)
1618 {
1619     pending_dc_struct *pms, *first;
1620     int count;
1621
1622     // Look for a pending connection for this port
1623     pms = dc_list.next;
1624     first = NULL;
1625     count = 0;
1626     
1627     while(pms) {
1628       
1629       if (pms->cleanup == 0) {
1630         
1631         if (pms->port == lt->port) {
1632           count ++;
1633           first = pms;
1634         }
1635         
1636       }
1637       
1638       pms = pms->next;
1639     }
1640     
1641     switch(count) {
1642     case 1:
1643       // Okay.  All is well...
1644
1645       net_connect_inbound_nb(lt, conn_open_inbound_generic, first, &share_tx, &share_rx, -1);
1646
1647       return;
1648       
1649     case 0:
1650       // We are probably being scanned...but we shouldn't be listening if
1651       // there is no pending connection...  Just flag a warning.
1652       net_open_log_attempt(lt);
1653       break;
1654       
1655     default:
1656       // Too many pending connections in the list.
1657
1658       // Shouldn't ever get here.  Should never have more than 1 pending connection
1659       // per port.
1660       write_log(log_file, "[WARNING] Couldn't find exactly 1 connection in pending list. [proxy:%d]",
1661                 lt->port);
1662       break;
1663     }
1664 }
1665
1666
1667 /*-------------------------------------------------------------------------
1668   void net_open_buggy_aim_dcc(listen_track_struct *lt)
1669   
1670   AIM appears to ignore the port specified in a direct connection setup.
1671   This breaks the dynamic dcc mapping, so we have this function to trap
1672   the buggy connection attempts to port 4443, and to do a fuzzy search
1673   of the pending connections list for a match.
1674
1675   This routine can only open a connection back to the inside if
1676   there is only 1 pending connection for an inside machine on port 4443.
1677
1678   A warning is logged if this isn't the case.
1679
1680   This should only ever be called for incoming requests from offsite hosts.
1681 -------------------------------------------------------------------------*/
1682 void net_open_buggy_aim_dcc(listen_track_struct *lt)
1683 {
1684     pending_dc_struct *pms, *first, *loose;
1685     listen_track_struct *ls;
1686     int count, loose_count;
1687
1688     // Look for a pending connection for this port
1689     pms = dc_list.next;
1690     first = NULL;
1691     count = 0;
1692     loose = NULL;
1693     loose_count = 0;
1694     
1695     while(pms) {
1696       
1697       if (pms->cleanup == 0) {
1698         
1699         if (pms->orig_port == lt->port) {
1700           count ++;
1701           first = pms;
1702         }
1703
1704         // Buggy client hack
1705         loose_count++;
1706         loose = pms;
1707         
1708       }
1709       
1710       pms = pms->next;
1711     }
1712     
1713     switch(count) {
1714     case 1:
1715       // Okay.  All is well...apart from the buggy AIM client
1716       
1717       write_log(log_file, "[WARNING] Unexpected connection to port %d.  Single match for buggy DCC found.",
1718                 lt->port);
1719       
1720       // Note we have to manually clean up the dynamic dcc listener as
1721       // we picked up the DCC on port 4443 rather than the one we were
1722       // supposed to be contacted on.
1723
1724       // Search for the listen tracker on the port in the pending_dc struct.
1725       ls = lt_list.next;
1726       while(ls) {
1727         if (ls->port == first->port)
1728           ls->cleanup = 1;
1729
1730         ls = ls->next;
1731       }
1732
1733       net_connect_inbound_nb(lt, conn_open_inbound_generic, first, &share_tx, &share_rx, -1);
1734
1735       return;
1736       
1737     case 0:
1738       // Didn't find any matches with strict port checking.  Try loose!
1739       if (loose_count == 1) {
1740         
1741         // Note we have to manually clean up the dynamic dcc listener as
1742         // we picked up the DCC on 4443 rather than the one we were
1743         // supposed to be contacted on.
1744         
1745         // Search for the listen tracker on the port in the pending_dc struct.
1746         ls = lt_list.next;
1747         while(ls) {
1748           if (ls->port == loose->port)
1749             ls->cleanup = 1;
1750           
1751           ls = ls->next;
1752         }
1753         
1754         write_log(log_file, "[WARNING] Unexpected connection to port %d.  Loose single match for buggy DCC. (Expected %d)",
1755                   lt->port, loose->port);
1756         
1757         net_connect_inbound_nb(lt, conn_open_inbound_generic, loose, &share_tx, &share_rx, DCC);
1758         
1759         return;
1760         
1761       }
1762     default:
1763       // Log the attempt.  We can get here if there is more than one DCC pending
1764       // or we're being port scanned.
1765       net_open_log_attempt(lt);
1766       break;
1767     }
1768 }
1769
1770
1771 /*-------------------------------------------------------------------------
1772   void net_open_msn(listen_track_struct *lt)
1773   
1774   Open the connection attempt from the LAN client, create the onward
1775   socket for the proxying, and allocate a tracking structure.
1776   
1777   If any steps fail, the client connection is terminated.
1778 -------------------------------------------------------------------------*/
1779
1780 void net_open_msn(listen_track_struct *lt)
1781 {
1782
1783   net_connect_outbound_nb(lt, conn_open_outbound_generic, NULL, &msn_tx, &msn_rx, lt->port);
1784
1785
1786
1787 /*-------------------------------------------------------------------------
1788   void net_open_msnrx(listen_track_struct *lt)
1789   
1790   Open the direct connection attempt from the remote party, and allocate
1791   the connection tracking structure.
1792   
1793   We know exactly which host to connect to as we are using dynamic dcc
1794   ports - one per connection.  Anything else causes an error to be
1795   flagged.
1796 -------------------------------------------------------------------------*/
1797 void net_open_msnrx(listen_track_struct *lt)
1798 {
1799     pending_dc_struct *pms, *first;
1800     int count;
1801
1802     // Look for a pending connection for this port
1803     pms = dc_list.next;
1804     first = NULL;
1805     count = 0;
1806     
1807     while(pms) {
1808       
1809       if (pms->cleanup == 0) {
1810         
1811         if (pms->port == lt->port) {
1812           count ++;
1813           first = pms;
1814         }
1815         
1816       }
1817       
1818       pms = pms->next;
1819     }
1820     
1821     switch(count) {
1822     case 1:
1823       // Okay.  All is well...
1824
1825       net_connect_inbound_nb(lt, conn_open_inbound_generic, first, &msnrx_tx, &msnrx_rx, -1);
1826
1827       return;
1828       
1829     case 0:
1830     default:
1831       // No/too many pending connections in the list.
1832
1833       // Shouldn't ever get here.  Should never have more than 1 pending connection
1834       // per port.
1835       write_log(log_file, "[WARNING] Couldn't find exactly 1 connection in pending list. [proxy:%d]",
1836                 lt->port);
1837       break;
1838     }
1839 }
1840
1841 /*-------------------------------------------------------------------------
1842   unsigned int fp_process(unsigned char *buff,
1843                           unsigned int len,
1844                           unsigned int max,
1845                           filter_chain *fc,
1846                           proxy_track_struct *pt)
1847
1848   Pass the packet through the filter chain.  Nice and simple really.
1849
1850   A NULL filter chain is valid, and mean 'pass unchanged'
1851   
1852 -------------------------------------------------------------------------*/
1853
1854 unsigned int fp_process(unsigned char *buff,
1855                         unsigned int len, unsigned int max,
1856                         filter_chain *fc,
1857                         proxy_track_struct *pt)
1858 {
1859     int i;
1860     
1861     // Pass the data unchanged if there's no filter chain.
1862     if (!fc)
1863         return len;
1864     
1865     // Should be a little less lazy about using a fixed upper size limit
1866     // but there's no point making it complex for now.
1867     for (i = 0; (i < MAX_FILTERS) && fc->proc[i]; i++)
1868         len = fc->proc[i](buff, len, max, pt);
1869     
1870     return len;
1871 }
1872
1873 /*-------------------------------------------------------------------------
1874   int fp_locate(unsigned char *data_buff, unsigned int data_len,
1875                 unsigned char *find_buff, unsigned int find_len,
1876                 unsigned char *mask_buff)
1877                           
1878   Filter helper:  Binary search for find_buff in data_buff, and return the
1879                   offset.  The buffers are masked with the mask_buff.
1880   
1881   Returns -1 if the sub-string can't be found.
1882 -------------------------------------------------------------------------*/
1883
1884 int fp_locate(unsigned char *data_buff, unsigned int data_len,
1885               unsigned char *find_buff, unsigned int find_len,
1886               unsigned char *mask_buff)
1887 {
1888   unsigned int s, i;
1889
1890   if (find_len > data_len)
1891     return -1;
1892   
1893   for (s = 0; s < data_len - find_len; s++) {
1894     
1895     for (i = 0; i < find_len; i++) {
1896       
1897       if ((data_buff[s+i] & mask_buff[i]) != (find_buff[i] & mask_buff[i]))
1898         break;
1899     }
1900     
1901     if (i == find_len)
1902       return s;
1903   }
1904   
1905   return -1;
1906 }
1907
1908 /*-------------------------------------------------------------------------
1909   unsigned int fp_oscar_tx(unsigned char *buff,
1910                            unsigned int len,
1911                            unsigned int max,
1912                            proxy_track_struct *pt)
1913                           
1914   Filter procedure: Search for and modify OSCAR IP/Port specifications in
1915                     passing packets.
1916   
1917   If the packet does not appear to be a file transfer setup, return it
1918   unchanged.
1919   
1920   If it appears to have an IP/port setting, setup a listen socket for
1921   the anticipated return packet.
1922
1923 -------------------------------------------------------------------------*/
1924
1925 unsigned int fp_oscar_tx(unsigned char *buff,
1926                          unsigned int len, unsigned int max,
1927                          proxy_track_struct *pt)
1928 {
1929 #if USE_DYNAMIC_DCC
1930     listen_track_struct *lt;
1931     struct timeval tv_now;
1932 #endif
1933     
1934     // Not long enough for us to check properly...
1935     if (len < 26)
1936         return len;
1937     
1938     // Check its long enough for the TLV_TYPE
1939     if (len < AIM_BUD_NEXT(buff) + 2)
1940         return len;
1941     
1942     // Does it look like a potential Direct Connection setup packet ?
1943     if ((AIM_CMDSTART(buff)        == 0x2a) &&
1944         (AIM_CHANNEL(buff)         == 0x02) &&
1945         (AIM_FNAC_FAMILY(buff)     == 0x0004) &&
1946         (AIM_FNAC_SUBTYPE(buff)    == 0x0006) &&
1947         (AIM_FNAC_FLAGS(buff)      == 0x0000) &&
1948         (AIM_SNAC_CHAN(buff)       == 0x0002) &&
1949         (AIM_SNAC_TLV_TYPE(buff)   == 0x0005)) {
1950
1951         int alloc_port, orig_dcc_port;
1952         int ip[4], ip_offset, src_ip[4], offset;
1953         struct sockaddr_in src_addr;
1954         int salen;
1955         unsigned char scan[12], mask[12];
1956         pending_dc_struct *pdc;
1957
1958         // Read the source IP for the client connection.
1959         // We use this for extra sanity checks in locating the client IP
1960         // in the setup packet
1961         salen = sizeof(struct sockaddr_in);
1962         if (getpeername(pt->sockets[TS_CLIENT], (struct sockaddr*) &src_addr, &salen) == -1) {
1963             return len;
1964         }
1965         
1966         sscanf(inet_ntoa(src_addr.sin_addr), "%d.%d.%d.%d", &src_ip[0], &src_ip[1], &src_ip[2], &src_ip[3]);
1967
1968         // Look for a sequence in the packet that is 00 03 00 04 IP IP IP IP 00 05 00 02 ?? ??
1969         scan[0] = 0x00;
1970         scan[1] = 0x03;
1971         scan[2] = 0x00;
1972         scan[3] = 0x04;
1973         scan[4] = src_ip[0];
1974         scan[5] = src_ip[1];
1975         scan[6] = src_ip[2];
1976         scan[7] = src_ip[3];
1977         scan[8] = 0x00;
1978         scan[9] = 0x05;
1979         scan[10] = 0x00;
1980         scan[11] = 0x02;
1981
1982         // Setup the mask
1983         memset(mask, 255, sizeof(mask));
1984         mask[4] = mask[5] = mask[6] = mask[7] = 0;
1985         
1986         // Search for the IP/port address sequence
1987         offset = fp_locate(buff, len, scan, 12, mask);
1988         if (offset == -1)
1989           return len;
1990
1991         // Extract the original DCC port on the inside host
1992         orig_dcc_port = (buff[offset + 12] << 8) | buff[offset + 13];
1993
1994         // Point to the actual address by adjusting over the search preamble.
1995         ip_offset = offset + 4;
1996         
1997         // Okay.  Determine which address to overwrite the client IP with...
1998         if (outside_ip == NULL) {
1999             
2000             // Make a best guess here because we weren't told....
2001             struct sockaddr_in svr_addr;
2002             
2003             // Read the source address of the connection to the server
2004             // and give up if we can't...
2005             salen = sizeof(struct sockaddr_in);
2006             if (getsockname(pt->sockets[TS_SERVER], (struct sockaddr*) &svr_addr, &salen) == -1) {
2007                 write_log(log_file, "Found a DCC F setup, but couldn't get the external IP - dodo mode.");
2008                 return len;
2009             }
2010             
2011             sscanf(inet_ntoa(svr_addr.sin_addr), "%d.%d.%d.%d",
2012                    &ip[0], &ip[1], &ip[2], &ip[3]);
2013             
2014         } else {
2015             
2016             if (sscanf(outside_ip, "%d.%d.%d.%d",
2017                        &ip[0], &ip[1], &ip[2], &ip[3]) != 4) {
2018                 write_log(log_file, "Bad external proxy IP address specified - [%s] Dodo mode",
2019                           outside_ip);
2020                 return len;
2021             }
2022         }
2023         
2024 #if USE_DYNAMIC_DCC
2025         lt = create_listener_between(INC_MIN, INC_MAX, net_open_aim);
2026         // Couldn't create onward, so can't mangle this request.
2027         if (!lt)
2028           return len;
2029         
2030         // Setup as a 1 shot with a 30 second limit.
2031         lt->oneshot = 1;
2032         gettimeofday(&tv_now, NULL);
2033         lt->timeout = tv_now.tv_sec + INC_TIMEOUT;
2034         
2035         alloc_port = lt->port;
2036 #else
2037         alloc_port = SHARE;
2038 #endif
2039         
2040         // Mangle the data so it has the outside IP address
2041         // and port in the right place.
2042         buff[ip_offset + 0] = ip[0];
2043         buff[ip_offset + 1] = ip[1];
2044         buff[ip_offset + 2] = ip[2];
2045         buff[ip_offset + 3] = ip[3];
2046         buff[ip_offset + 8] = (alloc_port >> 8) & 0xff;
2047         buff[ip_offset + 9] = alloc_port & 0xff;
2048         
2049         // Report the mangling we just did
2050         write_log(log_file,"[MASQ] DCC F Setup IP Changed "
2051                   "[%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d] [offset=%d] [buddy=%.*s]",
2052                   src_ip[0], src_ip[1], src_ip[2], src_ip[3], orig_dcc_port,
2053                   ip[0], ip[1], ip[2], ip[3], alloc_port,
2054                   ip_offset,
2055                   AIM_BUD_NAME_LEN(buff), AIM_BUD_NAME(buff));
2056         
2057         // Allocate a pending_dc_struct here.
2058         pdc = malloc(sizeof(pending_dc_struct));
2059         memset(pdc, 0, sizeof(pending_dc_struct));
2060
2061         pdc->magic = pt->magic;
2062         pdc->id[0] = AIM_SNAC_COOKIE(buff)[0];
2063         pdc->id[1] = AIM_SNAC_COOKIE(buff)[1];
2064         pdc->id[2] = AIM_SNAC_COOKIE(buff)[2];
2065         pdc->id[3] = AIM_SNAC_COOKIE(buff)[3];
2066         pdc->id[4] = AIM_SNAC_COOKIE(buff)[4];
2067         pdc->id[5] = AIM_SNAC_COOKIE(buff)[5];
2068         pdc->id[6] = AIM_SNAC_COOKIE(buff)[6];
2069         pdc->id[7] = AIM_SNAC_COOKIE(buff)[7];
2070
2071         pdc->port = alloc_port;
2072         pdc->orig_port = orig_dcc_port;
2073
2074         // Copy the original source address information into the DC struct
2075         // We need this to establish the back connection.
2076         memcpy(&pdc->src, &src_addr, sizeof(src_addr));
2077         
2078         pdc->next = dc_list.next;
2079         dc_list.next = pdc;
2080     }
2081     
2082     return len;
2083 }
2084
2085
2086 /*-------------------------------------------------------------------------
2087   unsigned int fp_msn_tx_dcc_setup(unsigned char *buff,
2088                                    unsigned int len, unsigned int max,
2089                                    proxy_track_struct *pt)
2090   
2091   This function examines data flowing out from this machine for answers
2092   to direct connection setup queries.
2093   
2094   If it looks like a DCC request, we search for the IP address and port
2095   being sent to the remote party, and we overwrite it with the external
2096   IP address, and a port from the dynamic dcc range.
2097
2098   Having done that, we setup a pending connection structure, and create
2099   the listenner that will process the incoming request from the remote
2100   party. (See net_open_msnrx for the incoming request processing)
2101 -------------------------------------------------------------------------*/
2102
2103 unsigned int fp_msn_tx_dcc_setup(unsigned char *buff,
2104                          unsigned int len, unsigned int max,
2105                          proxy_track_struct *pt)
2106 {
2107     int port, cookie;
2108
2109     int ip[4], src_ip[4];
2110     struct sockaddr_in src_addr;
2111     int salen;
2112     pending_dc_struct *pdc;
2113     char copy_msg[2048], *pHdrs[32], *pMsgs[32], *scan, tmpbuf[256];
2114     int hdr_fields, msg_fields, find, dcc_port;
2115 #if USE_DYNAMIC_DCC
2116     listen_track_struct *lt;
2117     struct timeval tv_now;
2118 #endif
2119     
2120     // Not long enough for a dcc setup request or too long...
2121     if (len < 85 || len >= sizeof(copy_msg))
2122         return len;
2123     
2124     memcpy(copy_msg, buff, len);
2125     copy_msg[len] = '\0';
2126
2127     hdr_fields = 0;
2128     
2129     for (scan = copy_msg;
2130          (scan != NULL) &&
2131          (scan[0] != '\0') &&
2132              (scan[0] != '\r') &&
2133              (scan[1] != '\n');) {
2134
2135         pHdrs[hdr_fields] = scan;
2136         hdr_fields ++;
2137         if (hdr_fields == 32)
2138             return len;
2139         
2140         scan = strstr(scan, "\r\n");
2141         if (scan) {
2142             *scan = '\0'; // NULL terminate the pHdr
2143             scan += 2;    // Shuffle past the \r\n
2144         }
2145     }
2146     
2147     // Badly formed buffer
2148     if (!scan || scan[0] == '\0')
2149         return len;
2150
2151     scan += 2; // Skip the \r\n separator
2152
2153     msg_fields = 0;
2154     
2155     for (;
2156          (scan != NULL) &&
2157          (scan[0] != '\0') &&
2158              (scan[0] != '\r') &&
2159              (scan[1] != '\n');) {
2160
2161         pMsgs[msg_fields] = scan;
2162         msg_fields ++;
2163         if (msg_fields == 32)
2164             return len;
2165         
2166         scan = strstr(scan, "\r\n");
2167         if (scan) {
2168             *scan = '\0'; // NULL terminate the pMsg
2169             scan += 2;    // Shuffle past the \r\n
2170         }
2171     }
2172
2173 #if TRILLIAN_HEADER_SUPPORT
2174     // Trillian doesn't end the headers with two \n\r pairs as
2175     // it should, so we do actually reach the end of the buffer
2176     // when looking for headers above.  If we're compiling with
2177     // TRILLIAN support, skip this check, even though it potentially
2178     // confuses the header parsing with the user message.
2179
2180 #else
2181     // Badly formed buffer without two \n\r pairs at the end of the headers.
2182     if (!scan || scan[0] == '\0')
2183         return len;
2184 #endif
2185
2186     // Look for the invite / accepted message....
2187
2188     for (find = 0; find < hdr_fields; find ++) {
2189         if (strcmp(pHdrs[find],
2190                    "Content-Type: text/x-msmsgsinvite; charset=UTF-8") == 0)
2191             break;
2192     }
2193     
2194     if (find == hdr_fields)
2195         return len;
2196
2197     for (find = 0; find < msg_fields; find ++) {
2198         if (strcmp(pMsgs[find],
2199                    "Invitation-Command: ACCEPT") == 0)
2200             break;
2201     }
2202
2203     if (find == msg_fields)
2204         return len;
2205
2206     // Find the IP address header in the packet
2207     for (find = 0; find < msg_fields; find ++) {
2208         if (strncmp(pMsgs[find], "IP-Address: ",
2209                     strlen("IP-Address: ")) == 0) {
2210
2211             if (sscanf(pMsgs[find], "IP-Address: %d.%d.%d.%d",
2212                        &ip[0], &ip[1], &ip[2], &ip[3]) != 4) {
2213                 write_log(log_file, "MSN DCC: Badly formed IP Address - dodo mode");
2214                 return len;
2215             }
2216             
2217             break;
2218         }
2219     }
2220     
2221     if (find == msg_fields)
2222         return len;
2223     
2224     // Find the IP address header in the packet
2225     for (find = 0; find < msg_fields; find ++) {
2226         if (strncmp(pMsgs[find], "Port: ",
2227                     strlen("Port: ")) == 0) {
2228             
2229             if (sscanf(pMsgs[find], "Port: %d",
2230                        &port) != 1) {
2231                 write_log(log_file, "MSN DCC: Badly formed IP port specifier - dodo mode");
2232                 return len;
2233             }
2234             
2235             break;
2236         }
2237     }
2238     
2239     if (find == msg_fields)
2240         return len;
2241     
2242     // Find the AuthCookie in the packet
2243     for (find = 0; find < msg_fields; find ++) {
2244         if (strncmp(pMsgs[find], "AuthCookie: ",
2245                     strlen("AuthCookie: ")) == 0) {
2246
2247             if (sscanf(pMsgs[find], "AuthCookie: %d",
2248                        &cookie) != 1) {
2249                 write_log(log_file, "MSN DCC: no cookie found - dodo mode");
2250                 return len;
2251             }
2252             
2253             break;
2254         }
2255     }
2256     
2257     if (find == msg_fields)
2258         return len;
2259     
2260     // Read the source IP for the client connection.
2261     // We use this for extra sanity checks in locating the client IP in
2262     // the setup packet
2263     salen = sizeof(struct sockaddr_in);
2264     if (getpeername(pt->sockets[TS_CLIENT], (struct sockaddr*) &src_addr, &salen) == -1) {
2265         return len;
2266     }
2267     
2268     sscanf(inet_ntoa(src_addr.sin_addr), "%d.%d.%d.%d",
2269            &src_ip[0], &src_ip[1], &src_ip[2], &src_ip[3]);
2270     
2271     if ((ip[0] != src_ip[0]) || (ip[1] != src_ip[1]) ||
2272         (ip[2] != src_ip[2]) || (ip[3] != src_ip[3])) {
2273 #if LOOSE_CLIENT_IP
2274         // If strict checking is on, just note the discrepency...
2275         write_log(log_file, "MSN Loose DCC Source. Expecting %d.%d.%d.%d, found %d.%d.%d.%d. Continuing mangle.", 
2276                   src_ip[0], src_ip[1], src_ip[2], src_ip[3],
2277                   ip[0], ip[1], ip[2], ip[3]);
2278 #else
2279         // If strict checking is on, complain and don't mangle.
2280         write_log(log_file, "MSN Loose DCC Source. Expecting %d.%d.%d.%d, found %d.%d.%d.%d. Not overwriting.", 
2281                   src_ip[0], src_ip[1], src_ip[2], src_ip[3],
2282                   ip[0], ip[1], ip[2], ip[3]);
2283         return len;
2284 #endif
2285     }
2286     
2287     // Okay.  Now to determine which address to overwrite the client IP with...
2288     if (outside_ip == NULL) {
2289             
2290         // Make a best guess here because we weren't told....
2291         struct sockaddr_in svr_addr;
2292         
2293         // Read the source address of the server connection...
2294         salen = sizeof(struct sockaddr_in);
2295         if (getsockname(pt->sockets[TS_SERVER], (struct sockaddr*) &svr_addr, &salen) == -1) {
2296             write_log(log_file, "MSN Found a DC setup, but couldn't work out the external IP - dodo mode");
2297             return len;
2298         }
2299         
2300         sscanf(inet_ntoa(svr_addr.sin_addr), "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
2301         
2302     } else {
2303         sscanf(outside_ip, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
2304     }
2305     
2306 #if USE_DYNAMIC_DCC
2307     lt = create_listener_between(INC_MIN, INC_MAX, net_open_msnrx);
2308     // Couldn't create onward, so can't mangle this request.
2309     if (!lt)
2310       return len;
2311     
2312     // Setup as a 1 shot with a 30 second limit.
2313     lt->oneshot = 1;
2314     gettimeofday(&tv_now, NULL);
2315     lt->timeout = tv_now.tv_sec + INC_TIMEOUT;
2316     
2317     dcc_port = lt->port;
2318 #else
2319     dcc_port = MSNRX;
2320 #endif
2321
2322     // Create the new packet, now we have all the data.
2323     
2324     write_log(log_file, "MSN DCC Setup IP Changed...%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d",
2325               src_ip[0], src_ip[1], src_ip[2], src_ip[3], port,
2326               ip[0], ip[1], ip[2], ip[3], dcc_port);
2327     
2328     // copy over the headers
2329     for (find = 0, scan = buff, len = 0; find < hdr_fields; find++) {
2330         
2331         sprintf(scan, "%s\r\n", pHdrs[find]);
2332         scan = &scan[(strlen(pHdrs[find]) + 2)];
2333         len += (strlen(pHdrs[find]) + 2);
2334     }
2335     
2336     sprintf(scan, "\r\n");
2337     scan = &scan[2];
2338     len += 2;
2339     
2340     // Copy over and mangle as required the msg fields
2341     for (find = 0; find < msg_fields; find ++) {
2342         
2343         int done = 0;
2344         
2345         if (strncmp(pMsgs[find], "IP-Address: ",
2346                     strlen("IP-Address: ")) == 0) {
2347             
2348             sprintf(tmpbuf, "IP-Address: %d.%d.%d.%d",
2349                     ip[0], ip[1], ip[2], ip[3]);
2350             
2351             sprintf(scan, "%s\r\n", tmpbuf);
2352             scan = &scan[(strlen(tmpbuf) + 2)];
2353             len += (strlen(tmpbuf) + 2);
2354             done = 1;
2355             
2356         } else if (strncmp(pMsgs[find], "Port: ",
2357                     strlen("Port: ")) == 0) {
2358             
2359             sprintf(tmpbuf, "Port: %d", dcc_port);
2360             
2361             sprintf(scan, "%s\r\n", tmpbuf);
2362             scan = &scan[(strlen(tmpbuf) + 2)];
2363             len += (strlen(tmpbuf) + 2);
2364             done = 1;
2365             
2366         }
2367         
2368         if (!done) {
2369             // Just copy over the field unchanged
2370             sprintf(scan, "%s\r\n", pMsgs[find]);
2371             scan = &scan[(strlen(pMsgs[find]) + 2)];
2372             len += (strlen(pMsgs[find]) + 2);
2373             
2374         }
2375     }
2376
2377     // Finish off the command building
2378     sprintf(scan, "\r\n");
2379     scan = &scan[2];
2380     len += 2;
2381     
2382     // Allocate a pending_dc_struct here.
2383     pdc = calloc(sizeof(pending_dc_struct), 1);
2384     if (!pdc) {
2385       // Damn.  Ran out of RAM.  All hell is about to break loose.
2386       // There won't be a direct connect struct for this DCC, so
2387       // the DCC will fail, but it should only fail with an error
2388       // in the net_open_msnrx procedure.
2389       return len;
2390     }
2391     
2392     pdc->orig_port  = port;
2393     pdc->port       = dcc_port;
2394     
2395     // Copy the original source address information into the DC struct
2396     // We need this to establish the back connection.
2397     memcpy(&pdc->src, &src_addr, sizeof(src_addr));
2398     
2399     // Add to pending DC list
2400     pdc->next    = dc_list.next;
2401     dc_list.next = pdc;
2402     
2403     return len;
2404 }
2405
2406 /*
2407  * Read in a filter configuration / control file
2408  *
2409  * Also dynamic link any modules when I get that far...
2410  *
2411  * For now, just do it statically.
2412  */
2413 void setup_filters(const char *ini_file)
2414 {
2415     // AIM FILTERS
2416     memset(&oscar_tx, 0, sizeof(oscar_tx));
2417 #if USE_DYNAMIC_DCC
2418     oscar_tx.proc[0] = fp_oscar_tx;                    // LAN client to AIM filter
2419 #else
2420     oscar_tx.proc[0] = fp_oscar_tx;                    // LAN client to AIM filter
2421 #endif
2422
2423     memset(&oscar_rx, 0, sizeof(oscar_rx));
2424
2425     //share_tx;   // LAN to Remote filter
2426     memset(&share_tx, 0, sizeof(share_tx));
2427
2428     //share_rx;   // Remote to LAN filter
2429     memset(&share_rx, 0, sizeof(share_rx));
2430
2431     // MSN FILTERS
2432     memset(&msn_tx, 0, sizeof(msn_tx));
2433     msn_tx.proc[0] = fp_msn_tx_dcc_setup;  // LAN client to MSG filter
2434
2435     //msn_rx;
2436     memset(&msn_rx, 0, sizeof(msn_rx));
2437
2438     //msnrx_tx;   // MSN file xfer things
2439     memset(&msnrx_tx, 0, sizeof(msnrx_tx));
2440
2441     //msnrx_rx;   
2442     memset(&msnrx_rx, 0, sizeof(msnrx_rx));
2443 }
2444
2445 /*-------------------------------------------------------------------------
2446  * Open a new listen socket, and attach a track struct to the
2447  * linked list of tracking structures.
2448  *
2449  * Return NULL on failure, or the newly allocated and added
2450  * track struct on success.
2451  *-----------------------------------------------------------------------*/
2452 listen_track_struct* create_listener_on(int port, listen_proc lp)
2453 {
2454   listen_track_struct *lt;
2455   
2456   // Allocate a new track structure if possible.
2457   lt = malloc(sizeof(listen_track_struct));
2458   if (!lt)
2459     return NULL;
2460   memset(lt, 0, sizeof(listen_track_struct));
2461   
2462   lt->proc = lp;
2463   lt->port = port;
2464   lt->socket = net_listen(port, "0.0.0.0");
2465   if (lt->socket == -1) {
2466     free(lt);
2467     return NULL;
2468   }
2469   
2470   // Add to the tracked socket list.
2471   lt->next = lt_list.next;
2472   lt_list.next = lt;
2473   
2474   return lt;
2475 }
2476
2477 /*-------------------------------------------------------------------------
2478  * Open a new listen socket, and attach a track struct to the
2479  * linked list of tracking structures.
2480  *
2481  * Return NULL on failure, or the newly allocated and added
2482  * track struct on success.
2483  *
2484  * This call searches the specified port range for an open port to use.
2485  * The port allocated is returned in the listen_track_struct for the
2486  * caller.
2487  *-----------------------------------------------------------------------*/
2488 listen_track_struct* create_listener_between(int port_min, int port_max, listen_proc lp)
2489 {
2490   listen_track_struct *lt;
2491   
2492   // Allocate a new track structure if possible.
2493   lt = malloc(sizeof(listen_track_struct));
2494   if (!lt)
2495     return NULL;
2496   memset(lt, 0, sizeof(listen_track_struct));
2497   
2498   lt->oneshot = 1;
2499   lt->proc = lp;
2500   lt->socket = net_listen_between(port_min, port_max, "0.0.0.0", &lt->port);
2501   if (lt->socket == -1) {
2502     free(lt);
2503     return NULL;
2504   }
2505   
2506   // Add to the tracked socket list.
2507   lt->next = lt_list.next;
2508   lt_list.next = lt;
2509   
2510   return lt;
2511 }
2512
2513 /*
2514  * Read in a filter configuration / control file
2515  *
2516  * Also dynamic link any modules when I get that far...
2517  *
2518  * For now, just do it statically.
2519  */
2520 int setup_listenners(const char *ini_file)
2521 {
2522   int n_lt;
2523   listen_track_struct *lt;
2524   
2525   //
2526   // Interception for data heading out to external hosts.
2527   //
2528   // These procedures attach the appropriate filtering
2529   // routines for that type of connection.
2530   //
2531
2532   if (enable_msn) {
2533     create_listener_on(MSN,     net_open_msn);
2534 #if USE_DYNAMIC_DCC
2535     // Log invalid attempts
2536     create_listener_on(MSNRX,   net_open_log_attempt);
2537 #else
2538     create_listener_on(MSNRX,   net_open_msnrx);
2539 #endif
2540   } else {
2541     write_log(log_file, "[STARTUP] Support for MSN is disabled");
2542   }
2543   
2544   if (enable_aim) {
2545     create_listener_on(OSCAR,   net_open_aim_oscar);
2546 #if USE_DYNAMIC_DCC
2547     // Log invalid shares
2548     create_listener_on(SHARE,   net_open_log_attempt);
2549     // Some AIM clients are buggy, so watch for that
2550     create_listener_on(DCC,     net_open_buggy_aim_dcc);
2551 #else
2552     create_listener_on(SHARE,   net_open_aim);
2553     create_listener_on(DCC,     net_open_aim);
2554 #endif
2555   } else {
2556     write_log(log_file, "[STARTUP] Support for AIM is disabled");
2557   }
2558
2559   // Count listen_track_struct
2560   n_lt = 0;
2561   lt = lt_list.next;
2562   while(lt != NULL) {
2563     n_lt ++;
2564     lt = lt->next;
2565   }
2566   
2567   return n_lt;
2568 }
2569
2570 void close_listenners(const char *ini_file)
2571 {
2572     listen_track_struct *lt;
2573     
2574     // Run around the listenners list and free any listenners
2575     while (lt_list.next) {
2576
2577       lt = lt_list.next;
2578       lt_list.next = lt->next;
2579
2580       close(lt->socket);
2581       free(lt);
2582     }
2583 }
2584
2585 /* HUP Signal Handler */
2586 void sig_hup(int i)
2587 {
2588   pending_hup = 1;
2589 }
2590
2591 /* Setup as a demon.  Parent process is terminated */
2592 void demonize()
2593 {
2594     pid_t pid;
2595     int sockets, max_sockets;
2596
2597     /* Fork and close the parent */
2598     pid = fork();
2599     
2600     /* Parent has pid of child.  Child has pid == 0 */
2601     if (pid != 0) {
2602       _exit(0); // close the parent
2603     }
2604     
2605     // Setup as a process leader...
2606     setsid();
2607     
2608     /* Fork and close the process leader */
2609     pid = fork();
2610
2611     /* Parent has pid of child.  Child has pid == 0 */
2612     if (pid != 0) {
2613       _exit(0); // close the parent
2614     }
2615     
2616     /* Change to root directory */
2617     chdir("/");
2618
2619     /* Close any open sockets.  Including stdout/stderr/stdin.
2620      * Perhaps I should reopen 0/1/2, but ReAIM doesn't use them
2621      */
2622     max_sockets = sysconf(_SC_OPEN_MAX);
2623     for (sockets = 0; sockets < max_sockets; sockets ++)
2624       close(sockets);
2625 }
2626
2627 void usage()
2628 {
2629   printf("Usage: reaim [-h] [-m] [-a] [-e <ip>] [-l log] [-d]\n"
2630          "\n"
2631          "  -h | --help                   : Show this text.\n"
2632          "  -m | --disable-msn            : Disable MSN support.\n"
2633          "  -a | --disable-aim            : Disable AIM support.\n"
2634          "  -e <ip> | --external-ip <ip>  : Manually set the override ip address.\n"
2635          "  -l <log> | --logfile <log>    : Set logfile location.\n"
2636          "                                    Default: %s\n"
2637          "  -d                            : Do not fork into the background.\n",
2638          LOG_FILE);
2639 }
2640
2641 int parse_options(int argc, char * argv[])
2642 {
2643 // BRCM begin      
2644   int option_index = 0, lose = 0;
2645 // BRCM end 
2646   int c;
2647   
2648   while (1) {
2649     
2650     c = getopt_long(argc, argv, "mae:hl:d",
2651                     long_options, &option_index);
2652     
2653     if (c == -1)
2654       break;
2655     
2656     switch(c) {
2657     case 'm':
2658       enable_msn = 0;
2659       break;
2660     case 'a':
2661       enable_aim = 0;
2662       break;
2663     case 'e':
2664       outside_ip = strdup(optarg);
2665       break;
2666     case 'h':
2667       usage();
2668       return 0;
2669       break;
2670     case 'l':
2671 // BRCM begin      
2672       enable_log = 1;
2673       if (strlen(optarg) > 0) 
2674          log_file = strdup(optarg);
2675 // BRCM end      
2676       break;
2677     case 'd':
2678       enable_fork = 0;
2679       break;
2680     default:
2681       lose = 1;
2682       break;
2683     }
2684   }
2685
2686 // BRCM begin      
2687   if (lose || optind < argc) {
2688      usage();
2689      return 0;
2690   }     
2691 // BRCM end      
2692   
2693   return 1;
2694 }
2695
2696 #ifdef BUILD_STATIC
2697 int reaim_main(int argc, char *argv[])
2698 #else
2699 int main(int argc, char *argv[])
2700 #endif
2701 {
2702     fd_set rfds, efds, wfds;
2703     struct timeval tv_sel, tv_now;
2704     int sv;
2705     struct sigaction set_act, old_act;
2706     proxy_track_struct *pt, *prev_pt;
2707     listen_track_struct *lt, *plt;
2708     pending_connect_struct *pc;
2709     int max_fd, sock;
2710     pending_dc_struct *pdc, *prev_pdc;
2711 #if PERIODIC_LOG
2712     struct timeval tv_stats;
2713     tv_stats.tv_sec = 0;
2714 #endif
2715     
2716     if (!parse_options(argc, argv))
2717       exit(-5);
2718     
2719     if (write_log(log_file,
2720                   "[STARTUP] Started AIM-Fix Proxy [%s%s]",
2721                   REAIM_VERSION, PLATFORM) == 0) {
2722 //BRCM begin        
2723 #if 0
2724       if (enable_fork) {
2725         fprintf(stderr,
2726                 "[STARTUP] Started AIM-Fix Proxy [%s%s]\n"
2727                 "[WARNING] Unable to write log to %s.\n"
2728                 "[WARNING] Proxy will continue, but logging will not work.\n",
2729                 REAIM_VERSION, PLATFORM, log_file);
2730       } else {
2731         // In the case of invalid log file but not forking, write_log
2732         // writes to stderr
2733         write_log(log_file,
2734                   "[WARNING] Unable to write log to %s.\n", log_file);
2735         write_log(log_file,
2736                   "[WARNING] Proxy will run, but logging will not work.\n");
2737       }
2738 #endif      
2739 //BRCM end        
2740     };
2741     
2742     if (enable_fork)
2743       demonize();
2744     
2745     /* Setup the action table for SIGPIPE - ignore. */
2746     memset(&set_act,0,sizeof(set_act));
2747     set_act.sa_handler  = SIG_IGN;
2748     sigemptyset(&set_act.sa_mask);
2749     set_act.sa_flags    = 0;
2750     sigaction(SIGPIPE, &set_act, &old_act);
2751     
2752     /* Setup the action table for SIGHUP - rebind the listenning sockets. */
2753     memset(&set_act,0,sizeof(set_act));
2754     set_act.sa_handler  = sig_hup;
2755     sigemptyset(&set_act.sa_mask);
2756     set_act.sa_flags    = 0;
2757     sigaction(SIGHUP, &set_act, &old_act);
2758
2759     if (outside_ip)
2760       write_log(log_file, "[STARTUP] Using %s for the external IP address.", outside_ip);
2761     else
2762       write_log(log_file, "[STARTUP] Auto-detecting the external IP address.");
2763     
2764     setup_filters("");
2765     
2766     if (setup_listenners("") == 0) {
2767       write_log(log_file, "[WARNING] Not listenning on any sockets.");
2768       write_log(log_file, "[WARNING] Already running / misconfigured ?");
2769     }
2770     
2771     // - Wait for connections to the redirected port
2772     // - Setup the onward connection to listen
2773     // - Make onward connection to source
2774     // - Push around any packets
2775     
2776     while(1) {
2777
2778       // Check for HUP...
2779       if (pending_hup) {
2780         write_log(log_file, "[SIGNAL] SIGHUP received.  Rebinding listenning sockets.");
2781         close_listenners("");
2782         setup_listenners("");
2783         pending_hup = 0;
2784       }
2785       
2786       // Setup the list of sockets we are monitoring
2787       FD_ZERO(&rfds);
2788       FD_ZERO(&efds);
2789       FD_ZERO(&wfds);
2790       
2791       max_fd = 0;
2792       
2793       // Get the current time
2794       gettimeofday(&tv_now, NULL);
2795       
2796 #if PERIODIC_LOG
2797       // Periodic stats.
2798       // 1 line every 5 minutes.
2799       // Useful for finding leaks in the list handling.
2800       if (tv_stats.tv_sec < tv_now.tv_sec) {
2801         periodic_log();
2802         tv_stats.tv_sec = tv_now.tv_sec + 60*5;
2803       }
2804 #endif
2805
2806
2807       // Process the listen_track list.
2808       // - Timeout processing
2809       // - Cleanup processing
2810       // - Add any listenners to the socket list.
2811       plt = &lt_list;
2812       lt = lt_list.next;
2813       while(lt != NULL) {
2814         
2815         if ((lt->timeout != 0) && (lt->timeout < tv_now.tv_sec)) {
2816           write_log(log_file, "[TIMEOUT] Listen on proxy:%d timed out.", lt->port);
2817           lt->cleanup = 1;
2818         }
2819         
2820         if (lt->cleanup) {
2821           
2822           plt->next = lt->next;
2823           
2824           close(lt->socket);
2825           
2826           // As we just stopped listening to lt->port, kill any
2827           // pending connects for that port too.
2828           pdc = dc_list.next;
2829           while(pdc) {
2830             if (pdc->port == lt->port)
2831               pdc->cleanup = 1;
2832             
2833             pdc = pdc->next;
2834           }
2835           
2836           free(lt);
2837           
2838         } else {
2839           
2840           if (lt->socket > max_fd)
2841             max_fd = lt->socket;
2842           
2843           FD_SET(lt->socket, &rfds);
2844           
2845           plt = lt;
2846         }
2847         
2848         // Advance loop
2849         lt = plt->next;
2850       }
2851       
2852       // Cleanup any pending_dc_list entries that are flagged for cleanup
2853       prev_pdc = &dc_list;
2854       pdc = dc_list.next;
2855       while(pdc) {
2856         if (pdc->cleanup) {
2857           pending_dc_struct *next_dc;
2858           
2859           prev_pdc->next = pdc->next;
2860
2861           next_dc = pdc->next;
2862           free(pdc);
2863           pdc = next_dc;
2864         } else {
2865           prev_pdc = pdc;
2866           pdc = pdc->next;
2867         }
2868       }
2869       
2870         pt = pt_list.next;
2871         prev_pt = &pt_list;
2872         while(pt != NULL) {
2873
2874             // Cleanup any proxy connections that are flagged...
2875             if (pt->cleanup) {
2876
2877                 proxy_track_struct *clean_pt = pt;
2878                 
2879                 write_log(log_file, "[Cleanup] proxy_track_struct [magic=%d] [user=%d]",
2880                           pt->magic, pt->user);
2881
2882                 // Adjust the linked list
2883                 prev_pt->next = pt->next;
2884                 pt = pt->next;
2885
2886                 // Clean up the proxy track structure data
2887                 
2888                 if (clean_pt->data_buff[0])
2889                     free(clean_pt->data_buff[0]);
2890
2891                 if (clean_pt->data_buff[1])
2892                     free(clean_pt->data_buff[1]);
2893
2894                 if (clean_pt->sockets[0] != -1)
2895                     close(clean_pt->sockets[0]);
2896                 if (clean_pt->sockets[1] != -1)
2897                     close(clean_pt->sockets[1]);
2898
2899                 // If it's the user-associated socket, zap the user
2900                 if (clean_pt->user == 1) {
2901
2902                     user_track_struct *user_ut = user_list.next;
2903
2904                     while(user_ut) {
2905                         if (user_ut->magic == clean_pt->magic)
2906                             user_ut->cleanup = 1;
2907                         
2908                         user_ut = user_ut->next;
2909                     }
2910                 }
2911                 
2912                 free(clean_pt);
2913                 
2914                 continue;
2915             }
2916
2917             // Add the sockets to the read/write selection arrays
2918             // as appropriate.
2919             for (sock = 0; sock < 2; sock ++) {
2920
2921                 if (pt->sockets[sock] != -1) {
2922                     FD_SET(pt->sockets[sock], &rfds);
2923                     
2924                     if (pt->data_len[sock] > 0)
2925                         FD_SET(pt->sockets[sock], &wfds);
2926                     
2927                     if (pt->sockets[sock] > max_fd)
2928                         max_fd = pt->sockets[sock];
2929                 }
2930             }
2931
2932             prev_pt = pt;
2933             pt = pt->next;
2934         }
2935         
2936         // Add any pending connection sockets to the write check
2937
2938         pc = &pc_list;
2939         while(pc->next) {
2940           if (pc->next->socket == -1) {
2941
2942             // Free the finished up socket
2943             pending_connect_struct *pct;
2944
2945             pct = pc->next;
2946             pc->next = pct->next;
2947             free(pct);
2948
2949           } else {
2950
2951             // Check for a timeout.
2952             if (pc->next->timeout < tv_now.tv_sec) {
2953
2954               char *tmpstr;
2955               tmpstr = strdup(inet_ntoa(pc->next->src.sin_addr));
2956               write_log(log_file, "[CONN_NB] Connection [%s:%d -> %s:%d via proxy] failed "
2957                         "[timeout reached] (%d %d)",
2958                         tmpstr,                      ntohs(pc->next->src.sin_port),
2959                         inet_ntoa(pc->next->dst.sin_addr), ntohs(pc->next->dst.sin_port),
2960                         pc->next->client_sock, pc->next->socket);
2961               free(tmpstr);
2962               
2963               close(pc->next->socket);
2964               close(pc->next->client_sock);
2965               pc->next->client_sock = -1;
2966               pc->next->socket = -1;
2967
2968             } else {
2969               
2970               // Add the socket
2971               FD_SET(pc->next->socket, &wfds);
2972               if (pc->next->socket > max_fd)
2973                 max_fd = pc->next->socket;
2974             }
2975             
2976             pc = pc->next;
2977           }
2978         }
2979         
2980         // Wait for some activity
2981         tv_sel.tv_usec = 0;
2982         tv_sel.tv_sec  = 1;
2983         
2984         sv = select(max_fd+1,&rfds,&wfds,&efds,&tv_sel);
2985         switch(sv) {
2986           
2987         case -1:
2988             /* Some socket error, maybe */
2989             if (errno != EINTR) {
2990                 perror("[FATAL] Server socket died: ");
2991                 exit(1);
2992             }
2993             break;
2994         case 0:
2995             // Just timed out with nothing going on.
2996             break;
2997             
2998         default:
2999             
3000             // Process listenners...
3001             lt = lt_list.next;
3002             while(lt != NULL) {
3003               
3004               if ((lt->socket != -1) &&
3005                   (FD_ISSET(lt->socket, &rfds))) {
3006                 lt->proc(lt);
3007                 if (lt->oneshot)
3008                   lt->cleanup = 1;
3009               }
3010               
3011               lt = lt->next;
3012             }
3013             
3014             // Check pending connection sockets
3015             pc = &pc_list;
3016             while(pc->next) {
3017               if (pc->next->socket != -1) {
3018                 
3019                 if (FD_ISSET(pc->next->socket, &wfds)) {
3020                   pc->next->proc(pc->next);
3021                 }
3022               }
3023               
3024               pc = pc->next;
3025             }
3026             
3027             // Check generic proxied port pairs
3028             pt = pt_list.next;
3029             while(pt) {
3030
3031                 for (sock = 0; sock < 2; sock ++) {
3032                     
3033                     // On Write list ?  We must have pending data for it...
3034                     if ((pt->sockets[sock] != -1) &&
3035                         (pt->cleanup == 0) &&
3036                         FD_ISSET(pt->sockets[sock], &wfds)) {
3037                         
3038                         int txs;
3039                         
3040                         txs = write(pt->sockets[sock],
3041                                     &pt->data_buff[sock][pt->data_offset[sock]],
3042                                     pt->data_len[sock]);
3043                         if (txs < 0) {
3044                             if ((errno != EINTR) && (errno != EAGAIN)) {
3045                                 write_log(log_file, "Socket write failure! cleaning up!");
3046                                 pt->cleanup = 1;
3047                             }
3048                         } else {
3049                             pt->data_len[sock] -= txs;
3050                             if (pt->data_len[sock] == 0)
3051                                 pt->data_offset[sock] = 0;
3052                             else
3053                                 pt->data_offset[sock] += txs;
3054                         }
3055                     }
3056                     
3057                     // On read list, we have data for the other half...
3058                     //
3059                     // We only read it if the other half's write buffer is
3060                     // completely empty.
3061                     //
3062                     if ((pt->sockets[sock] != -1) &&
3063                         (pt->cleanup == 0) &&
3064                         FD_ISSET(pt->sockets[sock], &rfds) &&
3065                         (pt->data_len[sock ^ 1] == 0)) {
3066                         
3067                         int rxs;
3068
3069                         // Read into the other half's data buffer.
3070                         rxs = read(pt->sockets[sock],
3071                                    pt->data_buff[sock^1],
3072                                    pt->data_max[sock^1]);
3073                         if (rxs == -1) {
3074                             if (errno == EAGAIN)
3075                                 write_log(log_file, "FOOIE! FD_ISSET, but read() returned EAGAIN [%d]!",
3076                                           pt->sockets[sock]);
3077                             if ((errno != EINTR) && (errno != EAGAIN)) {
3078                                 pt->cleanup = 1;
3079                             }
3080                         }
3081                         
3082                         if (rxs == 0) {
3083                             write_log(log_file, "socket closed.  cleaning up.....");
3084                             pt->cleanup = 1;
3085                         }
3086                         
3087                         if (rxs > 0) {
3088                             
3089                             pt->data_len[sock^1] =
3090                                 fp_process(pt->data_buff[sock^1],
3091                                            rxs,
3092                                            pt->data_max[sock^1],
3093                                            pt->filter[sock],
3094                                            pt);
3095                         }
3096                     }
3097                     
3098                 } // End of for(sock...)
3099                 
3100                 pt = pt->next;
3101                 
3102             } // End of while(pt)
3103
3104             break;
3105         } // End of switch(sv)
3106         
3107     } // End of while(1)
3108     
3109     return 0;
3110 }