libnetfilter_conntrack 1.0.9
objopt.c
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
12static 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
53static 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
76static 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 break;
85 case AF_INET6:
86 memcpy(&ct->dnat.min_ip.v6, &ct->repl.src.v6,
87 sizeof(struct in6_addr));
88 memcpy(&ct->dnat.max_ip.v6, &ct->dnat.min_ip.v6,
89 sizeof(struct in6_addr));
90 memcpy(&ct->repl.src.v6, &ct->head.orig.dst.v6,
91 sizeof(struct in6_addr));
92 set_bit(ATTR_DNAT_IPV6, ct->head.set);
93 break;
94 default:
95 break;
96 }
97}
98
99static void setobjopt_undo_spat(struct nf_conntrack *ct)
100{
101 ct->snat.l4min.all = ct->repl.l4dst.tcp.port;
102 ct->snat.l4max.all = ct->snat.l4min.all;
103 ct->repl.l4dst.tcp.port =
104 ct->head.orig.l4src.tcp.port;
105 set_bit(ATTR_SNAT_PORT, ct->head.set);
106}
107
108static void setobjopt_undo_dpat(struct nf_conntrack *ct)
109{
110 ct->dnat.l4min.all = ct->repl.l4src.tcp.port;
111 ct->dnat.l4max.all = ct->dnat.l4min.all;
112 ct->repl.l4src.tcp.port =
113 ct->head.orig.l4dst.tcp.port;
114 set_bit(ATTR_DNAT_PORT, ct->head.set);
115}
116
117static void setobjopt_setup_orig(struct nf_conntrack *ct)
118{
119 __autocomplete(ct, __DIR_ORIG);
120}
121
122static void setobjopt_setup_repl(struct nf_conntrack *ct)
123{
124 __autocomplete(ct, __DIR_REPL);
125}
126
127static const setobjopt setobjopt_array[__NFCT_SOPT_MAX] = {
128 [NFCT_SOPT_UNDO_SNAT] = setobjopt_undo_snat,
129 [NFCT_SOPT_UNDO_DNAT] = setobjopt_undo_dnat,
130 [NFCT_SOPT_UNDO_SPAT] = setobjopt_undo_spat,
131 [NFCT_SOPT_UNDO_DPAT] = setobjopt_undo_dpat,
132 [NFCT_SOPT_SETUP_ORIGINAL] = setobjopt_setup_orig,
133 [NFCT_SOPT_SETUP_REPLY] = setobjopt_setup_repl,
134};
135
136int __setobjopt(struct nf_conntrack *ct, unsigned int option)
137{
138 if (unlikely(option > NFCT_SOPT_MAX))
139 return -1;
140
141 setobjopt_array[option](ct);
142 return 0;
143}
144
145static int getobjopt_is_snat(const struct nf_conntrack *ct)
146{
147 if (test_bit(ATTR_STATUS, ct->head.set) &&
148 !(ct->status & IPS_SRC_NAT_DONE))
149 return 0;
150
151 switch (ct->head.orig.l3protonum) {
152 case AF_INET:
153 return ct->repl.dst.v4 != ct->head.orig.src.v4;
154 case AF_INET6:
155 if (memcmp(&ct->repl.dst.v6, &ct->head.orig.src.v6,
156 sizeof(struct in6_addr)) != 0)
157 return 1;
158 else
159 return 0;
160 default:
161 return 0;
162 }
163}
164
165static int getobjopt_is_dnat(const struct nf_conntrack *ct)
166{
167 if (test_bit(ATTR_STATUS, ct->head.set) &&
168 !(ct->status & IPS_DST_NAT_DONE))
169 return 0;
170
171 switch (ct->head.orig.l3protonum) {
172 case AF_INET:
173 return ct->repl.src.v4 != ct->head.orig.dst.v4;
174 case AF_INET6:
175 if (memcmp(&ct->repl.src.v6, &ct->head.orig.dst.v6,
176 sizeof(struct in6_addr)) != 0)
177 return 1;
178 else
179 return 0;
180 default:
181 return 0;
182 }
183}
184
185static int getobjopt_is_spat(const struct nf_conntrack *ct)
186{
187 return ((test_bit(ATTR_STATUS, ct->head.set) ?
188 ct->status & IPS_SRC_NAT_DONE : 1) &&
189 ct->repl.l4dst.tcp.port !=
190 ct->head.orig.l4src.tcp.port);
191}
192
193static int getobjopt_is_dpat(const struct nf_conntrack *ct)
194{
195 return ((test_bit(ATTR_STATUS, ct->head.set) ?
196 ct->status & IPS_DST_NAT_DONE : 1) &&
197 ct->repl.l4src.tcp.port !=
198 ct->head.orig.l4dst.tcp.port);
199}
200
201static const getobjopt getobjopt_array[__NFCT_GOPT_MAX] = {
202 [NFCT_GOPT_IS_SNAT] = getobjopt_is_snat,
203 [NFCT_GOPT_IS_DNAT] = getobjopt_is_dnat,
204 [NFCT_GOPT_IS_SPAT] = getobjopt_is_spat,
205 [NFCT_GOPT_IS_DPAT] = getobjopt_is_dpat,
206};
207
208int __getobjopt(const struct nf_conntrack *ct, unsigned int option)
209{
210 if (unlikely(option > NFCT_GOPT_MAX))
211 return -1;
212
213 return getobjopt_array[option](ct);
214}