aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/nft_chain_nat_ipv4.c157
1 files changed, 37 insertions, 120 deletions
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
index 3964157d826c..df547bf50078 100644
--- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c
+++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
@@ -26,136 +26,53 @@
26#include <net/netfilter/nf_nat_l3proto.h> 26#include <net/netfilter/nf_nat_l3proto.h>
27#include <net/ip.h> 27#include <net/ip.h>
28 28
29/* 29static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops,
30 * NAT chains 30 struct sk_buff *skb,
31 */ 31 const struct net_device *in,
32 32 const struct net_device *out,
33static unsigned int nf_nat_fn(const struct nf_hook_ops *ops, 33 struct nf_conn *ct)
34 struct sk_buff *skb,
35 const struct net_device *in,
36 const struct net_device *out,
37 int (*okfn)(struct sk_buff *))
38{ 34{
39 enum ip_conntrack_info ctinfo;
40 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
41 struct nf_conn_nat *nat;
42 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
43 struct nft_pktinfo pkt; 35 struct nft_pktinfo pkt;
44 unsigned int ret;
45
46 if (ct == NULL || nf_ct_is_untracked(ct))
47 return NF_ACCEPT;
48
49 NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
50
51 nat = nf_ct_nat_ext_add(ct);
52 if (nat == NULL)
53 return NF_ACCEPT;
54
55 switch (ctinfo) {
56 case IP_CT_RELATED:
57 case IP_CT_RELATED + IP_CT_IS_REPLY:
58 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
59 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
60 ops->hooknum))
61 return NF_DROP;
62 else
63 return NF_ACCEPT;
64 }
65 /* Fall through */
66 case IP_CT_NEW:
67 if (nf_nat_initialized(ct, maniptype))
68 break;
69 36
70 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); 37 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
71 38
72 ret = nft_do_chain(&pkt, ops); 39 return nft_do_chain(&pkt, ops);
73 if (ret != NF_ACCEPT)
74 return ret;
75 if (!nf_nat_initialized(ct, maniptype)) {
76 ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
77 if (ret != NF_ACCEPT)
78 return ret;
79 }
80 default:
81 break;
82 }
83
84 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
85} 40}
86 41
87static unsigned int nf_nat_prerouting(const struct nf_hook_ops *ops, 42static unsigned int nft_nat_ipv4_fn(const struct nf_hook_ops *ops,
88 struct sk_buff *skb, 43 struct sk_buff *skb,
89 const struct net_device *in, 44 const struct net_device *in,
90 const struct net_device *out, 45 const struct net_device *out,
91 int (*okfn)(struct sk_buff *)) 46 int (*okfn)(struct sk_buff *))
92{ 47{
93 __be32 daddr = ip_hdr(skb)->daddr; 48 return nf_nat_ipv4_fn(ops, skb, in, out, nft_nat_do_chain);
94 unsigned int ret;
95
96 ret = nf_nat_fn(ops, skb, in, out, okfn);
97 if (ret != NF_DROP && ret != NF_STOLEN &&
98 ip_hdr(skb)->daddr != daddr) {
99 skb_dst_drop(skb);
100 }
101 return ret;
102} 49}
103 50
104static unsigned int nf_nat_postrouting(const struct nf_hook_ops *ops, 51static unsigned int nft_nat_ipv4_in(const struct nf_hook_ops *ops,
105 struct sk_buff *skb, 52 struct sk_buff *skb,
106 const struct net_device *in, 53 const struct net_device *in,
107 const struct net_device *out, 54 const struct net_device *out,
108 int (*okfn)(struct sk_buff *)) 55 int (*okfn)(struct sk_buff *))
109{ 56{
110 enum ip_conntrack_info ctinfo __maybe_unused; 57 return nf_nat_ipv4_in(ops, skb, in, out, nft_nat_do_chain);
111 const struct nf_conn *ct __maybe_unused;
112 unsigned int ret;
113
114 ret = nf_nat_fn(ops, skb, in, out, okfn);
115#ifdef CONFIG_XFRM
116 if (ret != NF_DROP && ret != NF_STOLEN &&
117 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
118 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
119
120 if (ct->tuplehash[dir].tuple.src.u3.ip !=
121 ct->tuplehash[!dir].tuple.dst.u3.ip ||
122 ct->tuplehash[dir].tuple.src.u.all !=
123 ct->tuplehash[!dir].tuple.dst.u.all)
124 return nf_xfrm_me_harder(skb, AF_INET) == 0 ?
125 ret : NF_DROP;
126 }
127#endif
128 return ret;
129} 58}
130 59
131static unsigned int nf_nat_output(const struct nf_hook_ops *ops, 60static unsigned int nft_nat_ipv4_out(const struct nf_hook_ops *ops,
132 struct sk_buff *skb, 61 struct sk_buff *skb,
133 const struct net_device *in, 62 const struct net_device *in,
134 const struct net_device *out, 63 const struct net_device *out,
135 int (*okfn)(struct sk_buff *)) 64 int (*okfn)(struct sk_buff *))
136{ 65{
137 enum ip_conntrack_info ctinfo; 66 return nf_nat_ipv4_out(ops, skb, in, out, nft_nat_do_chain);
138 const struct nf_conn *ct; 67}
139 unsigned int ret;
140
141 ret = nf_nat_fn(ops, skb, in, out, okfn);
142 if (ret != NF_DROP && ret != NF_STOLEN &&
143 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
144 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
145 68
146 if (ct->tuplehash[dir].tuple.dst.u3.ip != 69static unsigned int nft_nat_ipv4_local_fn(const struct nf_hook_ops *ops,
147 ct->tuplehash[!dir].tuple.src.u3.ip) { 70 struct sk_buff *skb,
148 if (ip_route_me_harder(skb, RTN_UNSPEC)) 71 const struct net_device *in,
149 ret = NF_DROP; 72 const struct net_device *out,
150 } 73 int (*okfn)(struct sk_buff *))
151#ifdef CONFIG_XFRM 74{
152 else if (ct->tuplehash[dir].tuple.dst.u.all != 75 return nf_nat_ipv4_local_fn(ops, skb, in, out, nft_nat_do_chain);
153 ct->tuplehash[!dir].tuple.src.u.all)
154 if (nf_xfrm_me_harder(skb, AF_INET))
155 ret = NF_DROP;
156#endif
157 }
158 return ret;
159} 76}
160 77
161static const struct nf_chain_type nft_chain_nat_ipv4 = { 78static const struct nf_chain_type nft_chain_nat_ipv4 = {
@@ -168,10 +85,10 @@ static const struct nf_chain_type nft_chain_nat_ipv4 = {
168 (1 << NF_INET_LOCAL_OUT) | 85 (1 << NF_INET_LOCAL_OUT) |
169 (1 << NF_INET_LOCAL_IN), 86 (1 << NF_INET_LOCAL_IN),
170 .hooks = { 87 .hooks = {
171 [NF_INET_PRE_ROUTING] = nf_nat_prerouting, 88 [NF_INET_PRE_ROUTING] = nft_nat_ipv4_in,
172 [NF_INET_POST_ROUTING] = nf_nat_postrouting, 89 [NF_INET_POST_ROUTING] = nft_nat_ipv4_out,
173 [NF_INET_LOCAL_OUT] = nf_nat_output, 90 [NF_INET_LOCAL_OUT] = nft_nat_ipv4_local_fn,
174 [NF_INET_LOCAL_IN] = nf_nat_fn, 91 [NF_INET_LOCAL_IN] = nft_nat_ipv4_fn,
175 }, 92 },
176}; 93};
177 94