/* Everything about the rules for NAT. */ #define __NO_VERSION__ #include #include #include #include #include #include #include #include #include #include #include #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 #include #include #include #include #if 0 #define DEBUGP printk #else #define DEBUGP(format, args...) #endif #define NAT_VALID_HOOKS ((1<rangesize - 1))))) { DEBUGP("SNAT: Target size %u wrong for %u ranges\n", targinfosize, mr->rangesize); return 0; } /* Only allow these for NAT. */ if (strcmp(tablename, "nat") != 0) { DEBUGP("SNAT: wrong table %s\n", tablename); 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; } /* Only allow these for NAT. */ if (strcmp(tablename, "nat") != 0) { DEBUGP("DNAT: wrong table %s\n", tablename); 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; } #ifndef CONFIG_IP_NF_NAT_LOCAL if (hook_mask & (1 << NF_IP_LOCAL_OUT)) { DEBUGP("DNAT: CONFIG_IP_NF_NAT_LOCAL not enabled\n"); return 0; } #endif return 1; } static inline unsigned int alloc_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); } 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; 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; } 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); }