libnetfilter_conntrack  1.0.6
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 
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 
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 
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  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 
99 static 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 
108 static 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 
117 static void setobjopt_setup_orig(struct nf_conntrack *ct)
118 {
119  __autocomplete(ct, __DIR_ORIG);
120 }
121 
122 static void setobjopt_setup_repl(struct nf_conntrack *ct)
123 {
124  __autocomplete(ct, __DIR_REPL);
125 }
126 
127 static 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 
136 int __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 
145 static 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 
165 static 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 
185 static 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 
193 static 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 
201 static 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 
208 int __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 }