diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h index c228bde..349ac87 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h @@ -79,6 +79,8 @@ struct ip_conntrack_tuple /* The direction (for tuplehash) */ u_int8_t dir; } dst; + + u_int32_t mark; }; /* This is optimized opposed to a memset of the whole structure. Everything we @@ -114,7 +116,8 @@ static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1, const struct ip_conntrack_tuple *t2) { return t1->src.ip == t2->src.ip - && t1->src.u.all == t2->src.u.all; + && t1->src.u.all == t2->src.u.all + && t1->mark == t2->mark; } static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1, @@ -122,7 +125,8 @@ static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1, { return t1->dst.ip == t2->dst.ip && t1->dst.u.all == t2->dst.u.all - && t1->dst.protonum == t2->dst.protonum; + && t1->dst.protonum == t2->dst.protonum + && t1->mark == t2->mark; } static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1, @@ -140,7 +144,8 @@ static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t, || ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all) || ((t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all) || ((t->dst.protonum ^ tuple->dst.protonum) - & mask->dst.protonum)); + & mask->dst.protonum) + || ((t->mark ^ tuple->mark) & mask->mark)); } #endif /* _IP_CONNTRACK_TUPLE_H */ diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index ad246ba..4fd2bea 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -155,12 +155,14 @@ static int help(struct sk_buff **pskb, exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; exp->tuple.dst.protonum = IPPROTO_TCP; exp->tuple.dst.u.tcp.port = htons(port); + exp->tuple.mark = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.mark; exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.protonum = 0xFF; exp->mask.dst.u.tcp.port = htons(0xFFFF); + exp->mask.mark = 0xFFFF; /* RCU read locked by nf_hook_slow */ ip_nat_amanda = rcu_dereference(ip_nat_amanda_hook); diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index f8b3009..bb9de1d 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -146,7 +146,7 @@ static unsigned int ip_conntrack_hash_rnd; static u_int32_t __hash_conntrack(const struct ip_conntrack_tuple *tuple, unsigned int size, unsigned int rnd) { - return (jhash_3words((__force u32)tuple->src.ip, + return (jhash_3words((__force u32)tuple->src.ip ^ tuple->mark, ((__force u32)tuple->dst.ip ^ tuple->dst.protonum), (tuple->src.u.all | (tuple->dst.u.all << 16)), rnd) % size); @@ -177,6 +177,7 @@ ip_ct_get_tuple(const struct iphdr *iph, tuple->dst.ip = iph->daddr; tuple->dst.protonum = iph->protocol; tuple->dst.dir = IP_CT_DIR_ORIGINAL; + tuple->mark = skb->mark; return protocol->pkt_to_tuple(skb, dataoff, tuple); } @@ -190,6 +191,7 @@ ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse, inverse->dst.ip = orig->src.ip; inverse->dst.protonum = orig->dst.protonum; inverse->dst.dir = !orig->dst.dir; + inverse->mark = orig->mark; return protocol->invert_tuple(inverse, orig); } @@ -891,7 +893,8 @@ static inline int expect_clash(const struct ip_conntrack_expect *a, { a->mask.src.u.all & b->mask.src.u.all } }, { a->mask.dst.ip & b->mask.dst.ip, { a->mask.dst.u.all & b->mask.dst.u.all }, - a->mask.dst.protonum & b->mask.dst.protonum } }; + a->mask.dst.protonum & b->mask.dst.protonum }, + a->mask.mark & b->mask.mark }; return ip_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask); } diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 0410c99..3087fbf 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c @@ -425,9 +425,11 @@ static int help(struct sk_buff **pskb, exp->tuple.dst.u.tcp.port = htons(array[4] << 8 | array[5]); exp->tuple.src.u.tcp.port = 0; /* Don't care. */ exp->tuple.dst.protonum = IPPROTO_TCP; + exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; exp->mask = ((struct ip_conntrack_tuple) { { htonl(0xFFFFFFFF), { 0 } }, - { htonl(0xFFFFFFFF), { .tcp = { htons(0xFFFF) } }, 0xFF }}); + { htonl(0xFFFFFFFF), { .tcp = { htons(0xFFFF) } }, 0xFF }, + 0xFFFFFFFF }); exp->expectfn = NULL; exp->flags = 0; diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index aabfe1c..7bec4d1 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -255,11 +255,13 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, rtp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; rtp_exp->tuple.dst.u.udp.port = htons(rtp_port); rtp_exp->tuple.dst.protonum = IPPROTO_UDP; + rtp_exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; rtp_exp->mask.src.ip = htonl(0xFFFFFFFF); rtp_exp->mask.src.u.udp.port = 0; rtp_exp->mask.dst.ip = htonl(0xFFFFFFFF); rtp_exp->mask.dst.u.udp.port = htons(0xFFFF); rtp_exp->mask.dst.protonum = 0xFF; + rtp_exp->mask.mark = 0xFFFFFFFF; rtp_exp->flags = 0; /* Create expect for RTCP */ @@ -272,11 +274,13 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, rtcp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; rtcp_exp->tuple.dst.u.udp.port = htons(rtp_port + 1); rtcp_exp->tuple.dst.protonum = IPPROTO_UDP; + rtcp_exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; rtcp_exp->mask.src.ip = htonl(0xFFFFFFFF); rtcp_exp->mask.src.u.udp.port = 0; rtcp_exp->mask.dst.ip = htonl(0xFFFFFFFF); rtcp_exp->mask.dst.u.udp.port = htons(0xFFFF); rtcp_exp->mask.dst.protonum = 0xFF; + rtcp_exp->mask.mark = 0xFFFFFFFF; rtcp_exp->flags = 0; if (ct->tuplehash[dir].tuple.src.ip != @@ -344,11 +348,13 @@ static int expect_t120(struct sk_buff **pskb, exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; + exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; + exp->mask.mark = 0xFFFFFFFF; exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */ if (ct->tuplehash[dir].tuple.src.ip != @@ -669,11 +675,13 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; + exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; + exp->mask.mark = 0xFFFFFFFF; exp->flags = 0; if (ct->tuplehash[dir].tuple.src.ip != @@ -757,11 +765,13 @@ static int expect_callforwarding(struct sk_buff **pskb, exp->tuple.dst.ip = ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; + exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; + exp->mask.mark = 0xFFFFFFFF; exp->flags = 0; if (ct->tuplehash[dir].tuple.src.ip != @@ -1262,11 +1272,13 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; + exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; exp->mask.src.ip = gkrouted_only ? htonl(0xFFFFFFFF) : 0; exp->mask.src.u.tcp.port = 0; exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; + exp->mask.mark = 0xFFFFFFFF; exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */ nat_q931 = rcu_dereference(nat_q931_hook); @@ -1347,11 +1359,13 @@ static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_UDP; + exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; + exp->mask.mark = 0xFFFFFFFF; exp->flags = 0; exp->expectfn = ip_conntrack_ras_expect; if (ip_conntrack_expect_related(exp) == 0) { @@ -1561,11 +1575,13 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; + exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; + exp->mask.mark = 0xFFFFFFFF; exp->flags = IP_CT_EXPECT_PERMANENT; exp->expectfn = ip_conntrack_q931_expect; @@ -1624,11 +1640,13 @@ static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct, exp->tuple.dst.ip = ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.tcp.port = 0; exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.u.tcp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; + exp->mask.mark = 0xFFFFFFFF; exp->flags = IP_CT_EXPECT_PERMANENT; exp->expectfn = ip_conntrack_q931_expect; diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index 4d19373..25752bf 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c @@ -247,12 +247,14 @@ exp_gre(struct ip_conntrack *ct, exp_orig->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; exp_orig->tuple.dst.u.gre.key = callid; exp_orig->tuple.dst.protonum = IPPROTO_GRE; + exp_orig->tuple.mark = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.mark; exp_orig->mask.src.ip = htonl(0xffffffff); exp_orig->mask.src.u.all = 0; exp_orig->mask.dst.u.gre.key = htons(0xffff); exp_orig->mask.dst.ip = htonl(0xffffffff); exp_orig->mask.dst.protonum = 0xff; + exp_orig->mask.mark = 0xFFFFFFFF; exp_orig->master = ct; exp_orig->expectfn = pptp_expectfn; @@ -267,6 +269,7 @@ exp_gre(struct ip_conntrack *ct, exp_reply->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; exp_reply->tuple.dst.u.gre.key = peer_callid; exp_reply->tuple.dst.protonum = IPPROTO_GRE; + exp_reply->tuple.mark = ct->tuplehash[IP_CT_DIR_REPLY].tuple.mark; ip_nat_pptp_exp_gre = rcu_dereference(ip_nat_pptp_hook_exp_gre); if (ip_nat_pptp_exp_gre) diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index 91832ec..704aa56 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c @@ -216,11 +216,13 @@ static int help(struct sk_buff **pskb, { { 0, { 0 } }, { ct->tuplehash[!dir].tuple.dst.ip, { .tcp = { htons(dcc_port) } }, - IPPROTO_TCP }}); + IPPROTO_TCP }, + ct->tuplehash[!dir].tuple.mark }); exp->mask = ((struct ip_conntrack_tuple) { { 0, { 0 } }, { htonl(0xFFFFFFFF), - { .tcp = { htons(0xFFFF) } }, 0xFF }}); + { .tcp = { htons(0xFFFF) } }, 0xFF }, + 0xFFFFFFFF}); exp->expectfn = NULL; exp->flags = 0; ip_nat_irc = rcu_dereference(ip_nat_irc_hook); diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c index a1d6a89..10ecafb 100644 --- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c +++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c @@ -85,6 +85,7 @@ static int help(struct sk_buff **pskb, exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.u.udp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; + exp->mask.mark = 0xFFFFFFFF; exp->expectfn = NULL; exp->flags = IP_CT_EXPECT_PERMANENT; diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index 11c588a..2da68d8 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c @@ -365,12 +365,14 @@ static int set_expected_rtp(struct sk_buff **pskb, exp->tuple.dst.ip = ipaddr; exp->tuple.dst.u.udp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_UDP; + exp->tuple.mark = ct->tuplehash[!dir].tuple.mark; exp->mask.src.ip = htonl(0xFFFFFFFF); exp->mask.src.u.udp.port = 0; exp->mask.dst.ip = htonl(0xFFFFFFFF); exp->mask.dst.u.udp.port = htons(0xFFFF); exp->mask.dst.protonum = 0xFF; + exp->mask.mark = 0xFFFFFFFF; exp->expectfn = NULL; exp->flags = 0; diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 86efb54..010f155 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -55,8 +55,9 @@ static int print_tuple(struct seq_file *s, const struct ip_conntrack_tuple *tuple, struct ip_conntrack_protocol *proto) { - seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip)); + seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u mark=%u ", + NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip), + tuple->mark); return proto->print_tuple(s, tuple); } diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c index ef56de2..4b921f4 100644 --- a/net/ipv4/netfilter/ip_conntrack_tftp.c +++ b/net/ipv4/netfilter/ip_conntrack_tftp.c @@ -76,6 +76,7 @@ static int tftp_help(struct sk_buff **pskb, exp->mask.dst.ip = htonl(0xffffffff); exp->mask.dst.u.udp.port = htons(0xffff); exp->mask.dst.protonum = 0xff; + exp->mask.mark = 0xFFFFFFFF; exp->expectfn = NULL; exp->flags = 0; diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 9d1a517..045ec94 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -82,7 +82,7 @@ static inline unsigned int hash_by_src(const struct ip_conntrack_tuple *tuple) { /* Original src, to ensure we map it consistently if poss. */ - return jhash_3words((__force u32)tuple->src.ip, tuple->src.u.all, + return jhash_3words((__force u32)tuple->src.ip, tuple->src.u.all ^ tuple->mark, tuple->dst.protonum, 0) % ip_nat_htable_size; } @@ -148,7 +148,9 @@ same_src(const struct ip_conntrack *ct, && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == tuple->src.ip && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all - == tuple->src.u.all); + == tuple->src.u.all + && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.mark + == tuple->mark); } /* Only called for SRC manip */ @@ -217,7 +219,8 @@ find_best_ips_proto(struct ip_conntrack_tuple *tuple, * like this), even across reboots. */ minip = ntohl(range->min_ip); maxip = ntohl(range->max_ip); - j = jhash_2words((__force u32)tuple->src.ip, (__force u32)tuple->dst.ip, 0); + j = jhash_2words((__force u32)tuple->src.ip, + (__force u32)tuple->dst.ip ^ tuple->mark, 0); *var_ipp = htonl(minip + j % (maxip - minip + 1)); }