struct ip_masq * ip_masq_out_get(struct iphdr *iph) { __u16 *portptr; int protocol; __u32 s_addr, d_addr; __u16 s_port, d_port; portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); protocol = iph->protocol; s_addr = iph->saddr; s_port = portptr[0]; d_addr = iph->daddr; d_port = portptr[1]; return ip_masq_out_get_2(protocol, s_addr, s_port, d_addr, d_port); }
int ip_fw_masq_icmp(struct sk_buff **skb_p, struct device *dev) { struct sk_buff *skb = *skb_p; struct iphdr *iph = skb->h.iph; struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); struct iphdr *ciph; /* The ip header contained within the ICMP */ __u16 *pptr; /* port numbers from TCP/UDP contained header */ struct ip_masq *ms; unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("Incoming forward ICMP (%d,%d) %lX -> %lX\n", icmph->type, ntohs(icmp_id(icmph)), ntohl(iph->saddr), ntohl(iph->daddr)); #endif #ifdef CONFIG_IP_MASQUERADE_ICMP if ((icmph->type == ICMP_ECHO ) || (icmph->type == ICMP_TIMESTAMP ) || (icmph->type == ICMP_INFO_REQUEST ) || (icmph->type == ICMP_ADDRESS )) { #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp request rcv %lX->%lX id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type); #endif ms = ip_masq_out_get_2(iph->protocol, iph->saddr, icmp_id(icmph), iph->daddr, icmp_hv_req(icmph)); if (ms == NULL) { ms = ip_masq_new(dev, iph->protocol, iph->saddr, icmp_id(icmph), iph->daddr, icmp_hv_req(icmph), 0); if (ms == NULL) return (-1); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: Create new icmp entry\n"); #endif } ip_masq_set_expire(ms, 0); /* Rewrite source address */ /* * If sysctl !=0 and no pkt has been received yet * in this tunnel and routing iface address has changed... * "You are welcome, diald". */ if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && dev->pa_addr != ms->maddr) { unsigned long flags; #ifdef DEBUG_CONFIG_IP_MASQUERADE printk(KERN_INFO "ip_fw_masq_icmp(): change masq.addr %s", in_ntoa(ms->maddr)); printk("-> %s\n", in_ntoa(dev->pa_addr)); #endif save_flags(flags); cli(); ip_masq_unhash(ms); ms->maddr = dev->pa_addr; ip_masq_hash(ms); restore_flags(flags); } iph->saddr = ms->maddr; ip_send_check(iph); /* Rewrite port (id) */ (icmph->un).echo.id = ms->mport; icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *)icmph, len); ip_masq_set_expire(ms, MASQUERADE_EXPIRE_ICMP); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp request rwt %lX->%lX id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type); #endif return (1); } #endif /* * Work through seeing if this is for us. * These checks are supposed to be in an order that * means easy things are checked first to speed up * processing.... however this means that some * packets will manage to get a long way down this * stack and then be rejected, but thats life */ if ((icmph->type != ICMP_DEST_UNREACH) && (icmph->type != ICMP_SOURCE_QUENCH) && (icmph->type != ICMP_TIME_EXCEEDED)) return 0; /* Now find the contained IP header */ ciph = (struct iphdr *) (icmph + 1); #ifdef CONFIG_IP_MASQUERADE_ICMP if (ciph->protocol == IPPROTO_ICMP) { /* * This section handles ICMP errors for ICMP packets */ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + (ciph->ihl<<2)); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: fw icmp/icmp rcv %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif ms = ip_masq_out_get_2(ciph->protocol, ciph->daddr, icmp_id(cicmph), ciph->saddr, icmp_hv_rep(cicmph)); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the source IP address, and recalc checksum */ iph->saddr = ms->maddr; ip_send_check(iph); /* Now change the *dest* address in the contained IP */ ciph->daddr = ms->maddr; ip_send_check(ciph); /* Change the ID to the masqed one! */ (cicmph->un).echo.id = ms->mport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: fw icmp/icmp rwt %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif return 1; } #endif /* CONFIG_IP_MASQUERADE_ICMP */ /* We are only interested ICMPs generated from TCP or UDP packets */ if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP)) return 0; /* * Find the ports involved - this packet was * incoming so the ports are right way round * (but reversed relative to outer IP header!) */ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); /* Ensure the checksum is correct */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ printk(KERN_DEBUG "MASQ: forward ICMP: failed checksum from %s!\n", in_ntoa(iph->saddr)); return(-1); } #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Handling forward ICMP for %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif /* This is pretty much what ip_masq_out_get() does */ ms = ip_masq_out_get_2(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the source IP address, and recalc checksum */ iph->saddr = ms->maddr; ip_send_check(iph); /* Now change the *dest* address in the contained IP */ ciph->daddr = ms->maddr; ip_send_check(ciph); /* the TCP/UDP dest port - cannot redo check */ pptr[1] = ms->mport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Rewrote forward ICMP to %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif return 1; }
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_in (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; unsigned char p1,p2,p3,p4,p5,p6; __u32 to; __u16 port; struct ip_masq *n_ms; if (! ms->flags & IP_MASQ_F_FTP_PASV) return 0; /* quick exit if no outstanding PASV */ 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; while (data < data_limit && *data != ' ') ++data; while (data < data_limit && *data == ' ') ++data; data += 22; if (data >= data_limit || *data != '(') return 0; p1 = simple_strtoul(data+1, &data, 10); if (data >= data_limit || *data != ',') return 0; p2 = simple_strtoul(data+1, &data, 10); if (data >= data_limit || *data != ',') return 0; p3 = simple_strtoul(data+1, &data, 10); if (data >= data_limit || *data != ',') return 0; p4 = simple_strtoul(data+1, &data, 10); if (data >= data_limit || *data != ',') return 0; p5 = simple_strtoul(data+1, &data, 10); if (data >= data_limit || *data != ',') return 0; p6 = simple_strtoul(data+1, &data, 10); if (data >= data_limit || *data != ')') return 0; to = (p1<<24) | (p2<<16) | (p3<<8) | p4; port = (p5<<8) | p6; /* * Now update or create an masquerade entry for it */ #if DEBUG_CONFIG_IP_MASQ_FTP printk("PASV response %lX:%X %X:%X detected\n", ntohl(ms->saddr), 0, to, port); #endif n_ms = ip_masq_out_get_2(iph->protocol, ms->saddr, 0, htonl(to), htons(port)); if (n_ms) { /* existing masquerade, clear timer */ ip_masq_set_expire(n_ms,0); } else { n_ms = ip_masq_new(dev, IPPROTO_TCP, ms->saddr, 0, htonl(to), htons(port), IP_MASQ_F_NO_SPORT); 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, client may not issue open * to server port before tcp_fin_timeout. */ ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout*3); ms->flags &= ~IP_MASQ_F_FTP_PASV; return 0; /* no diff required for incoming packets, thank goodness */ }