patch-2.1.73 linux/net/ipv4/ip_masq_irc.c

Next file: linux/net/ipv4/ip_masq_mod.c
Previous file: linux/net/ipv4/ip_masq_ftp.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_irc.c linux/net/ipv4/ip_masq_irc.c
@@ -2,13 +2,22 @@
  *		IP_MASQ_IRC irc masquerading module
  *
  *
- * Version:	@(#)ip_masq_irc.c 0.01   03/20/96
+ * Version:	@(#)ip_masq_irc.c 0.03   97/11/30
  *
  * Author:	Juan Jose Ciarlante
- *
- *
+ *		
+ * Additions:
+ *  - recognize a few non-irc-II DCC requests (Oliver Wagner)
+ *     DCC MOVE (AmIRC/DCC.MOVE; SEND with resuming)
+ *     DCC SCHAT (AmIRC IDEA encrypted CHAT)
+ *     DCC TSEND (AmIRC/PIRCH SEND without ACKs)
  * Fixes:
- *	- set NO_DADDR flag in ip_masq_new().
+ *	Juan Jose Ciarlante	:  set NO_DADDR flag in ip_masq_new()
+ *	Nigel Metheringham	:  Added multiple port support 
+ *	Juan Jose Ciarlante	:  litl bits for 2.1
+ *	Oliver Wagner 		:  more IRC cmds processing
+ *	  <winmute@lucifer.gv.kotnet.org>
+ *	Juan Jose Ciarlante	:  put new ms entry to listen()
  *
  * FIXME:
  *	- detect also previous "PRIVMSG" string ?.
@@ -17,7 +26,18 @@
  *	modify it under the terms of the GNU General Public License
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
- *
+ *	
+ * Multiple Port Support
+ *	The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ *	with the port numbers being defined at module load time.  The module
+ *	uses the symbol "ports" to define a list of monitored ports, which can
+ *	be specified on the insmod command line as
+ *		ports=x1,x2,x3...
+ *	where x[n] are integer port numbers.  This option can be put into
+ *	/etc/conf.modules (or /etc/modules.conf depending on your config)
+ *	where modload will pick it up should you use modload to load your
+ *	modules.
+ *	
  */
 
 #include <linux/config.h>
@@ -34,7 +54,43 @@
 #include <net/tcp.h>
 #include <net/ip_masq.h>
 
-#define DEBUG_CONFIG_IP_MASQ_IRC 0
+
+/* 
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+int ports[MAX_MASQ_APP_PORTS] = {6667}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+/*
+ *	Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+
+/*
+ * List of supported DCC protocols
+ */
+
+#define NUM_DCCPROTO 5
+
+struct dccproto 
+{
+  char *match;
+  int matchlen;
+  int xtra_args;
+};
+
+struct dccproto dccprotos[NUM_DCCPROTO] = {
+ { "SEND ", 5, 1 },
+ { "CHAT ", 5, 0, },
+ { "MOVE ", 5, 1 },
+ { "TSEND ", 6, 1, },
+ { "SCHAT ", 6, 0, }
+};
+#define MAXMATCHLEN 6
 
 static int
 masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
@@ -72,145 +128,148 @@
         data = (char *)&th[1];
 
         /*
-         *	Hunt irc DCC string, the _shortest_:
-         *
-         *	strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26
-         *	strlen("DCC SEND F AAAAAAAA P S\x01\n")=25
-         *		AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
-         *		P:         bound port (min 1 d )
-         *		F:         filename   (min 1 d )
-         *		S:         size       (min 1 d )
-         *		0x01, \n:  terminators
+	 *	Hunt irc DCC string, the _shortest_:
+	 *
+	 *	strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26
+	 *	strlen("DCC SCHAT chat AAAAAAAA P\x01\n")=27
+	 *	strlen("DCC SEND F AAAAAAAA P S\x01\n")=25
+	 *	strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
+	 *	strlen("DCC TSEND F AAAAAAAA P S\x01\n")=26
+	 *	strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
+	 *		AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
+	 *		P:         bound port (min 1 d )
+	 *		F:         filename   (min 1 d )
+	 *		S:         size       (min 1 d ) 
+	 *		0x01, \n:  terminators
          */
 
         data_limit = skb->h.raw + skb->len;
-
-	while (data < (data_limit - 25) )
+        
+	while (data < (data_limit - ( 21 + MAXMATCHLEN ) ) )
 	{
+		int i;
 		if (memcmp(data,"DCC ",4))  {
 			data ++;
 			continue;
 		}
 
-                dcc_p = data;
+		dcc_p = data;
 		data += 4;     /* point to DCC cmd */
 
-                if (memcmp(data, "CHAT ", 5) == 0 ||
-                    memcmp(data, "SEND ", 5) == 0)
-                {
-                        /*
-                         *	extra arg (file_size) req. for "SEND"
-                         */
-
-                        if (*data == 'S') xtra_args++;
-                        data += 5;
-                }
-                else
-                        continue;
-
-                /*
-                 *	skip next string.
-                 */
-
-                while( *data++ != ' ')
-
-                        /*
-                         *	must still parse, at least, "AAAAAAAA P\x01\n",
-                         *      12 bytes left.
-                         */
-                        if (data > (data_limit-12)) return 0;
-
-
-                addr_beg_p = data;
-
-                /*
-                 *	client bound address in dec base
-                 */
-
- 		s_addr = simple_strtoul(data,&data,10);
-		if (*data++ !=' ')
-			continue;
-
-                /*
-                 *	client bound port in dec base
-                 */
-
-		s_port = simple_strtoul(data,&data,10);
-                addr_end_p = data;
-
-                /*
-                 *	should check args consistency?
-                 */
-
-                while(xtra_args) {
-                        if (*data != ' ')
-                                break;
-                        data++;
-                        simple_strtoul(data,&data,10);
-                        xtra_args--;
-                }
-
-                if (xtra_args != 0) continue;
-
-                /*
-                 *	terminators.
-                 */
-
-                if (data[0] != 0x01)
-                        continue;
-		if (data[1]!='\r' && data[1]!='\n')
-			continue;
-
-		/*
-		 *	Now create an masquerade entry for it
-                 * 	must set NO_DPORT and NO_DADDR because
-                 *	connection is requested by another client.
-		 */
-
-		n_ms = ip_masq_new(maddr, IPPROTO_TCP,
-                                   htonl(s_addr),htons(s_port),
-                                   0, 0,
-                                   IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR
-                                   );
-		if (n_ms==NULL)
-			return 0;
-
-                ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout);
-
-		/*
-		 * Replace the old "address port" with the new one
-		 */
-
-		buf_len = sprintf(buf,"%lu %u",
-                        ntohl(n_ms->maddr),ntohs(n_ms->mport));
-
-		/*
-		 * Calculate required delta-offset to keep TCP happy
-		 */
-
-		diff = buf_len - (addr_end_p-addr_beg_p);
-
-#if DEBUG_CONFIG_IP_MASQ_IRC
-                *addr_beg_p = '\0';
-		printk("masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
-#endif
-		/*
-		 *	No shift.
-		 */
-
-		if (diff==0)
+		for(i=0; i<NUM_DCCPROTO; i++)
 		{
 			/*
-			 * simple case, just copy.
- 			 */
- 			memcpy(addr_beg_p,buf,buf_len);
- 			return 0;
- 		}
-
-                *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
-                                             addr_beg_p, addr_end_p-addr_beg_p,
-                                             buf, buf_len);
-                return diff;
+			 * go through the table and hunt a match string
+			 */
+
+			if( memcmp(data, dccprotos[i].match, dccprotos[i].matchlen ) == 0 )
+			{
+				xtra_args = dccprotos[i].xtra_args;
+				data += dccprotos[i].matchlen;
+
+				/*
+				 *	skip next string.
+				 */
+
+				while( *data++ != ' ')
+
+					/*
+					 *	must still parse, at least, "AAAAAAAA P\x01\n",
+					 *      12 bytes left.
+					 */
+					if (data > (data_limit-12)) return 0;
+
+
+				addr_beg_p = data;
+
+				/*
+				 *	client bound address in dec base
+				 */
+
+				s_addr = simple_strtoul(data,&data,10);
+				if (*data++ !=' ')
+					continue;
+
+				/*
+				 *	client bound port in dec base
+				 */
+
+				s_port = simple_strtoul(data,&data,10);
+				addr_end_p = data;
+
+				/*
+				 *	should check args consistency?
+				 */
+
+				while(xtra_args) {
+					if (*data != ' ')
+						break;
+					data++;
+					simple_strtoul(data,&data,10);
+					xtra_args--;
+				}
+
+				if (xtra_args != 0) continue;
+
+				/*
+				 *	terminators.
+				 */
+
+				if (data[0] != 0x01)
+					continue;
+				if (data[1]!='\r' && data[1]!='\n')
+					continue;
+
+				/*
+				 *	Now create an masquerade entry for it
+				 * 	must set NO_DPORT and NO_DADDR because
+				 *	connection is requested by another client.
+				 */
+
+				n_ms = ip_masq_new(IPPROTO_TCP,
+						maddr, 0,
+						htonl(s_addr),htons(s_port),
+						0, 0,
+						IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
+				if (n_ms==NULL)
+					return 0;
+
+				/*
+				 * Replace the old "address port" with the new one
+				 */
+
+				buf_len = sprintf(buf,"%lu %u",
+						ntohl(n_ms->maddr),ntohs(n_ms->mport));
+
+				/*
+				 * Calculate required delta-offset to keep TCP happy
+				 */
+
+				diff = buf_len - (addr_end_p-addr_beg_p);
+
+				*addr_beg_p = '\0';
+				IP_MASQ_DEBUG(1-debug, "masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
+
+				/*
+				 *	No shift.
+				 */
+
+				if (diff==0) {
+					/*
+					 * simple case, just copy.
+					 */
+					memcpy(addr_beg_p,buf,buf_len);
+				} else {
+
+					*skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
+							addr_beg_p, addr_end_p-addr_beg_p,
+							buf, buf_len);
+				}
+				ip_masq_listen(n_ms);
+				ip_masq_put(n_ms);
+				return diff;
+			}
+		}
 	}
 	return 0;
 
@@ -221,7 +280,7 @@
  *     	You need 1 object per port in case you need
  *	to offer also other used irc ports (6665,6666,etc),
  *	they will share methods but they need own space for
- *	data.
+ *	data. 
  */
 
 struct ip_masq_app ip_masq_irc = {
@@ -241,7 +300,28 @@
 
 __initfunc(int ip_masq_irc_init(void))
 {
-        return register_ip_masq_app(&ip_masq_irc, IPPROTO_TCP, 6667);
+	int i, j;
+
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (ports[i]) {
+			if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+							    GFP_KERNEL)) == NULL)
+				return -ENOMEM;
+			memcpy(masq_incarnations[i], &ip_masq_irc, sizeof(struct ip_masq_app));
+			if ((j = register_ip_masq_app(masq_incarnations[i], 
+						      IPPROTO_TCP, 
+						      ports[i]))) {
+				return j;
+			}
+			IP_MASQ_DEBUG(1-debug,
+					"Irc: loaded support on port[%d] = %d\n",
+			       i, ports[i]);
+		} else {
+			/* To be safe, force the incarnation table entry to NULL */
+			masq_incarnations[i] = NULL;
+		}
+	}
+	return 0;
 }
 
 /*
@@ -250,8 +330,24 @@
 
 int ip_masq_irc_done(void)
 {
-        return unregister_ip_masq_app(&ip_masq_irc);
+	int i, j, k;
+
+	k=0;
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (masq_incarnations[i]) {
+			if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+				k = j;
+			} else {
+				kfree(masq_incarnations[i]);
+				masq_incarnations[i] = NULL;
+				IP_MASQ_DEBUG(1-debug, "Irc: unloaded support on port[%d] = %d\n",
+				       i, ports[i]);
+			}
+		}
+	}
+	return k;
 }
+
 
 #ifdef MODULE
 EXPORT_NO_SYMBOLS;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov