int masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev) { 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; int xtra_args = 0; /* extra int args wanted after addr */ char *dcc_p, *addr_beg_p, *addr_end_p; skb = *skb_p; iph = skb->h.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); 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 */ data_limit = skb->h.raw + skb->len; while (data < (data_limit - 25) ) { if (memcmp(data,"DCC ",4)) { data ++; continue; } 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(dev, 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) { /* * 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; } return 0; }
int masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev) { struct sk_buff *skb; struct iphdr *iph; struct tcphdr *th; char *p, *data, *data_limit; unsigned char p1,p2,p3,p4,p5,p6; __u32 from; __u16 port; struct ip_masq *n_ms; char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ unsigned buf_len; int diff; skb = *skb_p; iph = skb->h.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); data = (char *)&th[1]; data_limit = skb->h.raw + skb->len - 18; if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0)) ms->flags |= IP_MASQ_F_FTP_PASV; while (data < data_limit) { if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) { data ++; continue; } p = data+5; p1 = simple_strtoul(data+5,&data,10); if (*data!=',') continue; p2 = simple_strtoul(data+1,&data,10); if (*data!=',') continue; p3 = simple_strtoul(data+1,&data,10); if (*data!=',') continue; p4 = simple_strtoul(data+1,&data,10); if (*data!=',') continue; p5 = simple_strtoul(data+1,&data,10); if (*data!=',') continue; p6 = simple_strtoul(data+1,&data,10); if (*data!='\r' && *data!='\n') continue; from = (p1<<24) | (p2<<16) | (p3<<8) | p4; port = (p5<<8) | p6; #if DEBUG_CONFIG_IP_MASQ_FTP printk("PORT %X:%X detected\n",from,port); #endif /* * Now update or create an masquerade entry for it */ #if DEBUG_CONFIG_IP_MASQ_FTP printk("protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0); #endif n_ms = ip_masq_out_get_2(iph->protocol, htonl(from), htons(port), iph->daddr, 0); if (n_ms) { /* existing masquerade, clear timer */ ip_masq_set_expire(n_ms,0); } else { n_ms = ip_masq_new(dev, IPPROTO_TCP, htonl(from), htons(port), iph->daddr, 0, IP_MASQ_F_NO_DPORT); if (n_ms==NULL) return 0; n_ms->control = ms; /* keepalive from data to the control channel */ ms->flags |= IP_MASQ_F_CONTROL; /* this is a control channel */ } /* * keep for a bit longer than tcp_fin, caller may not reissue * PORT before tcp_fin_timeout. */ ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout*3); /* * Replace the old PORT with the new one */ from = ntohl(n_ms->maddr); port = ntohs(n_ms->mport); sprintf(buf,"%d,%d,%d,%d,%d,%d", from>>24&255,from>>16&255,from>>8&255,from&255, port>>8&255,port&255); buf_len = strlen(buf); #if DEBUG_CONFIG_IP_MASQ_FTP printk("new PORT %X:%X\n",from,port); #endif /* * Calculate required delta-offset to keep TCP happy */ diff = buf_len - (data-p); /* * No shift. */ if (diff==0) { /* * simple case, just replace the old PORT cmd */ memcpy(p,buf,buf_len); return 0; } *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len); return diff; } return 0; }
int masq_ftp_out (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 *p, *data, *data_limit; unsigned char p1,p2,p3,p4,p5,p6; __u32 from; __u16 port; struct ip_masq *n_ms; char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ unsigned buf_len; int diff; skb = *skb_p; iph = skb->nh.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); data = (char *)&th[1]; data_limit = skb->h.raw + skb->len - 18; if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0)) ms->app_data = &masq_ftp_pasv; while (data < data_limit) { if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) { data ++; continue; } p = data+5; p1 = simple_strtoul(data+5,&data,10); if (*data!=',') continue; p2 = simple_strtoul(data+1,&data,10); if (*data!=',') continue; p3 = simple_strtoul(data+1,&data,10); if (*data!=',') continue; p4 = simple_strtoul(data+1,&data,10); if (*data!=',') continue; p5 = simple_strtoul(data+1,&data,10); if (*data!=',') continue; p6 = simple_strtoul(data+1,&data,10); if (*data!='\r' && *data!='\n') continue; from = (p1<<24) | (p2<<16) | (p3<<8) | p4; port = (p5<<8) | p6; IP_MASQ_DEBUG(1-debug, "PORT %X:%X detected\n",from,port); /* * Now update or create an masquerade entry for it */ IP_MASQ_DEBUG(1-debug, "protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0); n_ms = ip_masq_out_get(iph->protocol, htonl(from), htons(port), iph->daddr, 0); if (!n_ms) { n_ms = ip_masq_new(IPPROTO_TCP, maddr, 0, htonl(from), htons(port), iph->daddr, 0, IP_MASQ_F_NO_DPORT); if (n_ms==NULL) return 0; ip_masq_control_add(n_ms, ms); } /* * Replace the old PORT with the new one */ from = ntohl(n_ms->maddr); port = ntohs(n_ms->mport); sprintf(buf,"%d,%d,%d,%d,%d,%d", from>>24&255,from>>16&255,from>>8&255,from&255, port>>8&255,port&255); buf_len = strlen(buf); IP_MASQ_DEBUG(1-debug, "new PORT %X:%X\n",from,port); /* * Calculate required delta-offset to keep TCP happy */ diff = buf_len - (data-p); /* * No shift. */ if (diff==0) { /* * simple case, just replace the old PORT cmd */ memcpy(p,buf,buf_len); } else { *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len); } /* * Move tunnel to listen state */ ip_masq_listen(n_ms); ip_masq_put(n_ms); return diff; } return 0; }
int masq_irc_out (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 string, the _shortest_: * * strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27 * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28 * 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 * 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 - ( 22 + MAXMATCHLEN ) ) ) { int i; if (memcmp(data,"\1DCC ",5)) { data ++; continue; } dcc_p = data; data += 5; /* point to DCC cmd */ for(i=0; i<NUM_DCCPROTO; i++) { /* * go through the table and hunt a match string */ if( memcmp(data, dccprotos[i].match, dccprotos[i].matchlen ) == 0 ) { data += dccprotos[i].matchlen; /* * skip next string. */ 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; /* * 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; /* * 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; }