static void masq_expire(unsigned long data) { struct ip_masq *ms = (struct ip_masq *)data, *ms_data; unsigned long flags; if (ms->flags & IP_MASQ_F_CONTROL) { /* a control channel is about to expire */ int idx = 0, reprieve = 0; #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Masquerade control %s %lX:%X about to expire\n", masq_proto_name(ms->protocol), ntohl(ms->saddr),ntohs(ms->sport)); #endif save_flags(flags); cli(); /* * If any other masquerade entry claims that the expiring entry * is its control channel then keep the control entry alive. * Useful for long running data channels with inactive control * links which we don't want to lose, e.g. ftp. * Assumption: loops such as a->b->a or a->a will never occur. */ for (idx = 0; idx < IP_MASQ_TAB_SIZE && !reprieve; idx++) { for (ms_data = ip_masq_m_tab[idx]; ms_data ; ms_data = ms_data->m_link) { if (ms_data->control == ms) { reprieve = 1; /* this control connection can live a bit longer */ ip_masq_set_expire(ms, ip_masq_expire->tcp_timeout); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Masquerade control %s %lX:%X expiry reprieved\n", masq_proto_name(ms->protocol), ntohl(ms->saddr),ntohs(ms->sport)); #endif break; } } } restore_flags(flags); if (reprieve) return; } #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Masqueraded %s %lX:%X expired\n",masq_proto_name(ms->protocol),ntohl(ms->saddr),ntohs(ms->sport)); #endif save_flags(flags); cli(); if (ip_masq_unhash(ms)) { ip_masq_free_ports[masq_proto_num(ms->protocol)]++; if (ms->protocol != IPPROTO_ICMP) ip_masq_unbind_app(ms); kfree_s(ms,sizeof(*ms)); } restore_flags(flags); }
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_vdolive_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; unsigned int tagval; /* This should be a 32 bit quantity */ struct ip_masq *n_ms; struct vdolive_priv_data *priv = (struct vdolive_priv_data *)ms->app_data; /* This doesn't work at all if no priv data was allocated on startup */ if (!priv) return 0; /* Everything running correctly already */ if (priv->state == 3) return 0; 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; if (data+8 > data_limit) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: packet too short for ID %lx %lx\n", data, data_limit); #endif return 0; } memcpy(&tagval, data+4, 4); #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: packet seen, tag %ld, in initial state %d\n", ntohl(tagval), priv->state); #endif /* Check for leading packet ID */ if ((ntohl(tagval) != 6) && (ntohl(tagval) != 1)) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: unrecognised tag %ld, in initial state %d\n", ntohl(tagval), priv->state); #endif return 0; } /* Check packet is long enough for data - ignore if not */ if ((ntohl(tagval) == 6) && (data+36 > data_limit)) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: initial packet too short %lx %lx\n", data, data_limit); #endif return 0; } else if ((ntohl(tagval) == 1) && (data+20 > data_limit)) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: secondary packet too short %lx %lx\n", data, data_limit); #endif return 0; } /* Adjust data pointers */ /* * I could check the complete protocol version tag * in here however I am just going to look for the * "VDO Live" tag in the hope that this part will * remain constant even if the version changes */ if (ntohl(tagval) == 6) { data += 24; #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: initial packet found\n"); #endif } else { data += 8; #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: secondary packet found\n"); #endif } if (memcmp(data, "VDO Live", 8) != 0) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: did not find tag\n"); #endif return 0; } /* * The port number is the next word after the tag. * VDOlive encodes all of these values * in 32 bit words, so in this case I am * skipping the first 2 bytes of the next * word to get to the relevant 16 bits */ data += 10; /* * If we have not seen the port already, * set the masquerading tunnel up */ if (!priv->origport) { memcpy(&priv->origport, data, 2); #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: found port %d\n", ntohs(priv->origport)); #endif /* Open up a tunnel */ n_ms = ip_masq_new(dev, IPPROTO_UDP, ms->saddr, priv->origport, ms->daddr, 0, IP_MASQ_F_NO_DPORT); if (n_ms==NULL) { printk("VDOlive: unable to build UDP tunnel for %x:%x\n", ms->saddr, priv->origport); /* Leave state as unset */ priv->origport = 0; return 0; } ip_masq_set_expire(n_ms, ip_masq_expire->udp_timeout); priv->masqport = n_ms->mport; } else if (memcmp(data, &(priv->origport), 2)) { printk("VDOlive: ports do not match\n"); /* Write the port in anyhow!!! */ } /* * Write masq port into packet */ memcpy(data, &(priv->masqport), 2); #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: rewrote port %d to %d, server %s\n", ntohs(priv->origport), ntohs(priv->masqport), in_ntoa(ms->saddr)); #endif /* * Set state bit to make which bit has been done */ priv->state |= (ntohl(tagval) == 6) ? 1 : 2; return 0; }
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 ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev) { struct sk_buff *skb=*skb_ptr; struct iphdr *iph = skb->h.iph; __u16 *portptr; struct ip_masq *ms; int size; unsigned long timeout; /* * We can only masquerade protocols with ports... * [TODO] * We may need to consider masq-ing some ICMP related to masq-ed protocols */ if (iph->protocol==IPPROTO_ICMP) return (ip_fw_masq_icmp(skb_ptr,dev)); if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) return -1; /* * Now hunt the list to see if we have an old entry */ portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Outgoing %s %lX:%X -> %lX:%X\n", masq_proto_name(iph->protocol), ntohl(iph->saddr), ntohs(portptr[0]), ntohl(iph->daddr), ntohs(portptr[1])); #endif ms = ip_masq_out_get(iph); if (ms!=NULL) { ip_masq_set_expire(ms,0); /* * 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; if (sysctl_ip_dynaddr > 1) { printk(KERN_INFO "ip_fw_masquerade(): change maddr from %s", in_ntoa(ms->maddr)); printk(" to %s\n", in_ntoa(dev->pa_addr)); } save_flags(flags); cli(); ip_masq_unhash(ms); ms->maddr = dev->pa_addr; ip_masq_hash(ms); restore_flags(flags); } /* * Set sport if not defined yet (e.g. ftp PASV). Because * masq entries are hashed on sport, unhash with old value * and hash with new. */ if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) { unsigned long flags; ms->flags &= ~IP_MASQ_F_NO_SPORT; save_flags(flags); cli(); ip_masq_unhash(ms); ms->sport = portptr[0]; ip_masq_hash(ms); /* hash on new sport */ restore_flags(flags); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_fw_masquerade(): filled sport=%d\n", ntohs(ms->sport)); #endif } } #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW /* update any ipautofw entries .. */ ip_autofw_update_out(iph->saddr, iph->daddr, portptr[1], iph->protocol); #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ /* * Nope, not found, create a new entry for it */ if (ms==NULL) { #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW /* if the source port is supposed to match the masq port, then make it so */ if (ip_autofw_check_direct(portptr[1],iph->protocol)) ms = ip_masq_new_enh(dev, iph->protocol, iph->saddr, portptr[0], iph->daddr, portptr[1], 0, portptr[0]); else #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ ms = ip_masq_new_enh(dev, iph->protocol, iph->saddr, portptr[0], iph->daddr, portptr[1], 0, 0); if (ms == NULL) return -1; } /* * Change the fragments origin */ size = skb->len - ((unsigned char *)portptr - skb->h.raw); /* * Set iph addr and port from ip_masq obj. */ iph->saddr = ms->maddr; portptr[0] = ms->mport; /* * Attempt ip_masq_app call. * will fix ip_masq and iph seq stuff */ if (ip_masq_app_pkt_out(ms, skb_ptr, dev) != 0) { /* * skb has possibly changed, update pointers. */ skb = *skb_ptr; iph = skb->h.iph; portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); size = skb->len - ((unsigned char *)portptr-skb->h.raw); } /* * Adjust packet accordingly to protocol */ if (masq_proto_num(iph->protocol)==0) { timeout = ip_masq_expire->udp_timeout; recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); } else { struct tcphdr *th; th = (struct tcphdr *)portptr; /* Set the flags up correctly... */ if (th->fin) { ms->flags |= IP_MASQ_F_SAW_FIN_OUT; } if (th->rst) { ms->flags |= IP_MASQ_F_SAW_RST; } /* * Timeout depends if FIN packet has been seen * Very short timeout if RST packet seen. */ if (ms->flags & IP_MASQ_F_SAW_RST) { timeout = 1; } else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN) { timeout = ip_masq_expire->tcp_fin_timeout; } else timeout = ip_masq_expire->tcp_timeout; skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0); tcp_send_check(th,iph->saddr,iph->daddr,size,skb); } ip_masq_set_expire(ms, timeout); ip_send_check(iph); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name); #endif return 0; }
int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) { struct sk_buff *skb = *skb_p; struct iphdr *iph = skb->h.iph; __u16 *portptr; struct ip_masq *ms; unsigned short len; unsigned long timeout; #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW struct ip_autofw *af; #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ switch (iph->protocol) { case IPPROTO_ICMP: return(ip_fw_demasq_icmp(skb_p, dev)); case IPPROTO_TCP: case IPPROTO_UDP: /* Make sure packet is in the masq range */ portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN || ntohs(portptr[1]) > PORT_MASQ_END) #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW && !ip_autofw_check_range(iph->saddr, portptr[1], iph->protocol, 0) && !ip_autofw_check_direct(portptr[1], iph->protocol) && !ip_autofw_check_port(portptr[1], iph->protocol) #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ ) return 0; /* Check that the checksum is OK */ len = ntohs(iph->tot_len) - (iph->ihl * 4); if ((iph->protocol == IPPROTO_UDP) && (portptr[3] == 0)) /* No UDP checksum */ break; switch (skb->ip_summed) { case CHECKSUM_NONE: skb->csum = csum_partial((char *)portptr, len, 0); case CHECKSUM_HW: if (csum_tcpudp_magic(iph->saddr, iph->daddr, len, iph->protocol, skb->csum)) { printk(KERN_DEBUG "MASQ: failed TCP/UDP checksum from %s!\n", in_ntoa(iph->saddr)); return -1; } default: /* CHECKSUM_UNNECESSARY */ } break; default: return 0; } #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Incoming %s %lX:%X -> %lX:%X\n", masq_proto_name(iph->protocol), ntohl(iph->saddr), ntohs(portptr[0]), ntohl(iph->daddr), ntohs(portptr[1])); #endif /* * reroute to original host:port if found... */ ms = ip_masq_in_get(iph); #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW if (ms == NULL && (af=ip_autofw_check_range(iph->saddr, portptr[1], iph->protocol, 0))) { #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_autofw_check_range\n"); #endif ms = ip_masq_new_enh(dev, iph->protocol, af->where, portptr[1], iph->saddr, portptr[0], 0, portptr[1]); } if ( ms == NULL && (af=ip_autofw_check_port(portptr[1], iph->protocol)) ) { #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_autofw_check_port\n"); #endif ms = ip_masq_new_enh(dev, iph->protocol, af->where, htons(af->hidden), iph->saddr, portptr[0], IP_MASQ_F_AFW_PORT, htons(af->visible)); } #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ if (ms != NULL) { #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW ip_autofw_update_in(iph->saddr, portptr[1], iph->protocol); #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ /* Stop the timer ticking.... */ ip_masq_set_expire(ms,0); /* * got reply, so clear flag */ ms->flags &= ~IP_MASQ_F_NO_REPLY; /* * Set dport if not defined yet. */ if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) { ms->flags &= ~IP_MASQ_F_NO_DPORT; ms->dport = portptr[0]; #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_fw_demasquerade(): filled dport=%d\n", ntohs(ms->dport)); #endif } if (ms->flags & IP_MASQ_F_NO_DADDR && ms->protocol == IPPROTO_TCP) { ms->flags &= ~IP_MASQ_F_NO_DADDR; ms->daddr = iph->saddr; #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_fw_demasquerade(): filled daddr=%X\n", ntohs(ms->daddr)); #endif } iph->daddr = ms->saddr; portptr[1] = ms->sport; /* * Attempt ip_masq_app call. * will fix ip_masq and iph ack_seq stuff */ if (ip_masq_app_pkt_in(ms, skb_p, dev) != 0) { /* * skb has changed, update pointers. */ skb = *skb_p; iph = skb->h.iph; portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); len = ntohs(iph->tot_len) - (iph->ihl * 4); } /* * Yug! adjust UDP/TCP and IP checksums, also update * timeouts. * If a TCP RST is seen collapse the tunnel (by using short timeout)! */ if (masq_proto_num(iph->protocol)==0) { recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len); timeout = ip_masq_expire->udp_timeout; } else { struct tcphdr *th; skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1), len - sizeof(struct tcphdr), 0); tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,len,skb); /* Check if TCP FIN or RST */ th = (struct tcphdr *)portptr; if (th->fin) { ms->flags |= IP_MASQ_F_SAW_FIN_IN; } if (th->rst) { ms->flags |= IP_MASQ_F_SAW_RST; } /* Now set the timeouts */ if (ms->flags & IP_MASQ_F_SAW_RST) { timeout = 1; } else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN) { timeout = ip_masq_expire->tcp_fin_timeout; } else timeout = ip_masq_expire->tcp_timeout; } ip_masq_set_expire(ms, timeout); ip_send_check(iph); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1])); #endif return 1; } /* sorry, all this trouble for a no-hit :) */ return 0; } /* * /proc/net entries */ #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW static int ip_autofw_procinfo(char *buffer, char **start, off_t offset, int length, int unused) { off_t pos=0, begin=0; struct ip_autofw * af; int len=0; len=sprintf(buffer,"Type Prot Low High Vis Hid Where Last CPto CPrt Timer Flags\n"); for(af = ip_autofw_hosts; af ; af = af->next) { len+=sprintf(buffer+len,"%4X %4X %04X-%04X/%04X %04X %08lX %08lX %04X %04X %6lu %4X\n", af->type, af->protocol, af->low, af->high, af->visible, af->hidden, ntohl(af->where), ntohl(af->lastcontact), af->ctlproto, af->ctlport, (af->timer.expires<jiffies ? 0 : af->timer.expires-jiffies), af->flags); pos=begin+len; if(pos<offset) { len=0; begin=pos; } if(pos>offset+length) break; } *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) len=length; return len; }
int ip_fw_demasq_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("MASQ: icmp in/rev (%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_ECHOREPLY) || (icmph->type == ICMP_TIMESTAMPREPLY) || (icmph->type == ICMP_INFO_REPLY) || (icmph->type == ICMP_ADDRESSREPLY)) { #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp reply rcv %lX->%lX id %d type %d, req %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type, icmp_type_request(icmph->type)); #endif ms = ip_masq_in_get_2(iph->protocol, iph->saddr, icmp_hv_rep(icmph), iph->daddr, icmp_id(icmph)); if (ms == NULL) return 0; ip_masq_set_expire(ms,0); /* * got reply, so clear flag */ ms->flags &= ~IP_MASQ_F_NO_REPLY; /* Reset source address */ iph->daddr = ms->saddr; /* Redo IP header checksum */ ip_send_check(iph); /* Set ID to fake port number */ (icmph->un).echo.id = ms->sport; /* Reset ICMP checksum and set expiry */ 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 reply rwt %lX->%lX id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type); #endif return 1; } else { #endif if ((icmph->type != ICMP_DEST_UNREACH) && (icmph->type != ICMP_SOURCE_QUENCH) && (icmph->type != ICMP_TIME_EXCEEDED)) return 0; #ifdef CONFIG_IP_MASQUERADE_ICMP } #endif /* * If we get here we have an ICMP error of one of the above 3 types * 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 * * First get a new ICMP header structure out of the IP packet */ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + (ciph->ihl<<2)); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: rv 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_in_get_2(ciph->protocol, ciph->daddr, icmp_hv_req(cicmph), ciph->saddr, icmp_id(cicmph)); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the dest IP address, and recalc checksum */ iph->daddr = ms->saddr; ip_send_check(iph); /* Now change the *source* address in the contained IP */ ciph->saddr = ms->saddr; ip_send_check(ciph); /* Change the ID to the original one! */ (cicmph->un).echo.id = ms->sport; /* 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: rv 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 - remember this packet was * *outgoing* so the ports are reversed (and addresses) */ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); if (ntohs(pptr[0]) < PORT_MASQ_BEGIN || ntohs(pptr[0]) > PORT_MASQ_END) return 0; /* Ensure the checksum is correct */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ printk(KERN_DEBUG "MASQ: reverse ICMP: failed checksum from %s!\n", in_ntoa(iph->saddr)); return(-1); } #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Handling reverse 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_in_get() does, except params are wrong way round */ ms = ip_masq_in_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 dest IP address, and recalc checksum */ iph->daddr = ms->saddr; ip_send_check(iph); /* Now change the *source* address in the contained IP */ ciph->saddr = ms->saddr; ip_send_check(ciph); /* the TCP/UDP source port - cannot redo check */ pptr[0] = ms->sport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Rewrote reverse 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 */ }