📄 ip_nat_rule.c
字号:
/* Everything about the rules for NAT. */#define __NO_VERSION__#include <linux/types.h>#include <linux/ip.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#include <linux/module.h>#include <linux/kmod.h>#include <linux/skbuff.h>#include <linux/proc_fs.h>#include <net/checksum.h>#include <linux/bitops.h>#include <linux/version.h>#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)#include <linux/netfilter_ipv4/ip_tables.h>#include <linux/netfilter_ipv4/ip_nat.h>#include <linux/netfilter_ipv4/ip_nat_core.h>#include <linux/netfilter_ipv4/ip_nat_rule.h>#include <linux/netfilter_ipv4/listhelp.h>#if 0#define DEBUGP printk#else#define DEBUGP(format, args...)#endif#define NAT_VALID_HOOKS ((1<<NF_IP_PRE_ROUTING) | (1<<NF_IP_POST_ROUTING) | (1<<NF_IP_LOCAL_OUT))/* Standard entry. */struct ipt_standard{ struct ipt_entry entry; struct ipt_standard_target target;};struct ipt_error_target{ struct ipt_entry_target target; char errorname[IPT_FUNCTION_MAXNAMELEN];};struct ipt_error{ struct ipt_entry entry; struct ipt_error_target target;};static struct{ struct ipt_replace repl; struct ipt_standard entries[3]; struct ipt_error term;} nat_initial_table __initdata= { { "nat", NAT_VALID_HOOKS, 4, sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), { [NF_IP_PRE_ROUTING] 0, [NF_IP_POST_ROUTING] sizeof(struct ipt_standard), [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) * 2 }, { [NF_IP_PRE_ROUTING] 0, [NF_IP_POST_ROUTING] sizeof(struct ipt_standard), [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) * 2 }, 0, NULL, { } }, { /* PRE_ROUTING */ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* POST_ROUTING */ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* LOCAL_OUT */ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } } }, /* ERROR */ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, 0, sizeof(struct ipt_entry), sizeof(struct ipt_error), 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, { } }, "ERROR" } }};static struct ipt_table nat_table= { { NULL, NULL }, "nat", &nat_initial_table.repl, NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };LIST_HEAD(nat_expect_list);/* Source NAT */static unsigned int ipt_snat_target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *targinfo, void *userinfo){ struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; 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)); IP_NF_ASSERT(out); return ip_nat_setup_info(ct, targinfo, hooknum);}static unsigned int ipt_dnat_target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *targinfo, void *userinfo){ struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; 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)); return ip_nat_setup_info(ct, targinfo, hooknum);}static int ipt_snat_checkentry(const char *tablename, const struct ipt_entry *e, void *targinfo, unsigned int targinfosize, unsigned int hook_mask){ struct ip_nat_multi_range *mr = targinfo; /* Must be a valid range */ if (targinfosize < sizeof(struct ip_nat_multi_range)) { DEBUGP("SNAT: Target size %u too small\n", targinfosize); return 0; } if (targinfosize != IPT_ALIGN((sizeof(struct ip_nat_multi_range) + (sizeof(struct ip_nat_range) * (mr->rangesize - 1))))) { DEBUGP("SNAT: Target size %u wrong for %u ranges\n", targinfosize, mr->rangesize); return 0; } if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) { DEBUGP("SNAT: hook mask 0x%x bad\n", hook_mask); return 0; } return 1;}static int ipt_dnat_checkentry(const char *tablename, const struct ipt_entry *e, void *targinfo, unsigned int targinfosize, unsigned int hook_mask){ struct ip_nat_multi_range *mr = targinfo; /* Must be a valid range */ if (targinfosize < sizeof(struct ip_nat_multi_range)) { DEBUGP("DNAT: Target size %u too small\n", targinfosize); return 0; } if (targinfosize != IPT_ALIGN((sizeof(struct ip_nat_multi_range) + (sizeof(struct ip_nat_range) * (mr->rangesize - 1))))) { DEBUGP("DNAT: Target size %u wrong for %u ranges\n", targinfosize, mr->rangesize); return 0; } if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) { DEBUGP("DNAT: hook mask 0x%x bad\n", hook_mask); return 0; } return 1;}static inline unsigned intalloc_null_binding(struct ip_conntrack *conntrack, struct ip_nat_info *info, unsigned int hooknum){ /* Force range to this IP; let proto decide mapping for per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). Use reply in case it's already been mangled (eg local packet). */ u_int32_t ip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); struct ip_nat_multi_range mr = { 1, { { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } } } }; DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", conntrack, NIPQUAD(ip)); return ip_nat_setup_info(conntrack, &mr, hooknum);}static inline int call_expect(const struct ip_nat_expect *i, struct sk_buff **pskb, unsigned int hooknum, struct ip_conntrack *ct, struct ip_nat_info *info, struct ip_conntrack *master, struct ip_nat_info *masterinfo, unsigned int *verdict){ return i->expect(pskb, hooknum, ct, info, master, masterinfo, verdict);}int ip_nat_rule_find(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, struct ip_conntrack *ct, struct ip_nat_info *info){ int ret; /* Master won't vanish while this ctrack still alive */ if (ct->master.master) { struct ip_conntrack *master; master = (struct ip_conntrack *)ct->master.master; if (LIST_FIND(&nat_expect_list, call_expect, struct ip_nat_expect *, pskb, hooknum, ct, info, master, &master->nat.info, &ret)) return ret; } ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL); if (ret == NF_ACCEPT) { if (!(info->initialized & (1 << HOOK2MANIP(hooknum)))) /* NUL mapping */ ret = alloc_null_binding(ct, info, hooknum); } return ret;}int ip_nat_expect_register(struct ip_nat_expect *expect){ WRITE_LOCK(&ip_nat_lock); list_prepend(&nat_expect_list, expect); WRITE_UNLOCK(&ip_nat_lock); return 0;}void ip_nat_expect_unregister(struct ip_nat_expect *expect){ WRITE_LOCK(&ip_nat_lock); LIST_DELETE(&nat_expect_list, expect); WRITE_UNLOCK(&ip_nat_lock);}static struct ipt_target ipt_snat_reg= { { NULL, NULL }, "SNAT", ipt_snat_target, ipt_snat_checkentry, NULL };static struct ipt_target ipt_dnat_reg= { { NULL, NULL }, "DNAT", ipt_dnat_target, ipt_dnat_checkentry, NULL };int __init ip_nat_rule_init(void){ int ret; ret = ipt_register_table(&nat_table); if (ret != 0) return ret; ret = ipt_register_target(&ipt_snat_reg); if (ret != 0) goto unregister_table; ret = ipt_register_target(&ipt_dnat_reg); if (ret != 0) goto unregister_snat; return ret; unregister_snat: ipt_unregister_target(&ipt_snat_reg); unregister_table: ipt_unregister_table(&nat_table); return ret;}void ip_nat_rule_cleanup(void){ ipt_unregister_target(&ipt_dnat_reg); ipt_unregister_target(&ipt_snat_reg); ipt_unregister_table(&nat_table);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -