diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index a6d34aa9abea..96dc4b9d6373 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -43,7 +43,10 @@ void nf_conntrack_cleanup_end(void); bool nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, const struct nf_conntrack_tuple *orig); -extern bool (*nattype_refresh_timer)(unsigned long nattype) __rcu __read_mostly; +extern bool (*nattype_refresh_timer) + (unsigned long nattype, + unsigned long timeout_value) + __rcu __read_mostly; /* Find a connection corresponding to a tuple. */ struct nf_conntrack_tuple_hash * diff --git a/net/ipv4/netfilter/ipt_NATTYPE.c b/net/ipv4/netfilter/ipt_NATTYPE.c index ca184d1e8909..ebc7b2a74ad5 100644 --- a/net/ipv4/netfilter/ipt_NATTYPE.c +++ b/net/ipv4/netfilter/ipt_NATTYPE.c @@ -13,33 +13,32 @@ #include #include #include -#include +#include #include #include #include -#if !defined(NATTYPE_DEBUG) -#define DEBUGP(type, args...) -#else static const char * const types[] = {"TYPE_PORT_ADDRESS_RESTRICTED", "TYPE_ENDPOINT_INDEPENDENT", "TYPE_ADDRESS_RESTRICTED"}; static const char * const modes[] = {"MODE_DNAT", "MODE_FORWARD_IN", "MODE_FORWARD_OUT"}; #define DEBUGP(args...) pr_debug(args) -#endif struct ipt_nattype { struct list_head list; struct timer_list timeout; - unsigned char is_valid; + unsigned long timeout_value; + unsigned int nattype_cookie; unsigned short proto; /* Protocol: TCP or UDP */ - struct nf_nat_ipv4_range range; /* LAN side src info*/ + struct nf_nat_range range; /* LAN side source information */ unsigned short nat_port; /* Routed NAT port */ unsigned int dest_addr; /* Original egress packets dst addr */ unsigned short dest_port;/* Original egress packets destination port */ }; +#define NATTYPE_COOKIE 0x11abcdef + static LIST_HEAD(nattype_list); static DEFINE_SPINLOCK(nattype_lock); @@ -49,11 +48,13 @@ static DEFINE_SPINLOCK(nattype_lock); static void nattype_nte_debug_print(const struct ipt_nattype *nte, const char *s) { - DEBUGP("%p: %s - proto[%d], src[%pI4:%d], nat[:%d], dest[%pI4:%d]\n", + DEBUGP("%p:%s-proto[%d],src[%pI4:%d],nat[%d],dest[%pI4:%d]\n", nte, s, nte->proto, - &nte->range.min_ip, ntohs(nte->range.min.all), + &nte->range.min_addr.ip, ntohs(nte->range.min_proto.all), ntohs(nte->nat_port), &nte->dest_addr, ntohs(nte->dest_port)); + DEBUGP("Timeout[%lx], Expires[%lx]\n", nte->timeout_value, + nte->timeout.expires); } /* netfilter NATTYPE nattype_free() @@ -61,28 +62,28 @@ static void nattype_nte_debug_print(const struct ipt_nattype *nte, */ static void nattype_free(struct ipt_nattype *nte) { - nattype_nte_debug_print(nte, "free"); kfree(nte); } /* netfilter NATTYPE nattype_refresh_timer() * Refresh the timer for this object. */ -bool nattype_refresh_timer_impl(unsigned long nat_type) +bool nattype_refresh_timer(unsigned long nat_type, unsigned long timeout_value) { struct ipt_nattype *nte = (struct ipt_nattype *)nat_type; if (!nte) return false; spin_lock_bh(&nattype_lock); - if (!nte->is_valid) { + if (nte->nattype_cookie != NATTYPE_COOKIE) { spin_unlock_bh(&nattype_lock); return false; } if (del_timer(&nte->timeout)) { - nte->timeout.expires = jiffies + NATTYPE_TIMEOUT * HZ; + nte->timeout.expires = timeout_value; add_timer(&nte->timeout); spin_unlock_bh(&nattype_lock); + nattype_nte_debug_print(nte, "refresh"); return true; } spin_unlock_bh(&nattype_lock); @@ -184,7 +185,8 @@ static bool nattype_packet_in_match(const struct ipt_nattype *nte, /* netfilter NATTYPE nattype_compare * Compare two entries, return true if relevant fields are the same. */ -static bool nattype_compare(struct ipt_nattype *n1, struct ipt_nattype *n2) +static bool nattype_compare(struct ipt_nattype *n1, struct ipt_nattype *n2, + const struct ipt_nattype_info *info) { /* netfilter NATTYPE Protocol * compare. @@ -199,17 +201,18 @@ static bool nattype_compare(struct ipt_nattype *n1, struct ipt_nattype *n2) * Since we always keep min/max values the same, * just compare the min values. */ - if (n1->range.min_ip != n2->range.min_ip) { - DEBUGP("%s: r.min_ip mismatch: %pI4:%pI4\n", - __func__, &n1->range.min_ip, &n2->range.min_ip); + if (n1->range.min_addr.ip != n2->range.min_addr.ip) { + DEBUGP("%s: r.min_addr.ip mismatch: %pI4:%pI4\n", + __func__, &n1->range.min_addr.ip, + &n2->range.min_addr.ip); return false; } - if (n1->range.min.all != n2->range.min.all) { + if (n1->range.min_proto.all != n2->range.min_proto.all) { DEBUGP("%s: r.min mismatch: %d:%d\n", - __func__, - ntohs(n1->range.min.all), - ntohs(n2->range.min.all)); + __func__, + ntohs(n1->range.min_proto.all), + ntohs(n2->range.min_proto.all)); return false; } @@ -222,9 +225,6 @@ static bool nattype_compare(struct ipt_nattype *n1, struct ipt_nattype *n2) return false; } - /* netfilter NATTYPE - * Destination compare - */ if (n1->dest_addr != n2->dest_addr) { DEBUGP("%s: dest_addr mismatch: %pI4:%pI4\n", __func__, &n1->dest_addr, &n2->dest_addr); @@ -236,6 +236,16 @@ static bool nattype_compare(struct ipt_nattype *n1, struct ipt_nattype *n2) __func__, ntohs(n1->dest_port), ntohs(n2->dest_port)); return false; } + /* netfilter NATTYPE Destination compare + * Destination Comapre for Address Restricted Cone NAT. + */ + if (info->type == TYPE_ADDRESS_RESTRICTED && + n1->dest_addr != n2->dest_addr) { + DEBUGP("%s: dest_addr mismatch: %pI4:%pI4\n", + __func__, &n1->dest_addr, &n2->dest_addr); + return false; + } + return true; } @@ -255,7 +265,7 @@ static unsigned int nattype_nat(struct sk_buff *skb, list_for_each_entry(nte, &nattype_list, list) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; - struct nf_nat_ipv4_range newrange; + struct nf_nat_range newrange; unsigned int ret; if (!nattype_packet_in_match(nte, skb, par->targinfo)) @@ -276,11 +286,21 @@ static unsigned int nattype_nat(struct sk_buff *skb, return XT_CONTINUE; } - /* Expand the ingress conntrack - * to include the reply as source + /* netfilter + * Refresh the timer, if we fail, break + * out and forward fail as though we never + * found the entry. + */ + if (!nattype_refresh_timer((unsigned long)nte, + jiffies + nte->timeout_value)) + break; + + /* netfilter + * Expand the ingress conntrack to include the reply as source */ DEBUGP("Expand ingress conntrack=%p, type=%d, src[%pI4:%d]\n", - ct, ctinfo, &newrange.min_ip, ntohs(newrange.min.all)); + ct, ctinfo, &newrange.min_addr.ip, + ntohs(newrange.min_proto.all)); ct->nattype_entry = (unsigned long)nte; ret = nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); DEBUGP("Expand returned: %d\n", ret); @@ -304,12 +324,21 @@ static unsigned int nattype_forward(struct sk_buff *skb, enum ip_conntrack_info ctinfo; const struct ipt_nattype_info *info = par->targinfo; u16 nat_port; + enum ip_conntrack_dir dir; - if (par->hooknum != NF_INET_FORWARD) + if (par->hooknum != NF_INET_POST_ROUTING) return XT_CONTINUE; - /* Ingress packet, - * refresh the timer if we find an entry. + /* netfilter + * Egress packet, create a new rule in our list. If conntrack does + * not have an entry, skip this packet. + */ + ct = nf_ct_get(skb, &ctinfo); + if (!ct) + return XT_CONTINUE; + + /* netfilter + * Ingress packet, refresh the timer if we find an entry. */ if (info->mode == MODE_FORWARD_IN) { spin_lock_bh(&nattype_lock); @@ -327,7 +356,8 @@ static unsigned int nattype_forward(struct sk_buff *skb, * out and forward fail as though we never * found the entry. */ - if (!nattype_refresh_timer((unsigned long)nte)) + if (!nattype_refresh_timer((unsigned long)nte, + ct->timeout.expires)) break; /* netfilter NATTYPE @@ -344,15 +374,9 @@ static unsigned int nattype_forward(struct sk_buff *skb, return XT_CONTINUE; } - /* netfilter NATTYPE - * Egress packet, create a new rule in our list. If conntrack does - * not have an entry, skip this packet. - */ - ct = nf_ct_get(skb, &ctinfo); - if (!ct || (ctinfo == IP_CT_NEW && ctinfo == IP_CT_RELATED)) - return XT_CONTINUE; + dir = CTINFO2DIR(ctinfo); - nat_port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all; + nat_port = ct->tuplehash[!dir].tuple.dst.u.all; /* netfilter NATTYPE * Allocate a new entry @@ -368,16 +392,18 @@ static unsigned int nattype_forward(struct sk_buff *skb, nte->proto = iph->protocol; nte->nat_port = nat_port; nte->dest_addr = iph->daddr; - nte->range.min_ip = iph->saddr; - nte->range.max_ip = nte->range.min_ip; + nte->range.min_addr.ip = iph->saddr; + nte->range.max_addr.ip = nte->range.min_addr.ip; if (iph->protocol == IPPROTO_TCP) { - nte->range.min.tcp.port = ((struct tcphdr *)protoh)->source; - nte->range.max.tcp.port = nte->range.min.tcp.port; + nte->range.min_proto.tcp.port = + ((struct tcphdr *)protoh)->source; + nte->range.max_proto.tcp.port = nte->range.min_proto.tcp.port; nte->dest_port = ((struct tcphdr *)protoh)->dest; } else if (iph->protocol == IPPROTO_UDP) { - nte->range.min.udp.port = ((struct udphdr *)protoh)->source; - nte->range.max.udp.port = nte->range.min.udp.port; + nte->range.min_proto.udp.port = + ((struct udphdr *)protoh)->source; + nte->range.max_proto.udp.port = nte->range.min_proto.udp.port; nte->dest_port = ((struct udphdr *)protoh)->dest; } nte->range.flags = (NF_NAT_RANGE_MAP_IPS | @@ -398,7 +424,7 @@ static unsigned int nattype_forward(struct sk_buff *skb, */ spin_lock_bh(&nattype_lock); list_for_each_entry(nte2, &nattype_list, list) { - if (!nattype_compare(nte, nte2)) + if (!nattype_compare(nte, nte2, info)) continue; spin_unlock_bh(&nattype_lock); /* netfilter NATTYPE @@ -406,7 +432,7 @@ static unsigned int nattype_forward(struct sk_buff *skb, * entry as this one is timed out and will be removed * from the list shortly. */ - if (!nattype_refresh_timer((unsigned long)nte2)) + if (!nattype_refresh_timer((unsigned long)nte2, jiffies + nte2->timeout_value)) break; /* netfilter NATTYPE @@ -423,11 +449,12 @@ static unsigned int nattype_forward(struct sk_buff *skb, /* netfilter NATTYPE * Add the new entry to the list. */ - nte->timeout.expires = jiffies + (NATTYPE_TIMEOUT * HZ); + nte->timeout_value = ct->timeout.expires; + nte->timeout.expires = ct->timeout.expires + jiffies; add_timer(&nte->timeout); list_add(&nte->list, &nattype_list); ct->nattype_entry = (unsigned long)nte; - nte->is_valid = 1; + nte->nattype_cookie = NATTYPE_COOKIE; spin_unlock_bh(&nattype_lock); nattype_nte_debug_print(nte, "ADD"); return XT_CONTINUE; @@ -513,7 +540,7 @@ static int nattype_check(const struct xt_tgchk_param *par) __func__, types[info->type], modes[info->mode]); if (par->hook_mask & ~((1 << NF_INET_PRE_ROUTING) | - (1 << NF_INET_FORWARD))) { + (1 << NF_INET_POST_ROUTING))) { DEBUGP("%s: bad hooks %x.\n", __func__, par->hook_mask); return -EINVAL; } @@ -554,7 +581,7 @@ static struct xt_target nattype = { .checkentry = nattype_check, .targetsize = sizeof(struct ipt_nattype_info), .hooks = ((1 << NF_INET_PRE_ROUTING) | - (1 << NF_INET_FORWARD)), + (1 << NF_INET_POST_ROUTING)), .me = THIS_MODULE, }; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 6cd4c2e78bdc..a811e9b213e5 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -64,7 +64,10 @@ EXPORT_SYMBOL_GPL(nf_conntrack_expect_lock); struct hlist_nulls_head *nf_conntrack_hash __read_mostly; EXPORT_SYMBOL_GPL(nf_conntrack_hash); -bool (*nattype_refresh_timer)(unsigned long nattype) __rcu __read_mostly; +bool (*nattype_refresh_timer) + (unsigned long nattype, + unsigned long timeout_value) + __rcu __read_mostly; EXPORT_SYMBOL(nattype_refresh_timer); struct conntrack_gc_work { @@ -1390,6 +1393,9 @@ __nf_conntrack_alloc(struct net *net, nf_ct_zone_add(ct, zone); +#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) + ct->nattype_entry = 0; +#endif /* Because we use RCU lookups, we set ct_general.use to zero before * this is inserted in any list. */ @@ -1792,7 +1798,9 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, bool do_acct) { #if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) - bool (*nattype_ref_timer)(unsigned long nattype); + bool (*nattype_ref_timer) + (unsigned long nattype, + unsigned long timeout_value); #endif /* Only update if this is not a fixed timeout */ @@ -1810,7 +1818,7 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, #if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) nattype_ref_timer = rcu_dereference(nattype_refresh_timer); if (nattype_ref_timer) - nattype_ref_timer(ct->nattype_entry); + nattype_ref_timer(ct->nattype_entry, ct->timeout.expires); #endif acct: diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index aa8adf930b3c..63af610bec9e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1686,6 +1686,11 @@ static int ctnetlink_change_timeout(struct nf_conn *ct, const struct nlattr * const cda[]) { u64 timeout = (u64)ntohl(nla_get_be32(cda[CTA_TIMEOUT])) * HZ; +#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) + bool (*nattype_ref_timer) + (unsigned long nattype, + unsigned long timeout_value); +#endif if (timeout > INT_MAX) timeout = INT_MAX; @@ -1694,6 +1699,12 @@ static int ctnetlink_change_timeout(struct nf_conn *ct, if (test_bit(IPS_DYING_BIT, &ct->status)) return -ETIME; +/* Refresh the NAT type entry. */ +#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) + nattype_ref_timer = rcu_dereference(nattype_refresh_timer); + if (nattype_ref_timer) + nattype_ref_timer(ct->nattype_entry, ct->timeout.expires); +#endif return 0; } diff --git a/net/netfilter/nf_nat_masquerade.c b/net/netfilter/nf_nat_masquerade.c index 8e8a65d46345..155e41010b6d 100644 --- a/net/netfilter/nf_nat_masquerade.c +++ b/net/netfilter/nf_nat_masquerade.c @@ -59,7 +59,13 @@ nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, newrange.max_proto = range->max_proto; /* Hand modified range to generic setup. */ +#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) + nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); + return XT_CONTINUE; +#else return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); +#endif + } EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4);