--- ip_masq_irc.c.old Mon Aug 9 14:04:41 1999 +++ ip_masq_irc.c Tue Aug 1 22:43:33 2000 @@ -20,9 +20,8 @@ * Juan Jose Ciarlante : put new ms entry to listen() * Scottie Shore : added support for clients that add extra args * - * - * FIXME: - * - detect also previous "PRIVMSG" string ?. + * Scottie Shore : added support for mIRC DCC resume negotiation + * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -91,9 +90,10 @@ { "CHAT ", 5 }, { "MOVE ", 5 }, { "TSEND ", 6 }, - { "SCHAT ", 6 } + { "SCHAT ", 6 }, + { "ACCEPT ", 7 }, }; -#define MAXMATCHLEN 6 +#define MAXMATCHLEN 7 static int masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) @@ -137,6 +137,7 @@ * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26 * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26 * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27 + * strlen("\1DCC ACCEPT F AAAAAAAA P S\1\n")=28 * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits) * P: bound port (min 1 d ) * F: filename (min 1 d ) @@ -197,17 +198,26 @@ s_port = simple_strtoul(data,&data,10); addr_end_p = data; + /* Do we already have a port open for this client? + * If so, use it (for DCC ACCEPT) + */ + + n_ms = ip_masq_out_get(IPPROTO_TCP, + htonl(s_addr),htons(s_port), + 0, 0); + /* - * Now create an masquerade entry for it - * must set NO_DPORT and NO_DADDR because + * If we didn't already have a port, we need to make one. + * We 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) + 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; @@ -252,6 +262,125 @@ } +int +masq_irc_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) +{ + struct sk_buff *skb; + struct iphdr *iph; + struct tcphdr *th; + char *data, *data_limit; + __u32 s_addr; + __u16 s_port; + struct ip_masq *n_ms; + char buf[20]; /* "m_addr m_port" (dec base)*/ + unsigned buf_len; + int diff; + char *dcc_p, *addr_beg_p, *addr_end_p; + + skb = *skb_p; + iph = skb->nh.iph; + th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); + data = (char *)&th[1]; + + /* + * Hunt irc DCC RESUME string: + * + * strlen("\1DCC RESUME chat AAAAAAAA P\1\n")=29 + * 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 - 29 ) ) + { + if (memcmp(data,"\1DCC RESUME ",12)) { + data ++; + continue; + } + + dcc_p = data; + data += 12; + + while( *data++ != ' ') + /* + * must still parse, at least, "AAAAAAAA P\1\n", + * 12 bytes left. + */ + if (data > (data_limit-12)) return 0; + + + addr_beg_p = data; + + /* + * masq bound address in dec base + */ + + s_addr = simple_strtoul(data,&data,10); + if (*data++ !=' ') + continue; + + /* + * masq bound port in dec base + */ + + s_port = simple_strtoul(data,&data,10); + addr_end_p = data; + + /* + * Find the masq entry associated with this connection. + * The entry should have no dest addr/port yet. + * If there is no entry, return 0. + */ + + n_ms = ip_masq_in_get(IPPROTO_TCP, + 0, 0, + htonl(s_addr), htons(s_port)); + + if (n_ms==NULL) + return 0; + + /* + * Replace the outside address with the inside address + */ + + buf_len = sprintf(buf,"%lu %u", + ntohl(n_ms->saddr),ntohs(n_ms->sport)); + + /* + * 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_in(): '%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); + } + + return diff; + + } + return 0; + +} + /* * Main irc object * You need 1 object per port in case you need @@ -263,12 +392,12 @@ struct ip_masq_app ip_masq_irc = { NULL, /* next */ "irc", /* name */ - 0, /* type */ - 0, /* n_attach */ - masq_irc_init_1, /* init_1 */ - masq_irc_done_1, /* done_1 */ - masq_irc_out, /* pkt_out */ - NULL /* pkt_in */ + 0, /* type */ + 0, /* n_attach */ + masq_irc_init_1, /* init_1 */ + masq_irc_done_1, /* done_1 */ + masq_irc_out, /* pkt_out */ + masq_irc_in /* pkt_in */ }; /*