1 /*
2 * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10 #include "internal/internal.h"
11
__autocomplete(struct nf_conntrack * ct,int dir)12 static void __autocomplete(struct nf_conntrack *ct, int dir)
13 {
14 struct __nfct_tuple *this = NULL, *other = NULL;
15
16 switch(dir) {
17 case __DIR_ORIG:
18 this = &ct->head.orig;
19 other = &ct->repl;
20 break;
21 case __DIR_REPL:
22 this = &ct->repl;
23 other = &ct->head.orig;
24 break;
25 }
26
27 this->l3protonum = other->l3protonum;
28 this->protonum = other->protonum;
29
30 memcpy(&this->src.v6, &other->dst.v6, sizeof(union __nfct_address));
31 memcpy(&this->dst.v6, &other->src.v6, sizeof(union __nfct_address));
32
33 switch(this->protonum) {
34 case IPPROTO_UDP:
35 case IPPROTO_TCP:
36 case IPPROTO_SCTP:
37 case IPPROTO_DCCP:
38 case IPPROTO_GRE:
39 case IPPROTO_UDPLITE:
40 this->l4src.all = other->l4dst.all;
41 this->l4dst.all = other->l4src.all;
42 break;
43 case IPPROTO_ICMP:
44 case IPPROTO_ICMPV6:
45 /* the setter already autocompletes the reply tuple. */
46 break;
47 }
48
49 /* XXX: this is safe but better convert bitset to uint64_t */
50 ct->head.set[0] |= TS_ORIG | TS_REPL;
51 }
52
setobjopt_undo_snat(struct nf_conntrack * ct)53 static void setobjopt_undo_snat(struct nf_conntrack *ct)
54 {
55 switch (ct->head.orig.l3protonum) {
56 case AF_INET:
57 ct->snat.min_ip.v4 = ct->repl.dst.v4;
58 ct->snat.max_ip.v4 = ct->snat.min_ip.v4;
59 ct->repl.dst.v4 = ct->head.orig.src.v4;
60 set_bit(ATTR_SNAT_IPV4, ct->head.set);
61 break;
62 case AF_INET6:
63 memcpy(&ct->snat.min_ip.v6, &ct->repl.dst.v6,
64 sizeof(struct in6_addr));
65 memcpy(&ct->snat.max_ip.v6, &ct->snat.min_ip.v6,
66 sizeof(struct in6_addr));
67 memcpy(&ct->repl.dst.v6, &ct->head.orig.src.v6,
68 sizeof(struct in6_addr));
69 set_bit(ATTR_SNAT_IPV6, ct->head.set);
70 break;
71 default:
72 break;
73 }
74 }
75
setobjopt_undo_dnat(struct nf_conntrack * ct)76 static void setobjopt_undo_dnat(struct nf_conntrack *ct)
77 {
78 switch (ct->head.orig.l3protonum) {
79 case AF_INET:
80 ct->dnat.min_ip.v4 = ct->repl.src.v4;
81 ct->dnat.max_ip.v4 = ct->dnat.min_ip.v4;
82 ct->repl.src.v4 = ct->head.orig.dst.v4;
83 set_bit(ATTR_DNAT_IPV4, ct->head.set);
84 case AF_INET6:
85 memcpy(&ct->dnat.min_ip.v6, &ct->repl.src.v6,
86 sizeof(struct in6_addr));
87 memcpy(&ct->dnat.max_ip.v6, &ct->dnat.min_ip.v6,
88 sizeof(struct in6_addr));
89 memcpy(&ct->repl.src.v6, &ct->head.orig.dst.v6,
90 sizeof(struct in6_addr));
91 set_bit(ATTR_DNAT_IPV6, ct->head.set);
92 break;
93 default:
94 break;
95 }
96 }
97
setobjopt_undo_spat(struct nf_conntrack * ct)98 static void setobjopt_undo_spat(struct nf_conntrack *ct)
99 {
100 ct->snat.l4min.all = ct->repl.l4dst.tcp.port;
101 ct->snat.l4max.all = ct->snat.l4min.all;
102 ct->repl.l4dst.tcp.port =
103 ct->head.orig.l4src.tcp.port;
104 set_bit(ATTR_SNAT_PORT, ct->head.set);
105 }
106
setobjopt_undo_dpat(struct nf_conntrack * ct)107 static void setobjopt_undo_dpat(struct nf_conntrack *ct)
108 {
109 ct->dnat.l4min.all = ct->repl.l4src.tcp.port;
110 ct->dnat.l4max.all = ct->dnat.l4min.all;
111 ct->repl.l4src.tcp.port =
112 ct->head.orig.l4dst.tcp.port;
113 set_bit(ATTR_DNAT_PORT, ct->head.set);
114 }
115
setobjopt_setup_orig(struct nf_conntrack * ct)116 static void setobjopt_setup_orig(struct nf_conntrack *ct)
117 {
118 __autocomplete(ct, __DIR_ORIG);
119 }
120
setobjopt_setup_repl(struct nf_conntrack * ct)121 static void setobjopt_setup_repl(struct nf_conntrack *ct)
122 {
123 __autocomplete(ct, __DIR_REPL);
124 }
125
126 static const setobjopt setobjopt_array[__NFCT_SOPT_MAX] = {
127 [NFCT_SOPT_UNDO_SNAT] = setobjopt_undo_snat,
128 [NFCT_SOPT_UNDO_DNAT] = setobjopt_undo_dnat,
129 [NFCT_SOPT_UNDO_SPAT] = setobjopt_undo_spat,
130 [NFCT_SOPT_UNDO_DPAT] = setobjopt_undo_dpat,
131 [NFCT_SOPT_SETUP_ORIGINAL] = setobjopt_setup_orig,
132 [NFCT_SOPT_SETUP_REPLY] = setobjopt_setup_repl,
133 };
134
__setobjopt(struct nf_conntrack * ct,unsigned int option)135 int __setobjopt(struct nf_conntrack *ct, unsigned int option)
136 {
137 if (unlikely(option > NFCT_SOPT_MAX))
138 return -1;
139
140 setobjopt_array[option](ct);
141 return 0;
142 }
143
getobjopt_is_snat(const struct nf_conntrack * ct)144 static int getobjopt_is_snat(const struct nf_conntrack *ct)
145 {
146 if (!(test_bit(ATTR_STATUS, ct->head.set)))
147 return 0;
148
149 if (!(ct->status & IPS_SRC_NAT_DONE))
150 return 0;
151
152 switch (ct->head.orig.l3protonum) {
153 case AF_INET:
154 return ct->repl.dst.v4 != ct->head.orig.src.v4;
155 case AF_INET6:
156 if (memcmp(&ct->repl.dst.v6, &ct->head.orig.src.v6,
157 sizeof(struct in6_addr)) != 0)
158 return 1;
159 else
160 return 0;
161 default:
162 return 0;
163 }
164 }
165
getobjopt_is_dnat(const struct nf_conntrack * ct)166 static int getobjopt_is_dnat(const struct nf_conntrack *ct)
167 {
168 if (!(test_bit(ATTR_STATUS, ct->head.set)))
169 return 0;
170
171 if (!(ct->status & IPS_DST_NAT_DONE))
172 return 0;
173
174 switch (ct->head.orig.l3protonum) {
175 case AF_INET:
176 return ct->repl.src.v4 != ct->head.orig.dst.v4;
177 case AF_INET6:
178 if (memcmp(&ct->repl.src.v6, &ct->head.orig.dst.v6,
179 sizeof(struct in6_addr)) != 0)
180 return 1;
181 else
182 return 0;
183 default:
184 return 0;
185 }
186 }
187
getobjopt_is_spat(const struct nf_conntrack * ct)188 static int getobjopt_is_spat(const struct nf_conntrack *ct)
189 {
190 return ((test_bit(ATTR_STATUS, ct->head.set) ?
191 ct->status & IPS_SRC_NAT_DONE : 1) &&
192 ct->repl.l4dst.tcp.port !=
193 ct->head.orig.l4src.tcp.port);
194 }
195
getobjopt_is_dpat(const struct nf_conntrack * ct)196 static int getobjopt_is_dpat(const struct nf_conntrack *ct)
197 {
198 return ((test_bit(ATTR_STATUS, ct->head.set) ?
199 ct->status & IPS_DST_NAT_DONE : 1) &&
200 ct->repl.l4src.tcp.port !=
201 ct->head.orig.l4dst.tcp.port);
202 }
203
204 static const getobjopt getobjopt_array[__NFCT_GOPT_MAX] = {
205 [NFCT_GOPT_IS_SNAT] = getobjopt_is_snat,
206 [NFCT_GOPT_IS_DNAT] = getobjopt_is_dnat,
207 [NFCT_GOPT_IS_SPAT] = getobjopt_is_spat,
208 [NFCT_GOPT_IS_DPAT] = getobjopt_is_dpat,
209 };
210
__getobjopt(const struct nf_conntrack * ct,unsigned int option)211 int __getobjopt(const struct nf_conntrack *ct, unsigned int option)
212 {
213 if (unlikely(option > NFCT_GOPT_MAX))
214 return -1;
215
216 return getobjopt_array[option](ct);
217 }
218