diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/nft_chain_nat_ipv4.c | 157 |
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 | /* | 29 | static 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, | |
33 | static 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 | ||
87 | static unsigned int nf_nat_prerouting(const struct nf_hook_ops *ops, | 42 | static 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 | ||
104 | static unsigned int nf_nat_postrouting(const struct nf_hook_ops *ops, | 51 | static 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 | ||
131 | static unsigned int nf_nat_output(const struct nf_hook_ops *ops, | 60 | static 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 != | 69 | static 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 | ||
161 | static const struct nf_chain_type nft_chain_nat_ipv4 = { | 78 | static 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 | ||