📄 nf_nat_core.c
字号:
manip_pkt(u_int16_t proto, struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *target, enum nf_nat_manip_type maniptype){ struct iphdr *iph; struct nf_nat_protocol *p; if (!skb_make_writable(skb, iphdroff + sizeof(*iph))) return 0; iph = (void *)skb->data + iphdroff; /* Manipulate protcol part. */ /* rcu_read_lock()ed by nf_hook_slow */ p = __nf_nat_proto_find(proto); if (!p->manip_pkt(skb, iphdroff, target, maniptype)) return 0; iph = (void *)skb->data + iphdroff; if (maniptype == IP_NAT_MANIP_SRC) { nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip); iph->saddr = target->src.u3.ip; } else { nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip); iph->daddr = target->dst.u3.ip; } return 1;}/* Do packet manipulations according to nf_nat_setup_info. */unsigned int nf_nat_packet(struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int hooknum, struct sk_buff *skb){ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned long statusbit; enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum); if (mtype == IP_NAT_MANIP_SRC) statusbit = IPS_SRC_NAT; else statusbit = IPS_DST_NAT; /* Invert if this is reply dir. */ if (dir == IP_CT_DIR_REPLY) statusbit ^= IPS_NAT_MASK; /* Non-atomic: these bits don't change. */ if (ct->status & statusbit) { struct nf_conntrack_tuple target; /* We are aiming to look like inverse of other direction. */ nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); if (!manip_pkt(target.dst.protonum, skb, 0, &target, mtype)) return NF_DROP; } return NF_ACCEPT;}EXPORT_SYMBOL_GPL(nf_nat_packet);/* Dir is direction ICMP is coming from (opposite to packet it contains) */int nf_nat_icmp_reply_translation(struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int hooknum, struct sk_buff *skb){ struct { struct icmphdr icmp; struct iphdr ip; } *inside; struct nf_conntrack_l4proto *l4proto; struct nf_conntrack_tuple inner, target; int hdrlen = ip_hdrlen(skb); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned long statusbit; enum nf_nat_manip_type manip = HOOK2MANIP(hooknum); if (!skb_make_writable(skb, hdrlen + sizeof(*inside))) return 0; inside = (void *)skb->data + ip_hdrlen(skb); /* We're actually going to mangle it beyond trivial checksum adjustment, so make sure the current checksum is correct. */ if (nf_ip_checksum(skb, hooknum, hdrlen, 0)) return 0; /* Must be RELATED */ NF_CT_ASSERT(skb->nfctinfo == IP_CT_RELATED || skb->nfctinfo == 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) { /* If NAT isn't finished, assume it and drop. */ if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK) return 0; if (ct->status & IPS_NAT_MASK) return 0; } pr_debug("icmp_reply_translation: translating error %p manip %u " "dir %s\n", skb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); /* rcu_read_lock()ed by nf_hook_slow */ l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); if (!nf_ct_get_tuple(skb, ip_hdrlen(skb) + sizeof(struct icmphdr), (ip_hdrlen(skb) + sizeof(struct icmphdr) + inside->ip.ihl * 4), (u_int16_t)AF_INET, inside->ip.protocol, &inner, l3proto, l4proto)) return 0; /* Change inner back to look like incoming packet. We do the opposite manip on this hook to normal, because it might not pass all hooks (locally-generated ICMP). Consider incoming packet: PREROUTING (DST manip), routing produces ICMP, goes through POSTROUTING (which must correct the DST manip). */ if (!manip_pkt(inside->ip.protocol, skb, ip_hdrlen(skb) + sizeof(inside->icmp), &ct->tuplehash[!dir].tuple, !manip)) return 0; if (skb->ip_summed != CHECKSUM_PARTIAL) { /* Reloading "inside" here since manip_pkt inner. */ inside = (void *)skb->data + ip_hdrlen(skb); inside->icmp.checksum = 0; inside->icmp.checksum = csum_fold(skb_checksum(skb, hdrlen, skb->len - hdrlen, 0)); } /* Change outer to look the reply to an incoming packet * (proto 0 means don't invert per-proto part). */ if (manip == IP_NAT_MANIP_SRC) statusbit = IPS_SRC_NAT; else statusbit = IPS_DST_NAT; /* Invert if this is reply dir. */ if (dir == IP_CT_DIR_REPLY) statusbit ^= IPS_NAT_MASK; if (ct->status & statusbit) { nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); if (!manip_pkt(0, skb, 0, &target, manip)) return 0; } return 1;}EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);/* Protocol registration. */int nf_nat_protocol_register(struct nf_nat_protocol *proto){ int ret = 0; write_lock_bh(&nf_nat_lock); if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) { ret = -EBUSY; goto out; } rcu_assign_pointer(nf_nat_protos[proto->protonum], proto); out: write_unlock_bh(&nf_nat_lock); return ret;}EXPORT_SYMBOL(nf_nat_protocol_register);/* Noone stores the protocol anywhere; simply delete it. */void nf_nat_protocol_unregister(struct nf_nat_protocol *proto){ write_lock_bh(&nf_nat_lock); rcu_assign_pointer(nf_nat_protos[proto->protonum], &nf_nat_unknown_protocol); write_unlock_bh(&nf_nat_lock); synchronize_rcu();}EXPORT_SYMBOL(nf_nat_protocol_unregister);#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)intnf_nat_port_range_to_nlattr(struct sk_buff *skb, const struct nf_nat_range *range){ NLA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), &range->min.tcp.port); NLA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), &range->max.tcp.port); return 0;nla_put_failure: return -1;}EXPORT_SYMBOL_GPL(nf_nat_port_nlattr_to_range);intnf_nat_port_nlattr_to_range(struct nlattr *tb[], struct nf_nat_range *range){ int ret = 0; /* we have to return whether we actually parsed something or not */ if (tb[CTA_PROTONAT_PORT_MIN]) { ret = 1; range->min.tcp.port = *(__be16 *)nla_data(tb[CTA_PROTONAT_PORT_MIN]); } if (!tb[CTA_PROTONAT_PORT_MAX]) { if (ret) range->max.tcp.port = range->min.tcp.port; } else { ret = 1; range->max.tcp.port = *(__be16 *)nla_data(tb[CTA_PROTONAT_PORT_MAX]); } return ret;}EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nlattr);#endif/* Noone using conntrack by the time this called. */static void nf_nat_cleanup_conntrack(struct nf_conn *ct){ struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT); if (nat == NULL || nat->ct == NULL) return; NF_CT_ASSERT(nat->ct->status & IPS_NAT_DONE_MASK); write_lock_bh(&nf_nat_lock); hlist_del(&nat->bysource); nat->ct = NULL; write_unlock_bh(&nf_nat_lock);}static void nf_nat_move_storage(struct nf_conn *conntrack, void *old){ struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT); struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old; struct nf_conn *ct = old_nat->ct; if (!ct || !(ct->status & IPS_NAT_DONE_MASK)) return; write_lock_bh(&nf_nat_lock); hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource); new_nat->ct = ct; write_unlock_bh(&nf_nat_lock);}static struct nf_ct_ext_type nat_extend __read_mostly = { .len = sizeof(struct nf_conn_nat), .align = __alignof__(struct nf_conn_nat), .destroy = nf_nat_cleanup_conntrack, .move = nf_nat_move_storage, .id = NF_CT_EXT_NAT, .flags = NF_CT_EXT_F_PREALLOC,};static int __init nf_nat_init(void){ size_t i; int ret; ret = nf_ct_extend_register(&nat_extend); if (ret < 0) { printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); return ret; } /* Leave them the same for the moment. */ nf_nat_htable_size = nf_conntrack_htable_size; bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, &nf_nat_vmalloced); if (!bysource) { ret = -ENOMEM; goto cleanup_extend; } /* Sew in builtin protocols. */ write_lock_bh(&nf_nat_lock); for (i = 0; i < MAX_IP_NAT_PROTO; i++) rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol); rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp); rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp); rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp); write_unlock_bh(&nf_nat_lock); for (i = 0; i < nf_nat_htable_size; i++) { INIT_HLIST_HEAD(&bysource[i]); } /* Initialize fake conntrack so that NAT will skip it */ nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); return 0; cleanup_extend: nf_ct_extend_unregister(&nat_extend); return ret;}/* Clear NAT section of all conntracks, in case we're loaded again. */static int clean_nat(struct nf_conn *i, void *data){ struct nf_conn_nat *nat = nfct_nat(i); if (!nat) return 0; memset(nat, 0, sizeof(*nat)); i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); return 0;}static void __exit nf_nat_cleanup(void){ nf_ct_iterate_cleanup(&clean_nat, NULL); synchronize_rcu(); nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size); nf_ct_l3proto_put(l3proto); nf_ct_extend_unregister(&nat_extend);}MODULE_LICENSE("GPL");module_init(nf_nat_init);module_exit(nf_nat_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -