aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2012-06-07 07:31:25 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2012-06-16 09:09:08 -0400
commit8c88f87cb27ad09086940bdd3e6955e5325ec89a (patch)
tree1acfa54ba78602eb4eb053110ffc0a54025318c7 /net/netfilter
parent9cb0176654a7dc33a32af8a0bc9e0b2f9f9ebb0f (diff)
netfilter: nfnetlink_queue: add NAT TCP sequence adjustment if packet mangled
User-space programs that receive traffic via NFQUEUE may mangle packets. If NAT is enabled, this usually puzzles sequence tracking, leading to traffic disruptions. With this patch, nfnl_queue will make the corresponding NAT TCP sequence adjustment if: 1) The packet has been mangled, 2) the NFQA_CFG_F_CONNTRACK flag has been set, and 3) NAT is detected. There are some records on the Internet complaning about this issue: http://stackoverflow.com/questions/260757/packet-mangling-utilities-besides-iptables By now, we only support TCP since we have no helpers for DCCP or SCTP. Better to add this if we ever have some helper over those layer 4 protocols. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_conntrack_netlink.c4
-rw-r--r--net/netfilter/nfnetlink_queue.c19
2 files changed, 15 insertions, 8 deletions
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index d304d5917950..8be0ab9b4758 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -46,6 +46,7 @@
46#ifdef CONFIG_NF_NAT_NEEDED 46#ifdef CONFIG_NF_NAT_NEEDED
47#include <net/netfilter/nf_nat_core.h> 47#include <net/netfilter/nf_nat_core.h>
48#include <net/netfilter/nf_nat_protocol.h> 48#include <net/netfilter/nf_nat_protocol.h>
49#include <net/netfilter/nf_nat_helper.h>
49#endif 50#endif
50 51
51#include <linux/netfilter/nfnetlink.h> 52#include <linux/netfilter/nfnetlink.h>
@@ -1751,6 +1752,9 @@ static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
1751 .build_size = ctnetlink_nfqueue_build_size, 1752 .build_size = ctnetlink_nfqueue_build_size,
1752 .build = ctnetlink_nfqueue_build, 1753 .build = ctnetlink_nfqueue_build,
1753 .parse = ctnetlink_nfqueue_parse, 1754 .parse = ctnetlink_nfqueue_parse,
1755#ifdef CONFIG_NF_NAT_NEEDED
1756 .seq_adjust = nf_nat_tcp_seq_adjust,
1757#endif
1754}; 1758};
1755#endif /* CONFIG_NETFILTER_NETLINK_QUEUE */ 1759#endif /* CONFIG_NETFILTER_NETLINK_QUEUE */
1756 1760
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 647923ae9230..ff82c7933dfd 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -502,12 +502,10 @@ err_out:
502} 502}
503 503
504static int 504static int
505nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e) 505nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff)
506{ 506{
507 struct sk_buff *nskb; 507 struct sk_buff *nskb;
508 int diff;
509 508
510 diff = data_len - e->skb->len;
511 if (diff < 0) { 509 if (diff < 0) {
512 if (pskb_trim(e->skb, data_len)) 510 if (pskb_trim(e->skb, data_len))
513 return -ENOMEM; 511 return -ENOMEM;
@@ -767,6 +765,8 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
767 unsigned int verdict; 765 unsigned int verdict;
768 struct nf_queue_entry *entry; 766 struct nf_queue_entry *entry;
769 struct nfq_ct_hook *nfq_ct; 767 struct nfq_ct_hook *nfq_ct;
768 enum ip_conntrack_info uninitialized_var(ctinfo);
769 struct nf_conn *ct = NULL;
770 770
771 queue = instance_lookup(queue_num); 771 queue = instance_lookup(queue_num);
772 if (!queue) 772 if (!queue)
@@ -789,20 +789,23 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
789 nfq_ct = rcu_dereference(nfq_ct_hook); 789 nfq_ct = rcu_dereference(nfq_ct_hook);
790 if (nfq_ct != NULL && 790 if (nfq_ct != NULL &&
791 (queue->flags & NFQA_CFG_F_CONNTRACK) && nfqa[NFQA_CT]) { 791 (queue->flags & NFQA_CFG_F_CONNTRACK) && nfqa[NFQA_CT]) {
792 enum ip_conntrack_info ctinfo;
793 struct nf_conn *ct;
794
795 ct = nf_ct_get(entry->skb, &ctinfo); 792 ct = nf_ct_get(entry->skb, &ctinfo);
796 if (ct && !nf_ct_is_untracked(ct)) 793 if (ct && !nf_ct_is_untracked(ct))
797 nfq_ct->parse(nfqa[NFQA_CT], ct); 794 nfq_ct->parse(nfqa[NFQA_CT], ct);
798 } 795 }
799 rcu_read_unlock();
800 796
801 if (nfqa[NFQA_PAYLOAD]) { 797 if (nfqa[NFQA_PAYLOAD]) {
798 u16 payload_len = nla_len(nfqa[NFQA_PAYLOAD]);
799 int diff = payload_len - entry->skb->len;
800
802 if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), 801 if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]),
803 nla_len(nfqa[NFQA_PAYLOAD]), entry) < 0) 802 payload_len, entry, diff) < 0)
804 verdict = NF_DROP; 803 verdict = NF_DROP;
804
805 if (ct && (ct->status & IPS_NAT_MASK) && diff)
806 nfq_ct->seq_adjust(skb, ct, ctinfo, diff);
805 } 807 }
808 rcu_read_unlock();
806 809
807 if (nfqa[NFQA_MARK]) 810 if (nfqa[NFQA_MARK])
808 entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK])); 811 entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));