6 * Homepage: http://reaim.sourceforge.net/
8 * Copyright: Mark Cooke, November 2001. All Rights Reserved.
10 * License: GNU General Public License, Version 2.
12 * CVS Data: $Id: reaim.c,v 1.30 2003/03/25 12:35:31 mark-c Exp $
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.
19 * It also has a filter module for MSN Messenger file transfer support.
21 * It accepts transparently redirected port 5190 (AIM server communications)
22 * traffic, and transparently forwards this to the usual destination with one
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
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.
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.
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.
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.
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.
56 * reaim [optional dotted quad for routable IP]
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).
68 * Example usage where eth0 is LAN, ppp0 is internet:
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
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
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
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
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
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
90 * Detailed AIM Manglement Notes:
92 * The proxy keeps three lists of connections (socket pairs).
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).
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.
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.
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.
116 * Connections to port 5566 are handled virtually identically.
118 * DC Setup Packet Format:
120 * With many thanks to the people working on the reverse engineering of
121 * the AIM OSCAR protocol.
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.
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.
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.
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!
145 * No warranty. Patches, bug reports, success stories, and other contributions
149 /* NOTE: NetBSD patch provided by David Vyskocil. Thanks!!!
151 * Compile with USE_IPF defined for NetBSD/IPF support.
154 /* NetBSD proxy redirect(ipnat) and firewall(ipf) setup
156 * assuming 'ne0' is the LAN device name and 'tun0' the internet connection
158 * /etc/ipnat.conf rules... (redirect for transparent proxying)
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
163 * /etc/ipf.conf rules... (firewall/logger)
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
178 #include <sys/time.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>
195 #include <sys/ioctl.h>
199 // Command line options
203 static struct option long_options[] = {
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' },
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"
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"
231 #define REAIM_VERSION "0.8 pre"
237 #define MSN 1863 // Where we listen for client messages
238 #define MSNRX 1864 // Where we listen for MSN DCCs
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
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
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
266 // This defines the size of the buffers used when proxying
267 // connections. Each proxied connection uses 2 of these
269 #define PROXY_BUFFER_SIZE 4096
272 #define LOG_FILE "/var/log/reaim.log"
275 char *log_file = LOG_FILE;
277 // Filter group IDs - needed for stateful storage access
282 // Set to 1 to enable additional logging for debugging purposes
283 #define VERBOSE_LOGGING 0
285 // Timeout for making onward connections
286 #define CONNECT_TIMEOUT 10
288 // Maximum number of filters on each open socket.
289 // TODO: remove this coded limit
290 #define MAX_FILTERS 4
292 // Logging routine. Borrowed from the squirm proxy.
293 int write_log(const char *logfile, const char *format, ...);
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;
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
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);
316 typedef void (listen_proc)(listen_track_struct *lt);
318 typedef void (connect_proc)(pending_connect_struct *pc);
321 struct _filter_chain {
322 filter_proc *proc[MAX_FILTERS]; // Procedures for filtering
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
332 * Generic proxied socket handler.
335 struct _proxy_track_struct {
336 proxy_track_struct *next; // Next proxy connection in linked list.
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.
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
351 struct _user_track_struct {
352 user_track_struct *next; // Next entry in the list
354 unsigned int magic; // Magic connection tracking number
355 unsigned int cleanup; // Set to 1 to clean up this entry
357 unsigned char *msg; // Connection setup message
358 unsigned char *user; // Screen name of the user
361 struct _pending_dc_struct {
363 pending_dc_struct *next; // Next pending connection
365 unsigned int cleanup; // Set to 1 to clean up this entry
367 unsigned short port; // Port we're listenning on.
368 unsigned short orig_port;// Original port the client was on.
370 unsigned int magic; // The user_track_struct magic number
371 unsigned char id[8]; // The DC setup message we're waiting on
373 struct sockaddr_in src; // Original Client Source address
376 struct _listen_track_struct {
378 listen_track_struct *next; // Next listenning socket
379 listen_proc *proc; // Procedure to call
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)
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
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...
420 /*===========================================================================*/
421 // The linked lists used to track state
422 /*===========================================================================*/
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
430 unsigned int ts_magic = 1; // Next free magic number
432 char * outside_ip = NULL;
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
443 static int pending_hup = 0; // Not zero if a HUP was received.
445 listen_track_struct* create_listener_between(int port_min, int port_max, listen_proc lp);
447 /*===========================================================================*/
453 * We use IP Filter on NetBSD to track original destination
455 * Descriptions: use ioctl for /dev/ipnat to extract original destination
457 * Arguments: (socket file descriptor,
458 * current destination address,
460 * Side Effects: replace sa to original destination
461 * Return Value: 0 (success) or -1 (failure)
464 get_realip_from_ipf(fd, sa, salen)
470 struct sockaddr_in sin, sloc;
471 struct sockaddr_in *sinp;
473 natlookup_t *natlookp = &natlook;
476 * get IP# and port # of the remote end of the connection (at the
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));
486 * get IP# and port # of the local end of the connection (at the
487 * man-in-the-middle).
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));
496 * Build up the NAT natlookup structure.
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;
505 * Open the NAT device and lookup the mapping pair.
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));
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));
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;
529 /*===========================================================================*
530 * int gettranssockname(int fd, struct sockaddr *sa, socklen_t *salen)
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
535 *===========================================================================*/
537 int gettranssockname(int fd, struct sockaddr *sa, socklen_t *salen)
539 if (*salen != sizeof(struct sockaddr_in)) {
544 // Try to ask for the original destination...
546 if (!get_realip_from_ipf(fd, sa, salen))
549 if (!getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, sa, salen))
553 // We have to explode if we can't read it back.
557 /*===========================================================================*
558 * void dump_packet(const char *buff, int len)
560 * Print out the contents of the packet.
561 *===========================================================================*/
562 void dump_packet(const char *buff, int len)
564 char dump_start[32768], *dump_buff = dump_start;
567 for (i = 0; i < len; i ++) {
570 sprintf(dump_buff, "%.4X ", i);
574 sprintf(dump_buff, "%02x ", (unsigned int) buff[i] & 0xff);
577 if ((i % 16) == 15) {
579 sprintf(dump_buff, " ");
582 for (j = -15; j < 1; j++) {
583 if (isalnum(buff[i+j]))
584 *dump_buff = buff[i+j];
597 write_log(log_file, "Packet Dump:\n%s", dump_start);
601 /*===========================================================================*
602 * void dump_packet(const char *buff, int len)
604 * Print out the contents of the packet.
605 *===========================================================================*/
607 int write_log(const char *logfile, const char *format, ...)
612 char msg_buff[32768];
615 va_start(args, format);
617 if (vsprintf(msg_buff, format, args) > 32767)
618 strcpy(msg_buff, "[WARNING] Insufficient log buffer size");
622 current_time = time(NULL);
623 date_str = ctime(¤t_time);
626 // Only write to log file when it's enabled, otherwise write to
627 // stderr when enable_fork == 0, otherwise throw it away.
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);
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);
642 if (enable_fork == 0)
643 fprintf(stderr, "[%.*s] %s\n", (int) strlen(date_str) - 1, date_str, msg_buff);
650 /*===========================================================================*
651 * void periodic_log()
653 * Print out some stats to the reaim log periodically.
654 *===========================================================================*/
656 void periodic_log() {
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;
664 // Count listen_track_struct
672 // Count pending_dc_struct
680 // Count proxy_track_struct
688 // Count pending_connect_struct
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);
702 /*===========================================================================*
703 * int net_listen(int port, char *ifs)
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
709 * The function binds to the address specified in the ifs parameter.
710 *===========================================================================*/
712 int net_listen(int port, const char *ifs)
715 struct sockaddr_in server;
718 hSock = socket(PF_INET, SOCK_STREAM, 0);
720 write_log(log_file, "[FATAL] Could create a socket for %s:%d",
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",
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",
743 if (listen(hSock, 5) == -1) {
744 write_log(log_file, "[FATAL] Could not listen on %s:%d",
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",
761 /*===========================================================================*
762 * int net_listen_between(int port_min, int port_max)
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.
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)
774 struct sockaddr_in server;
777 hSock = socket(PF_INET, SOCK_STREAM, 0);
779 write_log(log_file, "[FATAL] Could create a socket for %s:%d",
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",
792 server.sin_family = AF_INET;
793 server.sin_addr.s_addr = inet_addr(ifs);
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)
804 write_log(log_file, "[FATAL] Could not create listening socket on %s:%d-%d",
805 ifs, port_min, port_max);
810 if (listen(hSock, 5) == -1) {
811 write_log(log_file, "[FATAL] Could not listen on %s:%d",
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",
825 // Inform caller of the port we bound to.
832 /*===========================================================================*
833 * int net_connect_to(int port, const char *ifs)
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.
839 * DEPRECIATED: This function can block. Should be using either
840 * net_connect_outbound_nb or net_connect_inbound_nb
841 *===========================================================================*/
843 int net_connect_to(int port, const char *ifs)
846 struct sockaddr_in server;
849 hSock = socket(PF_INET, SOCK_STREAM, 0);
851 write_log(log_file, "Connection [%s:%d] failed [create]: %s [%d]",
852 ifs, port, strerror(errno), errno);
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);
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);
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);
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);
895 /*-------------------------------------------------------------------------
896 void* net_open_connection(int hSock)
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.
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)
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);
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);
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);
939 /*-------------------------------------------------------------------------
940 filter_state* find_state(proxy_track_struct *pts,
943 Search the list of filter state structures for the PTS, and return a
944 pointer to the appropriate one.
946 Return NULL if it does not exist.
947 -------------------------------------------------------------------------*/
949 filter_state *find_pts_state(proxy_track_struct *pts, unsigned int group_id)
953 scan = pts->state.next;
955 while((scan) && (scan->filter_group != group_id))
961 /*-------------------------------------------------------------------------
962 int add_pts_state(proxy_track_struct *pts,
964 filter_state *add_state)
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.
969 Return 0 if the new data was not added. 1 if it was.
970 -------------------------------------------------------------------------*/
972 int add_pts_state(proxy_track_struct *pts, unsigned int group_id, filter_state *add_state)
974 if (find_pts_state(pts, group_id))
977 add_state->next = pts->state.next;
978 pts->state.next = add_state;
983 /*-------------------------------------------------------------------------
984 filter_state* del_pts_state(proxy_track_struct *pts,
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.
990 Return NULL if there was no pts data.
991 -------------------------------------------------------------------------*/
993 filter_state * del_pts_state(proxy_track_struct *pts, unsigned int group_id)
995 filter_state *scan, *prev;
998 scan = pts->state.next;
1002 if (scan->filter_group == group_id) {
1003 prev->next = scan->next;
1014 /*-------------------------------------------------------------------------
1015 proxy_track_struct* pts_allocate()
1017 Allocate the buffers, setup counters, sizes, empty filters for a new
1018 proxy tracking structure.
1020 Return NULL if we can't allocate memory for some reason.
1021 -------------------------------------------------------------------------*/
1023 proxy_track_struct *pts_allocate()
1025 proxy_track_struct *pt;
1028 // Setup the tracking structure
1029 pt = calloc(sizeof(proxy_track_struct),1);
1031 write_log(log_file, "[WARNING] Memory allocation failed for "
1032 "proxy tracking structure.");
1039 pt->state.next = NULL;
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]);
1049 if (!pt->data_buff[sock]) {
1053 for (fs = 0; fs < sock; fs ++)
1054 free(pt->data_buff[fs]);
1057 write_log(log_file, "[WARNING] Memory allocation failed for "
1058 "proxy tracking data buffers.");
1063 pt->filter[sock] = NULL;
1069 /*-------------------------------------------------------------------------
1070 int net_connect_outbound_nb()
1072 Setup an outbound non-blocking connection attempt.
1074 Return 0 on a failure. Note that is it upto the caller to free
1075 proc_data if this function fails.
1076 -------------------------------------------------------------------------*/
1078 int net_connect_outbound_nb(listen_track_struct *lt,
1081 filter_chain *tx_filter,
1082 filter_chain *rx_filter,
1085 int new_client, new_server;
1087 pending_connect_struct *pc;
1089 struct timeval tv_now;
1091 // Allocate pending connection tracker
1092 pc = calloc(sizeof(pending_connect_struct), 1);
1097 gettimeofday(&tv_now, NULL);
1099 // Add to the pc list. This will do garbage collection
1101 pc->client_sock = -1;
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;
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) {
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);
1128 if (force_dst_port != -1) {
1129 if (force_dst_port != ntohs(pc->dst.sin_port)) {
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),
1139 pc->dst.sin_port = htons(force_dst_port);
1143 // Create the onward socket
1144 new_server = socket(PF_INET, SOCK_STREAM, 0);
1145 if (new_server == -1) {
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);
1158 // Record the socket handles in the track struct
1159 pc->socket = new_server;
1160 pc->client_sock = new_client;
1163 setsockopt(new_server, SOL_SOCKET, SO_REUSEADDR, (void*) &option, sizeof(option));
1166 setsockopt(new_server, SOL_SOCKET, SO_KEEPALIVE, (void*) &option, sizeof(option));
1168 fcntl(new_server, F_SETFL, O_NONBLOCK);
1170 if (connect(new_server, (struct sockaddr*) &pc->dst, sizeof(pc->dst)) == -1) {
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) {
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);
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);
1194 // Cleanup of the pending connect struct is done in the main loop
1198 pc->client_sock = -1;
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));
1209 // As we connected immediately, call the processing routine directly.
1215 /*-------------------------------------------------------------------------
1216 int net_connect_inbound_nb()
1218 Setup an inbound non-blocking connection attempt.
1220 Return 0 on a failure. Note that is it upto the caller to free
1221 proc_data if this function fails.
1222 -------------------------------------------------------------------------*/
1224 int net_connect_inbound_nb(listen_track_struct *lt,
1226 pending_dc_struct *pdc,
1227 filter_chain *tx_filter,
1228 filter_chain *rx_filter,
1231 int new_client, new_server;
1233 pending_connect_struct *pc;
1235 struct timeval tv_now;
1237 // We have to clean up the pdc in here.
1240 // Allocate pending connection tracker
1241 pc = calloc(sizeof(pending_connect_struct), 1);
1246 gettimeofday(&tv_now, NULL);
1248 // Add to the pc list. This will do garbage collection
1250 pc->client_sock = -1;
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;
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) {
1266 // The pdc contains the destination address / port
1268 memcpy(&pc->dst, &pdc->src, sizeof(pdc->src));
1269 pc->dst.sin_port = htons(pdc->orig_port);
1271 if (force_dst_port != -1) {
1272 if (force_dst_port != ntohs(pc->dst.sin_port)) {
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),
1282 pc->dst.sin_port = htons(force_dst_port);
1286 // Create the onward socket
1287 new_server = socket(PF_INET, SOCK_STREAM, 0);
1288 if (new_server == -1) {
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);
1301 // Record the socket handles in the track struct
1302 pc->socket = new_server;
1303 pc->client_sock = new_client;
1306 setsockopt(new_server, SOL_SOCKET, SO_REUSEADDR, (void*) &option, sizeof(option));
1309 setsockopt(new_server, SOL_SOCKET, SO_KEEPALIVE, (void*) &option, sizeof(option));
1311 fcntl(new_server, F_SETFL, O_NONBLOCK);
1313 if (connect(new_server, (struct sockaddr*) &pc->dst, sizeof(pc->dst)) == -1) {
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) {
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);
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);
1337 // Cleanup of the pending connect struct is done in the main loop
1341 pc->client_sock = -1;
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));
1352 // As we connected immediately, call the processing routine directly.
1358 /*-------------------------------------------------------------------------
1359 void* conn_open_outbound_generic(pending_connect_struct *pc)
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.
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)
1371 user_track_struct *ts;
1372 proxy_track_struct *pt;
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) {
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);
1388 close(pc->client_sock);
1391 pc->client_sock = -1;
1395 // se is non zero if the connection failed.
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);
1406 close(pc->client_sock);
1409 pc->client_sock = -1;
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;
1419 pt = pts_allocate();
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);
1432 close(pc->client_sock);
1434 pc->client_sock = -1;
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];
1443 pt->magic = ts->magic;
1445 pt->next = pt_list.next;
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);
1456 // Flag the pending connection for garbage collect without
1457 // closing the connections (which we just handed off to the
1458 // pt tracking struct)
1460 pc->client_sock = -1;
1464 /*-------------------------------------------------------------------------
1465 void* conn_open_inbound_generic(pending_connect_struct *pc)
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.
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)
1477 proxy_track_struct *pt;
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) {
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);
1493 close(pc->client_sock);
1496 pc->client_sock = -1;
1500 // se is non zero if the connection failed.
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);
1511 close(pc->client_sock);
1514 pc->client_sock = -1;
1518 pt = pts_allocate();
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);
1530 close(pc->client_sock);
1532 pc->client_sock = -1;
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];
1541 pt->next = pt_list.next;
1544 tmpstr = strdup(inet_ntoa(pc->src.sin_addr));
1545 write_log(log_file, "[CONN_BH] Connection [%s:%d -> %s:%d via proxy] established "
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);
1552 // Flag the pending connection for garbage collect without
1553 // closing the connections (which we just handed off to the
1554 // pt tracking struct)
1556 pc->client_sock = -1;
1560 /*-------------------------------------------------------------------------
1561 void net_open_aim_oscar(listen_track_struct *lt)
1563 Setup a generic open and callback pair which will attach the oscar filter
1564 if the connection is successfully established.
1566 This should only be called for connections heading out of the LAN to
1567 the off-site servers.
1568 -------------------------------------------------------------------------*/
1570 void net_open_aim_oscar(listen_track_struct *lt)
1573 net_connect_outbound_nb(lt, conn_open_outbound_generic, NULL, &oscar_tx, &oscar_rx, lt->port);
1578 /*-------------------------------------------------------------------------
1579 void net_open_log_attempt(listen_track_struct *lt)
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)
1586 struct sockaddr_in src_addr;
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)
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),
1604 /*-------------------------------------------------------------------------
1605 void net_open_aim(listen_track_struct *lt)
1607 Open the direct connection attempt from the remote party, and alloc
1608 the generic proxy_track struct.
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.
1613 A warning is logged if this isn't the case.
1615 This should only ever be called for incoming requests from offsite hosts.
1616 -------------------------------------------------------------------------*/
1617 void net_open_aim(listen_track_struct *lt)
1619 pending_dc_struct *pms, *first;
1622 // Look for a pending connection for this port
1629 if (pms->cleanup == 0) {
1631 if (pms->port == lt->port) {
1643 // Okay. All is well...
1645 net_connect_inbound_nb(lt, conn_open_inbound_generic, first, &share_tx, &share_rx, -1);
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);
1656 // Too many pending connections in the list.
1658 // Shouldn't ever get here. Should never have more than 1 pending connection
1660 write_log(log_file, "[WARNING] Couldn't find exactly 1 connection in pending list. [proxy:%d]",
1667 /*-------------------------------------------------------------------------
1668 void net_open_buggy_aim_dcc(listen_track_struct *lt)
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.
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.
1678 A warning is logged if this isn't the case.
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)
1684 pending_dc_struct *pms, *first, *loose;
1685 listen_track_struct *ls;
1686 int count, loose_count;
1688 // Look for a pending connection for this port
1697 if (pms->cleanup == 0) {
1699 if (pms->orig_port == lt->port) {
1704 // Buggy client hack
1715 // Okay. All is well...apart from the buggy AIM client
1717 write_log(log_file, "[WARNING] Unexpected connection to port %d. Single match for buggy DCC found.",
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.
1724 // Search for the listen tracker on the port in the pending_dc struct.
1727 if (ls->port == first->port)
1733 net_connect_inbound_nb(lt, conn_open_inbound_generic, first, &share_tx, &share_rx, -1);
1738 // Didn't find any matches with strict port checking. Try loose!
1739 if (loose_count == 1) {
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.
1745 // Search for the listen tracker on the port in the pending_dc struct.
1748 if (ls->port == loose->port)
1754 write_log(log_file, "[WARNING] Unexpected connection to port %d. Loose single match for buggy DCC. (Expected %d)",
1755 lt->port, loose->port);
1757 net_connect_inbound_nb(lt, conn_open_inbound_generic, loose, &share_tx, &share_rx, DCC);
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);
1771 /*-------------------------------------------------------------------------
1772 void net_open_msn(listen_track_struct *lt)
1774 Open the connection attempt from the LAN client, create the onward
1775 socket for the proxying, and allocate a tracking structure.
1777 If any steps fail, the client connection is terminated.
1778 -------------------------------------------------------------------------*/
1780 void net_open_msn(listen_track_struct *lt)
1783 net_connect_outbound_nb(lt, conn_open_outbound_generic, NULL, &msn_tx, &msn_rx, lt->port);
1787 /*-------------------------------------------------------------------------
1788 void net_open_msnrx(listen_track_struct *lt)
1790 Open the direct connection attempt from the remote party, and allocate
1791 the connection tracking structure.
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
1796 -------------------------------------------------------------------------*/
1797 void net_open_msnrx(listen_track_struct *lt)
1799 pending_dc_struct *pms, *first;
1802 // Look for a pending connection for this port
1809 if (pms->cleanup == 0) {
1811 if (pms->port == lt->port) {
1823 // Okay. All is well...
1825 net_connect_inbound_nb(lt, conn_open_inbound_generic, first, &msnrx_tx, &msnrx_rx, -1);
1831 // No/too many pending connections in the list.
1833 // Shouldn't ever get here. Should never have more than 1 pending connection
1835 write_log(log_file, "[WARNING] Couldn't find exactly 1 connection in pending list. [proxy:%d]",
1841 /*-------------------------------------------------------------------------
1842 unsigned int fp_process(unsigned char *buff,
1846 proxy_track_struct *pt)
1848 Pass the packet through the filter chain. Nice and simple really.
1850 A NULL filter chain is valid, and mean 'pass unchanged'
1852 -------------------------------------------------------------------------*/
1854 unsigned int fp_process(unsigned char *buff,
1855 unsigned int len, unsigned int max,
1857 proxy_track_struct *pt)
1861 // Pass the data unchanged if there's no filter chain.
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);
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)
1878 Filter helper: Binary search for find_buff in data_buff, and return the
1879 offset. The buffers are masked with the mask_buff.
1881 Returns -1 if the sub-string can't be found.
1882 -------------------------------------------------------------------------*/
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)
1890 if (find_len > data_len)
1893 for (s = 0; s < data_len - find_len; s++) {
1895 for (i = 0; i < find_len; i++) {
1897 if ((data_buff[s+i] & mask_buff[i]) != (find_buff[i] & mask_buff[i]))
1908 /*-------------------------------------------------------------------------
1909 unsigned int fp_oscar_tx(unsigned char *buff,
1912 proxy_track_struct *pt)
1914 Filter procedure: Search for and modify OSCAR IP/Port specifications in
1917 If the packet does not appear to be a file transfer setup, return it
1920 If it appears to have an IP/port setting, setup a listen socket for
1921 the anticipated return packet.
1923 -------------------------------------------------------------------------*/
1925 unsigned int fp_oscar_tx(unsigned char *buff,
1926 unsigned int len, unsigned int max,
1927 proxy_track_struct *pt)
1930 listen_track_struct *lt;
1931 struct timeval tv_now;
1934 // Not long enough for us to check properly...
1938 // Check its long enough for the TLV_TYPE
1939 if (len < AIM_BUD_NEXT(buff) + 2)
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)) {
1951 int alloc_port, orig_dcc_port;
1952 int ip[4], ip_offset, src_ip[4], offset;
1953 struct sockaddr_in src_addr;
1955 unsigned char scan[12], mask[12];
1956 pending_dc_struct *pdc;
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) {
1966 sscanf(inet_ntoa(src_addr.sin_addr), "%d.%d.%d.%d", &src_ip[0], &src_ip[1], &src_ip[2], &src_ip[3]);
1968 // Look for a sequence in the packet that is 00 03 00 04 IP IP IP IP 00 05 00 02 ?? ??
1973 scan[4] = src_ip[0];
1974 scan[5] = src_ip[1];
1975 scan[6] = src_ip[2];
1976 scan[7] = src_ip[3];
1983 memset(mask, 255, sizeof(mask));
1984 mask[4] = mask[5] = mask[6] = mask[7] = 0;
1986 // Search for the IP/port address sequence
1987 offset = fp_locate(buff, len, scan, 12, mask);
1991 // Extract the original DCC port on the inside host
1992 orig_dcc_port = (buff[offset + 12] << 8) | buff[offset + 13];
1994 // Point to the actual address by adjusting over the search preamble.
1995 ip_offset = offset + 4;
1997 // Okay. Determine which address to overwrite the client IP with...
1998 if (outside_ip == NULL) {
2000 // Make a best guess here because we weren't told....
2001 struct sockaddr_in svr_addr;
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.");
2011 sscanf(inet_ntoa(svr_addr.sin_addr), "%d.%d.%d.%d",
2012 &ip[0], &ip[1], &ip[2], &ip[3]);
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",
2025 lt = create_listener_between(INC_MIN, INC_MAX, net_open_aim);
2026 // Couldn't create onward, so can't mangle this request.
2030 // Setup as a 1 shot with a 30 second limit.
2032 gettimeofday(&tv_now, NULL);
2033 lt->timeout = tv_now.tv_sec + INC_TIMEOUT;
2035 alloc_port = lt->port;
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;
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,
2055 AIM_BUD_NAME_LEN(buff), AIM_BUD_NAME(buff));
2057 // Allocate a pending_dc_struct here.
2058 pdc = malloc(sizeof(pending_dc_struct));
2059 memset(pdc, 0, sizeof(pending_dc_struct));
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];
2071 pdc->port = alloc_port;
2072 pdc->orig_port = orig_dcc_port;
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));
2078 pdc->next = dc_list.next;
2086 /*-------------------------------------------------------------------------
2087 unsigned int fp_msn_tx_dcc_setup(unsigned char *buff,
2088 unsigned int len, unsigned int max,
2089 proxy_track_struct *pt)
2091 This function examines data flowing out from this machine for answers
2092 to direct connection setup queries.
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.
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 -------------------------------------------------------------------------*/
2103 unsigned int fp_msn_tx_dcc_setup(unsigned char *buff,
2104 unsigned int len, unsigned int max,
2105 proxy_track_struct *pt)
2109 int ip[4], src_ip[4];
2110 struct sockaddr_in src_addr;
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;
2116 listen_track_struct *lt;
2117 struct timeval tv_now;
2120 // Not long enough for a dcc setup request or too long...
2121 if (len < 85 || len >= sizeof(copy_msg))
2124 memcpy(copy_msg, buff, len);
2125 copy_msg[len] = '\0';
2129 for (scan = copy_msg;
2131 (scan[0] != '\0') &&
2132 (scan[0] != '\r') &&
2133 (scan[1] != '\n');) {
2135 pHdrs[hdr_fields] = scan;
2137 if (hdr_fields == 32)
2140 scan = strstr(scan, "\r\n");
2142 *scan = '\0'; // NULL terminate the pHdr
2143 scan += 2; // Shuffle past the \r\n
2147 // Badly formed buffer
2148 if (!scan || scan[0] == '\0')
2151 scan += 2; // Skip the \r\n separator
2157 (scan[0] != '\0') &&
2158 (scan[0] != '\r') &&
2159 (scan[1] != '\n');) {
2161 pMsgs[msg_fields] = scan;
2163 if (msg_fields == 32)
2166 scan = strstr(scan, "\r\n");
2168 *scan = '\0'; // NULL terminate the pMsg
2169 scan += 2; // Shuffle past the \r\n
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.
2181 // Badly formed buffer without two \n\r pairs at the end of the headers.
2182 if (!scan || scan[0] == '\0')
2186 // Look for the invite / accepted message....
2188 for (find = 0; find < hdr_fields; find ++) {
2189 if (strcmp(pHdrs[find],
2190 "Content-Type: text/x-msmsgsinvite; charset=UTF-8") == 0)
2194 if (find == hdr_fields)
2197 for (find = 0; find < msg_fields; find ++) {
2198 if (strcmp(pMsgs[find],
2199 "Invitation-Command: ACCEPT") == 0)
2203 if (find == msg_fields)
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) {
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");
2221 if (find == msg_fields)
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) {
2229 if (sscanf(pMsgs[find], "Port: %d",
2231 write_log(log_file, "MSN DCC: Badly formed IP port specifier - dodo mode");
2239 if (find == msg_fields)
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) {
2247 if (sscanf(pMsgs[find], "AuthCookie: %d",
2249 write_log(log_file, "MSN DCC: no cookie found - dodo mode");
2257 if (find == msg_fields)
2260 // Read the source IP for the client connection.
2261 // We use this for extra sanity checks in locating the client IP in
2263 salen = sizeof(struct sockaddr_in);
2264 if (getpeername(pt->sockets[TS_CLIENT], (struct sockaddr*) &src_addr, &salen) == -1) {
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]);
2271 if ((ip[0] != src_ip[0]) || (ip[1] != src_ip[1]) ||
2272 (ip[2] != src_ip[2]) || (ip[3] != src_ip[3])) {
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]);
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]);
2287 // Okay. Now to determine which address to overwrite the client IP with...
2288 if (outside_ip == NULL) {
2290 // Make a best guess here because we weren't told....
2291 struct sockaddr_in svr_addr;
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");
2300 sscanf(inet_ntoa(svr_addr.sin_addr), "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
2303 sscanf(outside_ip, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
2307 lt = create_listener_between(INC_MIN, INC_MAX, net_open_msnrx);
2308 // Couldn't create onward, so can't mangle this request.
2312 // Setup as a 1 shot with a 30 second limit.
2314 gettimeofday(&tv_now, NULL);
2315 lt->timeout = tv_now.tv_sec + INC_TIMEOUT;
2317 dcc_port = lt->port;
2322 // Create the new packet, now we have all the data.
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);
2328 // copy over the headers
2329 for (find = 0, scan = buff, len = 0; find < hdr_fields; find++) {
2331 sprintf(scan, "%s\r\n", pHdrs[find]);
2332 scan = &scan[(strlen(pHdrs[find]) + 2)];
2333 len += (strlen(pHdrs[find]) + 2);
2336 sprintf(scan, "\r\n");
2340 // Copy over and mangle as required the msg fields
2341 for (find = 0; find < msg_fields; find ++) {
2345 if (strncmp(pMsgs[find], "IP-Address: ",
2346 strlen("IP-Address: ")) == 0) {
2348 sprintf(tmpbuf, "IP-Address: %d.%d.%d.%d",
2349 ip[0], ip[1], ip[2], ip[3]);
2351 sprintf(scan, "%s\r\n", tmpbuf);
2352 scan = &scan[(strlen(tmpbuf) + 2)];
2353 len += (strlen(tmpbuf) + 2);
2356 } else if (strncmp(pMsgs[find], "Port: ",
2357 strlen("Port: ")) == 0) {
2359 sprintf(tmpbuf, "Port: %d", dcc_port);
2361 sprintf(scan, "%s\r\n", tmpbuf);
2362 scan = &scan[(strlen(tmpbuf) + 2)];
2363 len += (strlen(tmpbuf) + 2);
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);
2377 // Finish off the command building
2378 sprintf(scan, "\r\n");
2382 // Allocate a pending_dc_struct here.
2383 pdc = calloc(sizeof(pending_dc_struct), 1);
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.
2392 pdc->orig_port = port;
2393 pdc->port = dcc_port;
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));
2399 // Add to pending DC list
2400 pdc->next = dc_list.next;
2407 * Read in a filter configuration / control file
2409 * Also dynamic link any modules when I get that far...
2411 * For now, just do it statically.
2413 void setup_filters(const char *ini_file)
2416 memset(&oscar_tx, 0, sizeof(oscar_tx));
2418 oscar_tx.proc[0] = fp_oscar_tx; // LAN client to AIM filter
2420 oscar_tx.proc[0] = fp_oscar_tx; // LAN client to AIM filter
2423 memset(&oscar_rx, 0, sizeof(oscar_rx));
2425 //share_tx; // LAN to Remote filter
2426 memset(&share_tx, 0, sizeof(share_tx));
2428 //share_rx; // Remote to LAN filter
2429 memset(&share_rx, 0, sizeof(share_rx));
2432 memset(&msn_tx, 0, sizeof(msn_tx));
2433 msn_tx.proc[0] = fp_msn_tx_dcc_setup; // LAN client to MSG filter
2436 memset(&msn_rx, 0, sizeof(msn_rx));
2438 //msnrx_tx; // MSN file xfer things
2439 memset(&msnrx_tx, 0, sizeof(msnrx_tx));
2442 memset(&msnrx_rx, 0, sizeof(msnrx_rx));
2445 /*-------------------------------------------------------------------------
2446 * Open a new listen socket, and attach a track struct to the
2447 * linked list of tracking structures.
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)
2454 listen_track_struct *lt;
2456 // Allocate a new track structure if possible.
2457 lt = malloc(sizeof(listen_track_struct));
2460 memset(lt, 0, sizeof(listen_track_struct));
2464 lt->socket = net_listen(port, "0.0.0.0");
2465 if (lt->socket == -1) {
2470 // Add to the tracked socket list.
2471 lt->next = lt_list.next;
2477 /*-------------------------------------------------------------------------
2478 * Open a new listen socket, and attach a track struct to the
2479 * linked list of tracking structures.
2481 * Return NULL on failure, or the newly allocated and added
2482 * track struct on success.
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
2487 *-----------------------------------------------------------------------*/
2488 listen_track_struct* create_listener_between(int port_min, int port_max, listen_proc lp)
2490 listen_track_struct *lt;
2492 // Allocate a new track structure if possible.
2493 lt = malloc(sizeof(listen_track_struct));
2496 memset(lt, 0, sizeof(listen_track_struct));
2500 lt->socket = net_listen_between(port_min, port_max, "0.0.0.0", <->port);
2501 if (lt->socket == -1) {
2506 // Add to the tracked socket list.
2507 lt->next = lt_list.next;
2514 * Read in a filter configuration / control file
2516 * Also dynamic link any modules when I get that far...
2518 * For now, just do it statically.
2520 int setup_listenners(const char *ini_file)
2523 listen_track_struct *lt;
2526 // Interception for data heading out to external hosts.
2528 // These procedures attach the appropriate filtering
2529 // routines for that type of connection.
2533 create_listener_on(MSN, net_open_msn);
2535 // Log invalid attempts
2536 create_listener_on(MSNRX, net_open_log_attempt);
2538 create_listener_on(MSNRX, net_open_msnrx);
2541 write_log(log_file, "[STARTUP] Support for MSN is disabled");
2545 create_listener_on(OSCAR, net_open_aim_oscar);
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);
2552 create_listener_on(SHARE, net_open_aim);
2553 create_listener_on(DCC, net_open_aim);
2556 write_log(log_file, "[STARTUP] Support for AIM is disabled");
2559 // Count listen_track_struct
2570 void close_listenners(const char *ini_file)
2572 listen_track_struct *lt;
2574 // Run around the listenners list and free any listenners
2575 while (lt_list.next) {
2578 lt_list.next = lt->next;
2585 /* HUP Signal Handler */
2591 /* Setup as a demon. Parent process is terminated */
2595 int sockets, max_sockets;
2597 /* Fork and close the parent */
2600 /* Parent has pid of child. Child has pid == 0 */
2602 _exit(0); // close the parent
2605 // Setup as a process leader...
2608 /* Fork and close the process leader */
2611 /* Parent has pid of child. Child has pid == 0 */
2613 _exit(0); // close the parent
2616 /* Change to root directory */
2619 /* Close any open sockets. Including stdout/stderr/stdin.
2620 * Perhaps I should reopen 0/1/2, but ReAIM doesn't use them
2622 max_sockets = sysconf(_SC_OPEN_MAX);
2623 for (sockets = 0; sockets < max_sockets; sockets ++)
2629 printf("Usage: reaim [-h] [-m] [-a] [-e <ip>] [-l log] [-d]\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"
2637 " -d : Do not fork into the background.\n",
2641 int parse_options(int argc, char * argv[])
2644 int option_index = 0, lose = 0;
2650 c = getopt_long(argc, argv, "mae:hl:d",
2651 long_options, &option_index);
2664 outside_ip = strdup(optarg);
2673 if (strlen(optarg) > 0)
2674 log_file = strdup(optarg);
2687 if (lose || optind < argc) {
2697 int reaim_main(int argc, char *argv[])
2699 int main(int argc, char *argv[])
2702 fd_set rfds, efds, wfds;
2703 struct timeval tv_sel, tv_now;
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;
2710 pending_dc_struct *pdc, *prev_pdc;
2712 struct timeval tv_stats;
2713 tv_stats.tv_sec = 0;
2716 if (!parse_options(argc, argv))
2719 if (write_log(log_file,
2720 "[STARTUP] Started AIM-Fix Proxy [%s%s]",
2721 REAIM_VERSION, PLATFORM) == 0) {
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);
2731 // In the case of invalid log file but not forking, write_log
2734 "[WARNING] Unable to write log to %s.\n", log_file);
2736 "[WARNING] Proxy will run, but logging will not work.\n");
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);
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);
2760 write_log(log_file, "[STARTUP] Using %s for the external IP address.", outside_ip);
2762 write_log(log_file, "[STARTUP] Auto-detecting the external IP address.");
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 ?");
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
2780 write_log(log_file, "[SIGNAL] SIGHUP received. Rebinding listenning sockets.");
2781 close_listenners("");
2782 setup_listenners("");
2786 // Setup the list of sockets we are monitoring
2793 // Get the current time
2794 gettimeofday(&tv_now, NULL);
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) {
2802 tv_stats.tv_sec = tv_now.tv_sec + 60*5;
2807 // Process the listen_track list.
2808 // - Timeout processing
2809 // - Cleanup processing
2810 // - Add any listenners to the socket list.
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);
2822 plt->next = lt->next;
2826 // As we just stopped listening to lt->port, kill any
2827 // pending connects for that port too.
2830 if (pdc->port == lt->port)
2840 if (lt->socket > max_fd)
2841 max_fd = lt->socket;
2843 FD_SET(lt->socket, &rfds);
2852 // Cleanup any pending_dc_list entries that are flagged for cleanup
2853 prev_pdc = &dc_list;
2857 pending_dc_struct *next_dc;
2859 prev_pdc->next = pdc->next;
2861 next_dc = pdc->next;
2874 // Cleanup any proxy connections that are flagged...
2877 proxy_track_struct *clean_pt = pt;
2879 write_log(log_file, "[Cleanup] proxy_track_struct [magic=%d] [user=%d]",
2880 pt->magic, pt->user);
2882 // Adjust the linked list
2883 prev_pt->next = pt->next;
2886 // Clean up the proxy track structure data
2888 if (clean_pt->data_buff[0])
2889 free(clean_pt->data_buff[0]);
2891 if (clean_pt->data_buff[1])
2892 free(clean_pt->data_buff[1]);
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]);
2899 // If it's the user-associated socket, zap the user
2900 if (clean_pt->user == 1) {
2902 user_track_struct *user_ut = user_list.next;
2905 if (user_ut->magic == clean_pt->magic)
2906 user_ut->cleanup = 1;
2908 user_ut = user_ut->next;
2917 // Add the sockets to the read/write selection arrays
2919 for (sock = 0; sock < 2; sock ++) {
2921 if (pt->sockets[sock] != -1) {
2922 FD_SET(pt->sockets[sock], &rfds);
2924 if (pt->data_len[sock] > 0)
2925 FD_SET(pt->sockets[sock], &wfds);
2927 if (pt->sockets[sock] > max_fd)
2928 max_fd = pt->sockets[sock];
2936 // Add any pending connection sockets to the write check
2940 if (pc->next->socket == -1) {
2942 // Free the finished up socket
2943 pending_connect_struct *pct;
2946 pc->next = pct->next;
2951 // Check for a timeout.
2952 if (pc->next->timeout < tv_now.tv_sec) {
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);
2963 close(pc->next->socket);
2964 close(pc->next->client_sock);
2965 pc->next->client_sock = -1;
2966 pc->next->socket = -1;
2971 FD_SET(pc->next->socket, &wfds);
2972 if (pc->next->socket > max_fd)
2973 max_fd = pc->next->socket;
2980 // Wait for some activity
2984 sv = select(max_fd+1,&rfds,&wfds,&efds,&tv_sel);
2988 /* Some socket error, maybe */
2989 if (errno != EINTR) {
2990 perror("[FATAL] Server socket died: ");
2995 // Just timed out with nothing going on.
3000 // Process listenners...
3004 if ((lt->socket != -1) &&
3005 (FD_ISSET(lt->socket, &rfds))) {
3014 // Check pending connection sockets
3017 if (pc->next->socket != -1) {
3019 if (FD_ISSET(pc->next->socket, &wfds)) {
3020 pc->next->proc(pc->next);
3027 // Check generic proxied port pairs
3031 for (sock = 0; sock < 2; sock ++) {
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)) {
3040 txs = write(pt->sockets[sock],
3041 &pt->data_buff[sock][pt->data_offset[sock]],
3042 pt->data_len[sock]);
3044 if ((errno != EINTR) && (errno != EAGAIN)) {
3045 write_log(log_file, "Socket write failure! cleaning up!");
3049 pt->data_len[sock] -= txs;
3050 if (pt->data_len[sock] == 0)
3051 pt->data_offset[sock] = 0;
3053 pt->data_offset[sock] += txs;
3057 // On read list, we have data for the other half...
3059 // We only read it if the other half's write buffer is
3060 // completely empty.
3062 if ((pt->sockets[sock] != -1) &&
3063 (pt->cleanup == 0) &&
3064 FD_ISSET(pt->sockets[sock], &rfds) &&
3065 (pt->data_len[sock ^ 1] == 0)) {
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]);
3074 if (errno == EAGAIN)
3075 write_log(log_file, "FOOIE! FD_ISSET, but read() returned EAGAIN [%d]!",
3077 if ((errno != EINTR) && (errno != EAGAIN)) {
3083 write_log(log_file, "socket closed. cleaning up.....");
3089 pt->data_len[sock^1] =
3090 fp_process(pt->data_buff[sock^1],
3092 pt->data_max[sock^1],
3098 } // End of for(sock...)
3102 } // End of while(pt)
3105 } // End of switch(sv)
3107 } // End of while(1)