static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) { struct ip_conntrack *ct; struct ip_conntrack_tuple *t; enum ip_conntrack_info ctinfo; enum ip_conntrack_dir dir; unsigned long statusbit; ct = ip_conntrack_get(skb, &ctinfo); if (ct == NULL) return; dir = CTINFO2DIR(ctinfo); t = &ct->tuplehash[dir].tuple; if (dir == IP_CT_DIR_ORIGINAL) statusbit = IPS_DST_NAT; else statusbit = IPS_SRC_NAT; if (ct->status & statusbit) { fl->fl4_dst = t->dst.ip; if (t->dst.protonum == IPPROTO_TCP || t->dst.protonum == IPPROTO_UDP) fl->fl_ip_dport = t->dst.u.tcp.port; } statusbit ^= IPS_NAT_MASK; if (ct->status & statusbit) { fl->fl4_src = t->src.ip; if (t->dst.protonum == IPPROTO_TCP || t->dst.protonum == IPPROTO_UDP) fl->fl_ip_sport = t->src.u.tcp.port; } }
static unsigned int ipt_dnat_target(struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, unsigned int hooknum, const void *targinfo, void *userinfo) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; const struct ip_nat_multi_range_compat *mr = targinfo; IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT); ct = ip_conntrack_get(*pskb, &ctinfo); /* Connection must be valid and new. */ IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); if (hooknum == NF_IP_LOCAL_OUT && mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) warn_if_extra_mangle((*pskb)->nh.iph->daddr, mr->range[0].min_ip); return ip_nat_setup_info(ct, &mr->range[0], hooknum); }
static unsigned int ip_nat_local_fn(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; unsigned int ret; /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) return NF_ACCEPT; ret = ip_nat_fn(hooknum, pskb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.dst.ip != ct->tuplehash[!dir].tuple.src.ip #ifdef CONFIG_XFRM || ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[!dir].tuple.src.u.all #endif ) if (ip_route_me_harder(pskb, RTN_UNSPEC)) ret = NF_DROP; } return ret; }
static u_int32_t get_led(struct sk_buff **pskb, const struct ipt_led_info *ledinfo) { #ifdef CONFIG_IP_NF_CONNTRACK enum ip_conntrack_info ctinfo; struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); #endif switch (ledinfo->mode) { case IPT_LED_SAVE: #ifdef CONFIG_IP_NF_CONNTRACK if (ct) ct->led = ledinfo->led; #endif /* fallthrough */ case IPT_LED_SET: return ledinfo->led; case IPT_LED_RESTORE: #ifdef CONFIG_IP_NF_CONNTRACK if (ct) return ct->led; #endif /* fallthrough */ default: return LEDMAN_MAX; } }
static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop) { const struct ipt_bcount_match *info = matchinfo; struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); if (!ct) return !info->invert; return ((ct->bcount >= info->min) && (ct->bcount <= info->max)) ^ info->invert; }
static int set_addr(struct sk_buff **pskb, unsigned char **data, int dataoff, unsigned int addroff, __be32 ip, u_int16_t port) { enum ip_conntrack_info ctinfo; struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo); struct { __be32 ip; __be16 port; } __attribute__ ((__packed__)) buf; struct tcphdr _tcph, *th; buf.ip = ip; buf.port = htons(port); addroff += dataoff; if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) { if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, addroff, sizeof(buf), (char *) &buf, sizeof(buf))) { if (net_ratelimit()) printk("ip_nat_h323: ip_nat_mangle_tcp_packet" " error\n"); return -1; } /* Relocate data pointer */ th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, sizeof(_tcph), &_tcph); if (th == NULL) return -1; *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + th->doff * 4 + dataoff; } else { if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addroff, sizeof(buf), (char *) &buf, sizeof(buf))) { if (net_ratelimit()) printk("ip_nat_h323: ip_nat_mangle_udp_packet" " error\n"); return -1; } /* ip_nat_mangle_udp_packet uses skb_make_writable() to copy * or pull everything in a linear buffer, so we can safely * use the skb pointers now */ *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + sizeof(struct udphdr); } return 0; }
static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, int offset, int *hotdrop) { const struct ipt_helper_info *info = matchinfo; struct ip_conntrack_expect *exp; struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; int ret = info->invert; ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); if (!ct) { DEBUGP("ipt_helper: Eek! invalid conntrack?\n"); return ret; } if (!ct->master) { DEBUGP("ipt_helper: conntrack %p has no master\n", ct); return ret; } exp = ct->master; READ_LOCK(&ip_conntrack_lock); if (!exp->expectant) { DEBUGP("ipt_helper: expectation %p without expectant !?!\n", exp); goto out_unlock; } if (!exp->expectant->helper) { DEBUGP("ipt_helper: master ct %p has no helper\n", exp->expectant); goto out_unlock; } DEBUGP("master's name = %s , info->name = %s\n", exp->expectant->helper->name, info->name); if (info->name[0] == '\0') ret ^= 1; else ret ^= !strncmp(exp->expectant->helper->name, info->name, strlen(exp->expectant->helper->name)); out_unlock: READ_UNLOCK(&ip_conntrack_lock); return ret; }
static unsigned int target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *targinfo, void *userinfo) { enum ip_conntrack_info ctinfo; struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); if (ct) set_bit(IPS_LOG_BIT, &ct->status); return IPT_CONTINUE; }
static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop) { const struct ipt_connmark_info *info = matchinfo; enum ip_conntrack_info ctinfo; struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); if (!ct) return 0; return ((ct->mark & info->mask) == info->mark) ^ info->invert; }
static unsigned int ip_nat_adjust(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; ct = ip_conntrack_get(*pskb, &ctinfo); if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { DEBUGP("ip_nat_standalone: adjusting sequence number\n"); if (!ip_nat_seq_adjust(pskb, ct, ctinfo)) return NF_DROP; } return NF_ACCEPT; }
static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, int offset, int *hotdrop) { const struct ipt_state_info *sinfo = matchinfo; enum ip_conntrack_info ctinfo; unsigned int statebit; if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) statebit = IPT_STATE_INVALID; else statebit = IPT_STATE_BIT(ctinfo); return (sinfo->statemask & statebit); }
static unsigned int ip_confirm(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; /* This is where we call the helper: as the packet goes out. */ ct = ip_conntrack_get(*pskb, &ctinfo); if (ct && ct->helper) { unsigned int ret; ret = ct->helper->help(pskb, ct, ctinfo); if (ret != NF_ACCEPT) return ret; } /* We've seen it coming out the other side: confirm it */ return ip_conntrack_confirm(pskb); }
static unsigned int target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *targinfo, void *userinfo) { const struct ipt_connmark_target_info *markinfo = targinfo; unsigned long diff; unsigned long nfmark; unsigned long newmark; enum ip_conntrack_info ctinfo; struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); if (ct) { switch(markinfo->mode) { case IPT_CONNMARK_SET: newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; if (newmark != ct->mark) ct->mark = newmark; break; case IPT_CONNMARK_SAVE: newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask); if (ct->mark != newmark) ct->mark = newmark; break; case IPT_CONNMARK_RESTORE: nfmark = (*pskb)->nfmark; diff = (ct->mark ^ nfmark & markinfo->mask); if (diff != 0) { (*pskb)->nfmark = nfmark ^ diff; (*pskb)->nfcache |= NFC_ALTERED; } break; } } return IPT_CONTINUE; }
/* Source NAT */ static unsigned int ipt_snat_target(struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, unsigned int hooknum, const void *targinfo, void *userinfo) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; const struct ip_nat_multi_range_compat *mr = targinfo; IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); ct = ip_conntrack_get(*pskb, &ctinfo); /* Connection must be valid and new. */ IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); IP_NF_ASSERT(out); return ip_nat_setup_info(ct, &mr->range[0], hooknum); }
static unsigned int ip_nat_fn(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; struct ip_nat_info *info; /* maniptype == SRC for postrouting. */ enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum); /* We never see fragments: conntrack defrags on pre-routing and local-out, and ip_nat_out protects post-routing. */ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET))); (*pskb)->nfcache |= NFC_UNKNOWN; /* If we had a hardware checksum before, it's now invalid */ if ((*pskb)->ip_summed == CHECKSUM_HW) if (skb_checksum_help(*pskb, (out == NULL))) return NF_DROP; ct = ip_conntrack_get(*pskb, &ctinfo); /* Can't track? It's not due to stress, or conntrack would have dropped it. Hence it's the user's responsibilty to packet filter it out, or implement conntrack/NAT for that protocol. 8) --RR */ if (!ct) { /* Exception: ICMP redirect to new connection (not in hash table yet). We must not let this through, in case we're doing NAT to the same network. */ if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { struct icmphdr _hdr, *hp; hp = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, sizeof(_hdr), &_hdr); if (hp != NULL && hp->type == ICMP_REDIRECT) return NF_DROP; } return NF_ACCEPT; } switch (ctinfo) { case IP_CT_RELATED: case IP_CT_RELATED+IP_CT_IS_REPLY: if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { if (!icmp_reply_translation(pskb, ct, maniptype, CTINFO2DIR(ctinfo))) return NF_DROP; else return NF_ACCEPT; } /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ case IP_CT_NEW: info = &ct->nat.info; /* Seen it before? This can happen for loopback, retrans, or local packets.. */ if (!ip_nat_initialized(ct, maniptype)) { unsigned int ret; /* LOCAL_IN hook doesn't have a chain! */ if (hooknum == NF_IP_LOCAL_IN) ret = alloc_null_binding(ct, info, hooknum); else ret = ip_nat_rule_find(pskb, hooknum, in, out, ct, info); if (ret != NF_ACCEPT) { return ret; } } else DEBUGP("Already setup manip %s for ct %p\n", maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", ct); break; default: /* ESTABLISHED */ IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); info = &ct->nat.info; } IP_NF_ASSERT(info); return nat_packet(ct, ctinfo, hooknum, pskb); }
static unsigned int ip_nat_fn(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; struct ip_nat_info *info; /* maniptype == SRC for postrouting. */ enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum); /* We never see fragments: conntrack defrags on pre-routing and local-out, and ip_nat_out protects post-routing. */ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET))); (*pskb)->nfcache |= NFC_UNKNOWN; /* If we had a hardware checksum before, it's now invalid */ if ((*pskb)->ip_summed == CHECKSUM_HW) (*pskb)->ip_summed = CHECKSUM_NONE; ct = ip_conntrack_get(*pskb, &ctinfo); /* Can't track? It's not due to stress, or conntrack would have dropped it. Hence it's the user's responsibilty to packet filter it out, or implement conntrack/NAT for that protocol. 8) --RR */ if (!ct) { /* Exception: ICMP redirect to new connection (not in hash table yet). We must not let this through, in case we're doing NAT to the same network. */ struct iphdr *iph = (*pskb)->nh.iph; struct icmphdr *hdr = (struct icmphdr *) ((u_int32_t *)iph + iph->ihl); if (iph->protocol == IPPROTO_ICMP && hdr->type == ICMP_REDIRECT) return NF_DROP; return NF_ACCEPT; } switch (ctinfo) { case IP_CT_RELATED: case IP_CT_RELATED+IP_CT_IS_REPLY: if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { return icmp_reply_translation(*pskb, ct, hooknum, CTINFO2DIR(ctinfo)); } /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ case IP_CT_NEW: #ifdef CONFIG_IP_NF_NAT_LOCAL /* LOCAL_IN hook doesn't have a chain and thus doesn't care * about new packets -HW */ if (hooknum == NF_IP_LOCAL_IN) return NF_ACCEPT; #endif info = &ct->nat.info; WRITE_LOCK(&ip_nat_lock); /* Seen it before? This can happen for loopback, retrans, or local packets.. */ if (!(info->initialized & (1 << maniptype))) { int in_hashes = info->initialized; unsigned int ret; if (ct->master && master_ct(ct)->nat.info.helper && master_ct(ct)->nat.info.helper->expect) { ret = call_expect(master_ct(ct), pskb, hooknum, ct, info); } else { ret = ip_nat_rule_find(pskb, hooknum, in, out, ct, info); } if (ret != NF_ACCEPT) { WRITE_UNLOCK(&ip_nat_lock); return ret; } if (in_hashes) { IP_NF_ASSERT(info->bysource.conntrack); replace_in_hashes(ct, info); } else { place_in_hashes(ct, info); } } else DEBUGP("Already setup manip %s for ct %p\n", maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", ct); WRITE_UNLOCK(&ip_nat_lock); break; default: /* ESTABLISHED */ IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); info = &ct->nat.info; } IP_NF_ASSERT(info); return do_bindings(ct, ctinfo, info, hooknum, pskb); }
static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, int offset, unsigned int protoff, int *hotdrop) { const struct xt_conntrack_info *sinfo = matchinfo; struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; unsigned int statebit; ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) if (ct == &ip_conntrack_untracked) statebit = XT_CONNTRACK_STATE_UNTRACKED; else if (ct) statebit = XT_CONNTRACK_STATE_BIT(ctinfo); else statebit = XT_CONNTRACK_STATE_INVALID; if(sinfo->flags & XT_CONNTRACK_STATE) { if (ct) { if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) statebit |= XT_CONNTRACK_STATE_SNAT; if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip) statebit |= XT_CONNTRACK_STATE_DNAT; } if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE)) return 0; } if(sinfo->flags & XT_CONNTRACK_PROTO) { if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO)) return 0; } if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC)) return 0; } if(sinfo->flags & XT_CONNTRACK_ORIGDST) { if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST)) return 0; } if(sinfo->flags & XT_CONNTRACK_REPLSRC) { if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC)) return 0; } if(sinfo->flags & XT_CONNTRACK_REPLDST) { if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST)) return 0; } if(sinfo->flags & XT_CONNTRACK_STATUS) { if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS)) return 0; } if(sinfo->flags & XT_CONNTRACK_EXPIRES) { unsigned long expires; if(!ct) return 0; expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES)) return 0; } return 1; }
static unsigned int napt_handle(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn) (struct sk_buff *)) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; uint8_t *saddr, *daddr, *ssaddr, *sdaddr, *tsaddr, *tdaddr; uint32_t usaddr, udaddr, usport, udport, tusaddr, tusport; struct iphdr *iph = (*pskb)->nh.iph; struct udphdr *uh = ((struct udphdr *) (*pskb)->h.uh + 20); struct tftphdr *tftph = ((struct tftphdr *) (*pskb)->h.uh + 28); fal_napt_entry_t napt_entry; saddr = (uint8_t *) & iph->saddr; daddr = (uint8_t *) & iph->daddr; if (daddr[0] == 255) return NF_ACCEPT; ct = ip_conntrack_get(*pskb, &ctinfo); if (!ct) return NF_ACCEPT; if (((ct->status & IPS_NAT_MASK) != IPS_SRC_NAT) &&((ct->status & IPS_NAT_MASK) != IPS_DST_NAT)) return NF_ACCEPT; ssaddr = (uint8_t *) (&ct->tuplehash[0].tuple.src.ip); tsaddr = (uint8_t *) (&ct->tuplehash[0].tuple.dst.ip); sdaddr = (uint8_t *) (&ct->tuplehash[1].tuple.src.ip); tdaddr = (uint8_t *) (&ct->tuplehash[1].tuple.dst.ip); if ((ct->status & IPS_NAT_MASK) == IPS_SRC_NAT) { //snat usaddr = ct->tuplehash[0].tuple.src.ip; usport = ct->tuplehash[0].tuple.src.u.all; udaddr = ct->tuplehash[0].tuple.dst.ip; udport = ct->tuplehash[0].tuple.dst.u.all; tusaddr = ct->tuplehash[1].tuple.dst.ip; tusport = ct->tuplehash[1].tuple.dst.u.all; } else { //dnat usaddr = ct->tuplehash[1].tuple.src.ip; usport = ct->tuplehash[1].tuple.src.u.all; udaddr = ct->tuplehash[1].tuple.dst.ip; udport = ct->tuplehash[1].tuple.dst.u.all; tusaddr = ct->tuplehash[0].tuple.dst.ip; tusport = ct->tuplehash[0].tuple.dst.u.all; } if (iph->protocol == P_TCP) { //IPS_SRC_NAT IPS_DST_NAT if ((ct->proto.tcp.state == TCP_CONNTRACK_SYN_RECV) || (ct->proto.tcp.state == TCP_CONNTRACK_CLOSE)) { memset((void *) &napt_entry, 0, sizeof (fal_napt_entry_t)); napt_entry.counter_en = 1; napt_entry.counter_id = debug_counter; if(++debug_counter == 8) debug_counter = 0; napt_entry.flags = FAL_NAT_ENTRY_PROTOCOL_TCP | FAL_NAT_ENTRY_TRANS_IPADDR_INDEX; napt_entry.src_addr = usaddr; napt_entry.src_port = usport; napt_entry.dst_addr = udaddr; napt_entry.dst_port = udport; napt_entry.trans_addr = public_ip_add(tusaddr); napt_entry.trans_port = tusport; napt_entry.status = NAPT_AGE; } if (!ct->helper) { if (ct->proto.tcp.state == TCP_CONNTRACK_SYN_RECV) { printk("isis_napt_add####(pub:%x)####\n", napt_entry.trans_addr); isis_napt_add(0, &napt_entry); napt_death(ct, &napt_entry); } else if (ct->proto.tcp.state == TCP_CONNTRACK_CLOSE) { printk("isis_napt_del########\n"); /*if hw nat work, we recv the close any more*/ isis_napt_del(0, FAL_NAT_ENTRY_ID_EN, &napt_entry); } } else if (ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) { /*need kernel support ip_conntrack_pptp.ko and ip_nat_pptp.ko*/ if (!strcmp(ct->helper->name, "pptp")) { printk ("PPTP Session state %d, Call state %d, PAC Call ID %d to %d, PNS Call ID %d to %d\n", ct->help.ct_pptp_info.sstate, ct->help.ct_pptp_info.cstate, ntohs(ct->help.ct_pptp_info.pac_call_id), ntohs(ct->nat.help.nat_pptp_info.pac_call_id), ntohs(ct->help.ct_pptp_info.pns_call_id), ntohs(ct->nat.help.nat_pptp_info.pns_call_id)); if (((ct->help.ct_pptp_info.sstate == PPTP_SESSION_CONFIRMED) && (ct->help.ct_pptp_info.cstate == PPTP_CALL_OUT_REQ)) || (ct->help.ct_pptp_info.sstate == PPTP_SESSION_STOPREQ)) { memset((void *) &napt_entry, 0, sizeof (fal_napt_entry_t)); napt_entry.counter_en = 1; napt_entry.counter_id = debug_counter; if(++debug_counter == 8) debug_counter = 0; napt_entry.flags = FAL_NAT_ENTRY_PROTOCOL_PPTP | FAL_NAT_ENTRY_TRANS_IPADDR_INDEX; napt_entry.src_addr = usaddr; napt_entry.src_port = ct->help.ct_pptp_info.pns_call_id; napt_entry.dst_addr = udaddr; napt_entry.dst_port = 0; napt_entry.trans_addr = 15; napt_entry.trans_port = ct->nat.help.nat_pptp_info.pns_call_id; napt_entry.status = NAPT_AGE; } if ((ct->help.ct_pptp_info.sstate == PPTP_SESSION_CONFIRMED) && (ct->help.ct_pptp_info.cstate == PPTP_CALL_OUT_REQ)) { printk("pptp_isis_napt_add########\n"); isis_napt_add(0, &napt_entry); napt_death(ct, &napt_entry); } else if (ct->help.ct_pptp_info.sstate == PPTP_SESSION_STOPREQ) { printk("pptp_isis_napt_del########\n"); /*if hw nat work, we recv the close any more*/ isis_napt_del(0, FAL_NAT_ENTRY_ID_EN, &napt_entry); } } } } else if (iph->protocol == P_UDP) { /*need kernel support ip_conntrack_tftp.ko and ip_nat_tftp.ko*/ if (ct->master && ct->master->helper && !strcmp(ct->master->helper->name, "tftp")) { if ((ct->status == 0x191 || ct->status == 0x1a1) || ((ntohs(uh->len) - 12 < 512) && (ntohs(tftph->opcode) == TFTP_OPCODE_DATA))) { memset((void *) &napt_entry, 0, sizeof (fal_napt_entry_t)); napt_entry.counter_en = 1; napt_entry.counter_id = debug_counter; if(++debug_counter == 8) debug_counter = 0; napt_entry.flags = FAL_NAT_ENTRY_PROTOCOL_UDP | FAL_NAT_ENTRY_TRANS_IPADDR_INDEX; napt_entry.src_addr = usaddr; napt_entry.src_port = usport; napt_entry.dst_addr = udaddr; napt_entry.dst_port = udport; napt_entry.trans_addr = 15; napt_entry.trans_port = tusport; napt_entry.status = NAPT_AGE; } if (ct->status == 0x191 || ct->status == 0x1a1) { //add printk("tftp_isis_napt_add########\n"); isis_napt_add(0, &napt_entry); napt_death(ct, &napt_entry); } else if ((ntohs(uh->len) - 12 < 512) && (ntohs(tftph->opcode) == TFTP_OPCODE_DATA)) { //del printk("tftp_isis_napt_del########\n"); /*if hw nat work, we recv the close any more*/ isis_napt_del(0, FAL_NAT_ENTRY_ID_EN, &napt_entry); } } } return NF_ACCEPT; }
static unsigned int ip_nat_fn(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; struct ip_nat_info *info; /* maniptype == SRC for postrouting. */ enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum); /* jimmy added 20080324 */ struct sip_rtp_binding *sip_rtp_binding_tmp = NULL; /* --------------------------------- */ /* We never see fragments: conntrack defrags on pre-routing and local-out, and ip_nat_out protects post-routing. */ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET))); /* If we had a hardware checksum before, it's now invalid */ if ((*pskb)->ip_summed == CHECKSUM_HW) if (skb_checksum_help(*pskb, (out == NULL))) return NF_DROP; ct = ip_conntrack_get(*pskb, &ctinfo); /* Can't track? It's not due to stress, or conntrack would have dropped it. Hence it's the user's responsibilty to packet filter it out, or implement conntrack/NAT for that protocol. 8) --RR */ if (!ct) { /* Exception: ICMP redirect to new connection (not in hash table yet). We must not let this through, in case we're doing NAT to the same network. */ if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { struct icmphdr _hdr, *hp; hp = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, sizeof(_hdr), &_hdr); if (hp != NULL && hp->type == ICMP_REDIRECT) return NF_DROP; } return NF_ACCEPT; } /* Don't try to NAT if this packet is not conntracked */ if (ct == &ip_conntrack_untracked) return NF_ACCEPT; switch (ctinfo) { case IP_CT_RELATED: case IP_CT_RELATED+IP_CT_IS_REPLY: if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { if (!ip_nat_icmp_reply_translation(pskb, ct, maniptype, CTINFO2DIR(ctinfo))) return NF_DROP; else return NF_ACCEPT; } /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ case IP_CT_NEW: info = &ct->nat.info; /* Seen it before? This can happen for loopback, retrans, or local packets.. */ if (!ip_nat_initialized(ct, maniptype)) { unsigned int ret; if (unlikely(is_confirmed(ct))) /* NAT module was loaded late */ ret = alloc_null_binding_confirmed(ct, info, hooknum); else if (hooknum == NF_IP_LOCAL_IN) /* LOCAL_IN hook doesn't have a chain! */ ret = alloc_null_binding(ct, info, hooknum); else{ ret = ip_nat_rule_find(pskb, hooknum, in, out, ct, info); /* jimmy added 20080324 */ if((hooknum == NF_IP_POST_ROUTING) && ((*pskb)->nh.iph->protocol == IPPROTO_UDP)){ sip_rtp_binding_tmp = sip_rtp_binding_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip); if(sip_rtp_binding_tmp){ /* jimmy added 20080328, for avoid sip pattern 100 run through in */ if( sip_rtp_binding_tmp->wan_uac_port && (ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all == sip_rtp_binding_tmp->wan_uac_port)){ /* ----------------------------------------------- */ if(sip_rtp_binding_tmp->router_port && sip_rtp_binding_tmp->router_ip && (sip_rtp_binding_tmp->router_ip == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) && (sip_rtp_binding_tmp->router_port != ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all)){ write_lock_bh(&ip_conntrack_lock); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all = sip_rtp_binding_tmp->router_port; write_unlock_bh(&ip_conntrack_lock); DEBUGP("After modified conntrack for sip incoming conntrack hash, this ct are\n"); DEBUGP("[IP_CT_DIR_REPLY] : %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum, NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip), ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all), NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all)); DEBUGP("[IP_CT_DIR_ORIGINAL] : %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum, NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all), NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all)); } /* jimmy added 20080328, for avoid sip pattern 100 */ } /* ----------------------------------------------- */ } } /* ---------------------- */ } if (ret != NF_ACCEPT) { return ret; } } else DEBUGP("Already setup manip %s for ct %p\n", maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", ct); break; default: /* ESTABLISHED */ IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); info = &ct->nat.info; } IP_NF_ASSERT(info); return ip_nat_packet(ct, ctinfo, hooknum, pskb); }
static unsigned int ip_nat_fn(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; struct ip_nat_info *info; /* maniptype == SRC for postrouting. */ enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum); /* We never see fragments: conntrack defrags on pre-routing and local-out, and ip_nat_out protects post-routing. */ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET))); (*pskb)->nfcache |= NFC_UNKNOWN; /* If we had a hardware checksum before, it's now invalid */ if ((*pskb)->pkt_type != PACKET_LOOPBACK) (*pskb)->ip_summed = CHECKSUM_NONE; ct = ip_conntrack_get(*pskb, &ctinfo); /* Can't track? Maybe out of memory: this would make NAT unreliable. */ if (!ct) { if (net_ratelimit()) printk(KERN_DEBUG "NAT: %u dropping untracked packet %p %u %u.%u.%u.%u -> %u.%u.%u.%u\n", hooknum, *pskb, (*pskb)->nh.iph->protocol, NIPQUAD((*pskb)->nh.iph->saddr), NIPQUAD((*pskb)->nh.iph->daddr)); return NF_DROP; } switch (ctinfo) { case IP_CT_RELATED: case IP_CT_RELATED+IP_CT_IS_REPLY: if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { return icmp_reply_translation(*pskb, ct, hooknum, CTINFO2DIR(ctinfo)); } /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ case IP_CT_NEW: info = &ct->nat.info; WRITE_LOCK(&ip_nat_lock); /* Seen it before? This can happen for loopback, retrans, or local packets.. */ if (!(info->initialized & (1 << maniptype))) { int in_hashes = info->initialized; unsigned int ret; ret = ip_nat_rule_find(pskb, hooknum, in, out, ct, info); if (ret != NF_ACCEPT) { WRITE_UNLOCK(&ip_nat_lock); return ret; } if (in_hashes) { IP_NF_ASSERT(info->bysource.conntrack); replace_in_hashes(ct, info); } else { place_in_hashes(ct, info); } } else DEBUGP("Already setup manip %s for ct %p\n", maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", ct); WRITE_UNLOCK(&ip_nat_lock); break; default: /* ESTABLISHED */ IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); info = &ct->nat.info; } IP_NF_ASSERT(info); return do_bindings(ct, ctinfo, info, hooknum, pskb); }