?? ip_nat_core.c
字號:
conntrack->tuplehash[IP_CT_DIR_ORIGINAL] .tuple.dst.protonum); /* We place packet as seen OUTGOUNG in byips_proto hash (ie. reverse dst and src of reply packet. */ unsigned int ipsprotohash = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY] .tuple.dst.ip, conntrack->tuplehash[IP_CT_DIR_REPLY] .tuple.src.ip, conntrack->tuplehash[IP_CT_DIR_REPLY] .tuple.dst.protonum); IP_NF_ASSERT(!info->bysource.conntrack); MUST_BE_WRITE_LOCKED(&ip_nat_lock); info->byipsproto.conntrack = conntrack; info->bysource.conntrack = conntrack; list_prepend(&bysource[srchash], &info->bysource); list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);}/* Returns true if succeeded. */static intmanip_pkt(u_int16_t proto, struct sk_buff **pskb, unsigned int iphdroff, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype){ struct iphdr *iph; (*pskb)->nfcache |= NFC_ALTERED; if (!skb_ip_make_writable(pskb, iphdroff+sizeof(iph))) return 0; iph = (void *)(*pskb)->data + iphdroff; /* Manipulate protcol part. */ if (!find_nat_proto(proto)->manip_pkt(pskb, iphdroff + iph->ihl*4, manip, maniptype)) return 0; iph = (void *)(*pskb)->data + iphdroff; if (maniptype == IP_NAT_MANIP_SRC) { iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip, iph->check); iph->saddr = manip->ip; } else { iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip, iph->check); iph->daddr = manip->ip; } return 1;}static inline int exp_for_packet(struct ip_conntrack_expect *exp, struct sk_buff *skb){ struct ip_conntrack_protocol *proto; int ret = 1; MUST_BE_READ_LOCKED(&ip_conntrack_lock); proto = __ip_ct_find_proto(skb->nh.iph->protocol); if (proto->exp_matches_pkt) ret = proto->exp_matches_pkt(exp, skb); return ret;}/* Do packet manipulations according to binding. */unsigned intdo_bindings(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, struct ip_nat_info *info, unsigned int hooknum, struct sk_buff **pskb){ unsigned int i; struct ip_nat_helper *helper; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); int proto = (*pskb)->nh.iph->protocol; /* Need nat lock to protect against modification, but neither conntrack (referenced) and helper (deleted with synchronize_bh()) can vanish. */ READ_LOCK(&ip_nat_lock); for (i = 0; i < info->num_manips; i++) { if (info->manips[i].direction == dir && info->manips[i].hooknum == hooknum) { DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n", *pskb, info->manips[i].maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", NIPQUAD(info->manips[i].manip.ip), htons(info->manips[i].manip.u.all)); if (!manip_pkt(proto, pskb, 0, &info->manips[i].manip, info->manips[i].maniptype)) { READ_UNLOCK(&ip_nat_lock); return NF_DROP; } } } helper = info->helper; READ_UNLOCK(&ip_nat_lock); if (helper) { struct ip_conntrack_expect *exp = NULL; struct list_head *cur_item; int ret = NF_ACCEPT; int helper_called = 0; DEBUGP("do_bindings: helper existing for (%p)\n", ct); /* Always defragged for helpers */ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET))); /* Have to grab read lock before sibling_list traversal */ READ_LOCK(&ip_conntrack_lock); list_for_each_prev(cur_item, &ct->sibling_list) { exp = list_entry(cur_item, struct ip_conntrack_expect, expected_list); /* if this expectation is already established, skip */ if (exp->sibling) continue; if (exp_for_packet(exp, *pskb)) { /* FIXME: May be true multiple times in the * case of UDP!! */ DEBUGP("calling nat helper (exp=%p) for packet\n", exp); ret = helper->help(ct, exp, info, ctinfo, hooknum, pskb); if (ret != NF_ACCEPT) { READ_UNLOCK(&ip_conntrack_lock); return ret; } helper_called = 1; } } /* Helper might want to manip the packet even when there is no * matching expectation for this packet */ if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) { DEBUGP("calling nat helper for packet without expectation\n"); ret = helper->help(ct, NULL, info, ctinfo, hooknum, pskb); if (ret != NF_ACCEPT) { READ_UNLOCK(&ip_conntrack_lock); return ret; } } READ_UNLOCK(&ip_conntrack_lock); /* Adjust sequence number only once per packet * (helper is called at all hooks) */ if (proto == IPPROTO_TCP && (hooknum == NF_IP_POST_ROUTING || hooknum == NF_IP_LOCAL_IN)) { DEBUGP("ip_nat_core: adjusting sequence number\n"); /* future: put this in a l4-proto specific function, * and call this function here. */ if (!ip_nat_seq_adjust(pskb, ct, ctinfo)) ret = NF_DROP; } return ret; } else return NF_ACCEPT; /* not reached */}inticmp_reply_translation(struct sk_buff **pskb, struct ip_conntrack *conntrack, unsigned int hooknum, int dir){ struct { struct icmphdr icmp; struct iphdr ip; } *inside; unsigned int i; struct ip_nat_info *info = &conntrack->nat.info; int hdrlen; if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside))) return 0; inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; /* We're actually going to mangle it beyond trivial checksum adjustment, so make sure the current checksum is correct. */ if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) { hdrlen = (*pskb)->nh.iph->ihl * 4; if ((u16)csum_fold(skb_checksum(*pskb, hdrlen, (*pskb)->len - hdrlen, 0))) return 0; } /* Must be RELATED */ IP_NF_ASSERT((*pskb)->nfct - ((struct ip_conntrack *)(*pskb)->nfct->master)->infos == IP_CT_RELATED || (*pskb)->nfct - ((struct ip_conntrack *)(*pskb)->nfct->master)->infos == IP_CT_RELATED+IP_CT_IS_REPLY); /* Redirects on non-null nats must be dropped, else they'll start talking to each other without our translation, and be confused... --RR */ if (inside->icmp.type == ICMP_REDIRECT) { /* Don't care about races here. */ if (info->initialized != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST)) || info->num_manips != 0) return 0; } DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n", *pskb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); /* Note: May not be from a NAT'd host, but probably safest to do translation always as if it came from the host itself (even though a "host unreachable" coming from the host itself is a bit weird). More explanation: some people use NAT for anonymizing. Also, CERT recommends dropping all packets from private IP addresses (although ICMP errors from internal links with such addresses are not too uncommon, as Alan Cox points out) */ READ_LOCK(&ip_nat_lock); for (i = 0; i < info->num_manips; i++) { DEBUGP("icmp_reply: manip %u dir %s hook %u\n", i, info->manips[i].direction == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", info->manips[i].hooknum); if (info->manips[i].direction != dir) continue; /* Mapping the inner packet is just like a normal packet, except it was never src/dst reversed, so where we would normally apply a dst manip, we apply a src, and vice versa. */ if (info->manips[i].hooknum == hooknum) { DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n", info->manips[i].maniptype == IP_NAT_MANIP_SRC ? "DST" : "SRC", NIPQUAD(info->manips[i].manip.ip), ntohs(info->manips[i].manip.u.udp.port)); if (!manip_pkt(inside->ip.protocol, pskb, (*pskb)->nh.iph->ihl*4 + sizeof(inside->icmp), &info->manips[i].manip, !info->manips[i].maniptype)) goto unlock_fail; /* Outer packet needs to have IP header NATed like it's a reply. */ /* Use mapping to map outer packet: 0 give no per-proto mapping */ DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n", info->manips[i].maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", NIPQUAD(info->manips[i].manip.ip)); if (!manip_pkt(0, pskb, 0, &info->manips[i].manip, info->manips[i].maniptype)) goto unlock_fail; } } READ_UNLOCK(&ip_nat_lock); hdrlen = (*pskb)->nh.iph->ihl * 4; inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; inside->icmp.checksum = 0; inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen, (*pskb)->len - hdrlen, 0)); return 1; unlock_fail: READ_UNLOCK(&ip_nat_lock); return 0;}int __init ip_nat_init(void){ size_t i; /* Leave them the same for the moment. */ ip_nat_htable_size = ip_conntrack_htable_size; /* One vmalloc for both hash tables */ bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size*2); if (!bysource) { return -ENOMEM; } byipsproto = bysource + ip_nat_htable_size; /* Sew in builtin protocols. */ WRITE_LOCK(&ip_nat_lock); list_append(&protos, &ip_nat_protocol_tcp); list_append(&protos, &ip_nat_protocol_udp); list_append(&protos, &ip_nat_protocol_icmp); WRITE_UNLOCK(&ip_nat_lock); for (i = 0; i < ip_nat_htable_size; i++) { INIT_LIST_HEAD(&bysource[i]); INIT_LIST_HEAD(&byipsproto[i]); } /* FIXME: Man, this is a hack. <SIGH> */ IP_NF_ASSERT(ip_conntrack_destroyed == NULL); ip_conntrack_destroyed = &ip_nat_cleanup_conntrack; /* Initialize fake conntrack so that NAT will skip it */ ip_conntrack_untracked.nat.info.initialized |= (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST); return 0;}/* Clear NAT section of all conntracks, in case we're loaded again. */static int clean_nat(const struct ip_conntrack *i, void *data){ memset((void *)&i->nat, 0, sizeof(i->nat)); return 0;}/* Not __exit: called from ip_nat_standalone.c:init_or_cleanup() --RR */void ip_nat_cleanup(void){ ip_ct_selective_cleanup(&clean_nat, NULL); ip_conntrack_destroyed = NULL; vfree(bysource);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -