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); }
static int ip_masq_user_info(char *buffer, char **start, off_t offset, int length, int proto) { off_t pos=0, begin; struct ip_masq *ms; char temp[129]; int idx = 0; int len=0; int magic_control; MOD_INC_USE_COUNT; IP_MASQ_DEBUG(1-debug, "Entered user_info with proto=%d\n", proto); if (offset < 128) { sprintf(temp, "Prot SrcIP SPrt DstIP DPrt MAddr MPrt State Flgs Ref Ctl Expires (free=%d,%d,%d)", atomic_read(ip_masq_free_ports), atomic_read(ip_masq_free_ports+1), atomic_read(ip_masq_free_ports+2)); len = sprintf(buffer, "%-127s\n", temp); } pos = 128; for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) { /* * Lock is actually only need in next loop * we are called from uspace: must stop bh. */ read_lock_bh(&__ip_masq_lock); for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link) { if (ms->protocol != proto) { continue; } pos += 128; if (pos <= offset) { len = 0; continue; } /* * We have locked the tables, no need to del/add timers * nor cli() 8) */ magic_control = atomic_read(&ms->n_control); if (!magic_control && ms->control) magic_control = -1; sprintf(temp,"%-4s %08lX:%04X %08lX:%04X %08lX:%04X %-12s %3X %4d %3d %7lu", masq_proto_name(ms->protocol), ntohl(ms->saddr), ntohs(ms->sport), ntohl(ms->daddr), ntohs(ms->dport), ntohl(ms->maddr), ntohs(ms->mport), ip_masq_state_name(ms->state), ms->flags, atomic_read(&ms->refcnt), magic_control, (ms->timer.expires-jiffies)/HZ); len += sprintf(buffer+len, "%-127s\n", temp); if(len >= length) { read_unlock_bh(&__ip_masq_lock); goto done; } } read_unlock_bh(&__ip_masq_lock); } done: if (len) { begin = len - (pos - offset); *start = buffer + begin; len -= begin; } if(len>length) len = length; MOD_DEC_USE_COUNT; return len; }
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; }
struct ip_masq * ip_masq_new_enh(struct device *dev, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags, __u16 matchport) { struct ip_masq *ms, *mst; int ports_tried, *free_ports_p; unsigned long flags; static int n_fails = 0; free_ports_p = &ip_masq_free_ports[masq_proto_num(proto)]; if (*free_ports_p == 0) { if (++n_fails < 5) printk("ip_masq_new(proto=%s): no free ports.\n", masq_proto_name(proto)); return NULL; } ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC); if (ms == NULL) { if (++n_fails < 5) printk("ip_masq_new(proto=%s): no memory available.\n", masq_proto_name(proto)); return NULL; } memset(ms, 0, sizeof(*ms)); init_timer(&ms->timer); ms->timer.data = (unsigned long)ms; ms->timer.function = masq_expire; ms->protocol = proto; ms->saddr = saddr; ms->sport = sport; ms->daddr = daddr; ms->dport = dport; ms->flags = mflags; ms->app_data = NULL; ms->control = NULL; if (proto == IPPROTO_UDP && !matchport) ms->flags |= IP_MASQ_F_NO_DADDR; /* get masq address from rif */ ms->maddr = dev->pa_addr; /* * Setup new entry as not replied yet. * This flag will allow masq. addr (ms->maddr) * to follow forwarding interface address. */ ms->flags |= IP_MASQ_F_NO_REPLY; for (ports_tried = 0; (*free_ports_p && (ports_tried <= (PORT_MASQ_END - PORT_MASQ_BEGIN))); ports_tried++){ save_flags(flags); cli(); /* * Try the next available port number */ if (!matchport || ports_tried) ms->mport = htons(masq_port++); else ms->mport = matchport; if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN; restore_flags(flags); /* * lookup to find out if this port is used. */ mst = ip_masq_getbym(proto, ms->maddr, ms->mport); if (mst == NULL || matchport) { save_flags(flags); cli(); if (*free_ports_p == 0) { restore_flags(flags); break; } (*free_ports_p)--; ip_masq_hash(ms); restore_flags(flags); if (proto != IPPROTO_ICMP) ip_masq_bind_app(ms); n_fails = 0; return ms; } } if (++n_fails < 5) printk("ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n", masq_proto_name(ms->protocol), *free_ports_p); kfree_s(ms, sizeof(*ms)); return NULL; }
static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset, int length, int unused) { off_t pos=0, begin; struct ip_masq *ms; unsigned long flags; char temp[129]; int idx = 0; int len=0; if (offset < 128) { #ifdef CONFIG_IP_MASQUERADE_ICMP sprintf(temp, "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d,%d)", ip_masq_free_ports[0], ip_masq_free_ports[1], ip_masq_free_ports[2]); #else /* !defined(CONFIG_IP_MASQUERADE_ICMP) */ sprintf(temp, "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d)", ip_masq_free_ports[0], ip_masq_free_ports[1]); #endif /* CONFIG_IP_MASQUERADE_ICMP */ len = sprintf(buffer, "%-127s\n", temp); } pos = 128; save_flags(flags); cli(); for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link) { int timer_active; pos += 128; if (pos <= offset) continue; timer_active = del_timer(&ms->timer); if (!timer_active) ms->timer.expires = jiffies; sprintf(temp,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %7lu", masq_proto_name(ms->protocol), ntohl(ms->saddr), ntohs(ms->sport), ntohl(ms->daddr), ntohs(ms->dport), ntohs(ms->mport), ms->out_seq.init_seq, ms->out_seq.delta, ms->out_seq.previous_delta, ms->timer.expires-jiffies); if (timer_active) add_timer(&ms->timer); len += sprintf(buffer+len, "%-127s\n", temp); if(len >= length) goto done; } done: restore_flags(flags); begin = len - (pos - offset); *start = buffer + begin; len -= begin; if(len>length) len = length; return len; }
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; }