libnl  1.1.4
ct.c
1 /*
2  * lib/netfilter/ct.c Conntrack
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
10  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
11  * Copyright (c) 2007 Secure Computing Corporation
12  */
13 
14 /**
15  * @ingroup nfnl
16  * @defgroup ct Conntrack
17  * @brief
18  * @{
19  */
20 
21 #include <byteswap.h>
22 #include <sys/types.h>
23 #include <linux/netfilter/nfnetlink_conntrack.h>
24 
25 #include <netlink-local.h>
26 #include <netlink/attr.h>
27 #include <netlink/netfilter/nfnl.h>
28 #include <netlink/netfilter/ct.h>
29 
30 static struct nl_cache_ops nfnl_ct_ops;
31 
32 #if __BYTE_ORDER == __BIG_ENDIAN
33 static uint64_t ntohll(uint64_t x)
34 {
35  return x;
36 }
37 #elif __BYTE_ORDER == __LITTLE_ENDIAN
38 static uint64_t ntohll(uint64_t x)
39 {
40  return __bswap_64(x);
41 }
42 #endif
43 
44 static struct nla_policy ct_policy[CTA_MAX+1] = {
45  [CTA_TUPLE_ORIG] = { .type = NLA_NESTED },
46  [CTA_TUPLE_REPLY] = { .type = NLA_NESTED },
47  [CTA_STATUS] = { .type = NLA_U32 },
48  [CTA_PROTOINFO] = { .type = NLA_NESTED },
49  //[CTA_HELP]
50  //[CTA_NAT_SRC]
51  [CTA_TIMEOUT] = { .type = NLA_U32 },
52  [CTA_MARK] = { .type = NLA_U32 },
53  [CTA_COUNTERS_ORIG] = { .type = NLA_NESTED },
54  [CTA_COUNTERS_REPLY] = { .type = NLA_NESTED },
55  [CTA_USE] = { .type = NLA_U32 },
56  [CTA_ID] = { .type = NLA_U32 },
57  //[CTA_NAT_DST]
58 };
59 
60 static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
61  [CTA_TUPLE_IP] = { .type = NLA_NESTED },
62  [CTA_TUPLE_PROTO] = { .type = NLA_NESTED },
63 };
64 
65 static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
66  [CTA_IP_V4_SRC] = { .type = NLA_U32 },
67  [CTA_IP_V4_DST] = { .type = NLA_U32 },
68  [CTA_IP_V6_SRC] = { .minlen = 16 },
69  [CTA_IP_V6_DST] = { .minlen = 16 },
70 };
71 
72 static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
73  [CTA_PROTO_NUM] = { .type = NLA_U8 },
74  [CTA_PROTO_SRC_PORT] = { .type = NLA_U16 },
75  [CTA_PROTO_DST_PORT] = { .type = NLA_U16 },
76  [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 },
77  [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 },
78  [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 },
79  [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 },
80  [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 },
81  [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 },
82 };
83 
84 static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
85  [CTA_PROTOINFO_TCP] = { .type = NLA_NESTED },
86 };
87 
88 static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
89  [CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 },
90  [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 },
91  [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 },
92  [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .minlen = 2 },
93  [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .minlen = 2 },
94 
95 };
96 
97 static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
98  [CTA_COUNTERS_PACKETS] = { .type = NLA_U64 },
99  [CTA_COUNTERS_BYTES] = { .type = NLA_U64 },
100  [CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
101  [CTA_COUNTERS32_BYTES] = { .type = NLA_U32 },
102 };
103 
104 static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
105 {
106  struct nlattr *tb[CTA_IP_MAX+1];
107  struct nl_addr *addr;
108  int err;
109 
110  err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
111  if (err < 0)
112  goto errout;
113 
114  if (tb[CTA_IP_V4_SRC]) {
115  addr = nla_get_addr(tb[CTA_IP_V4_SRC], AF_INET);
116  if (addr == NULL)
117  goto errout_errno;
118  err = nfnl_ct_set_src(ct, repl, addr);
119  nl_addr_put(addr);
120  if (err < 0)
121  goto errout;
122  }
123  if (tb[CTA_IP_V4_DST]) {
124  addr = nla_get_addr(tb[CTA_IP_V4_DST], AF_INET);
125  if (addr == NULL)
126  goto errout_errno;
127  err = nfnl_ct_set_dst(ct, repl, addr);
128  nl_addr_put(addr);
129  if (err < 0)
130  goto errout;
131  }
132  if (tb[CTA_IP_V6_SRC]) {
133  addr = nla_get_addr(tb[CTA_IP_V6_SRC], AF_INET6);
134  if (addr == NULL)
135  goto errout_errno;
136  err = nfnl_ct_set_src(ct, repl, addr);
137  nl_addr_put(addr);
138  if (err < 0)
139  goto errout;
140  }
141  if (tb[CTA_IP_V6_DST]) {
142  addr = nla_get_addr(tb[CTA_IP_V6_DST], AF_INET6);
143  if (addr == NULL)
144  goto errout_errno;
145  err = nfnl_ct_set_dst(ct, repl, addr);
146  nl_addr_put(addr);
147  if (err < 0)
148  goto errout;
149  }
150 
151  return 0;
152 
153 errout_errno:
154  return nl_get_errno();
155 errout:
156  return err;
157 }
158 
159 static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
160 {
161  struct nlattr *tb[CTA_PROTO_MAX+1];
162  int err;
163 
164  err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
165  if (err < 0)
166  return err;
167 
168  if (!repl && tb[CTA_PROTO_NUM])
169  nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
170  if (tb[CTA_PROTO_SRC_PORT])
171  nfnl_ct_set_src_port(ct, repl,
172  nla_get_u16(tb[CTA_PROTO_SRC_PORT]));
173  if (tb[CTA_PROTO_DST_PORT])
174  nfnl_ct_set_dst_port(ct, repl,
175  nla_get_u16(tb[CTA_PROTO_DST_PORT]));
176  if (tb[CTA_PROTO_ICMP_ID])
177  nfnl_ct_set_icmp_id(ct, repl,
178  nla_get_u16(tb[CTA_PROTO_ICMP_ID]));
179  if (tb[CTA_PROTO_ICMP_TYPE])
180  nfnl_ct_set_icmp_type(ct, repl,
181  nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
182  if (tb[CTA_PROTO_ICMP_CODE])
183  nfnl_ct_set_icmp_code(ct, repl,
184  nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
185 
186  return 0;
187 }
188 
189 static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
190 {
191  struct nlattr *tb[CTA_TUPLE_MAX+1];
192  int err;
193 
194  err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
195  if (err < 0)
196  return err;
197 
198  if (tb[CTA_TUPLE_IP]) {
199  err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
200  if (err < 0)
201  return err;
202  }
203 
204  if (tb[CTA_TUPLE_PROTO]) {
205  err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
206  if (err < 0)
207  return err;
208  }
209 
210  return 0;
211 }
212 
213 static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
214 {
215  struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
216  int err;
217 
218  err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
219  ct_protoinfo_tcp_policy);
220  if (err < 0)
221  return err;
222 
223  if (tb[CTA_PROTOINFO_TCP_STATE])
224  nfnl_ct_set_tcp_state(ct,
225  nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
226 
227  return 0;
228 }
229 
230 static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
231 {
232  struct nlattr *tb[CTA_PROTOINFO_MAX+1];
233  int err;
234 
235  err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
236  ct_protoinfo_policy);
237  if (err < 0)
238  return err;
239 
240  if (tb[CTA_PROTOINFO_TCP]) {
241  err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
242  if (err < 0)
243  return err;
244  }
245 
246  return 0;
247 }
248 
249 static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
250 {
251  struct nlattr *tb[CTA_COUNTERS_MAX+1];
252  int err;
253 
254  err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
255  if (err < 0)
256  return err;
257 
258  if (tb[CTA_COUNTERS_PACKETS])
259  nfnl_ct_set_packets(ct, repl,
260  ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
261  if (tb[CTA_COUNTERS32_PACKETS])
262  nfnl_ct_set_packets(ct, repl,
263  ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
264  if (tb[CTA_COUNTERS_BYTES])
265  nfnl_ct_set_bytes(ct, repl,
266  ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
267  if (tb[CTA_COUNTERS32_BYTES])
268  nfnl_ct_set_bytes(ct, repl,
269  ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
270 
271  return 0;
272 }
273 
274 int nfnlmsg_ct_group(struct nlmsghdr *nlh)
275 {
276  switch (nfnlmsg_subtype(nlh)) {
277  case IPCTNL_MSG_CT_NEW:
278  if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
279  return NFNLGRP_CONNTRACK_NEW;
280  else
281  return NFNLGRP_CONNTRACK_UPDATE;
282  case IPCTNL_MSG_CT_DELETE:
283  return NFNLGRP_CONNTRACK_DESTROY;
284  default:
285  return NFNLGRP_NONE;
286  }
287 }
288 
289 struct nfnl_ct *nfnlmsg_ct_parse(struct nlmsghdr *nlh)
290 {
291  struct nfnl_ct *ct;
292  struct nlattr *tb[CTA_MAX+1];
293  int err;
294 
295  ct = nfnl_ct_alloc();
296  if (!ct)
297  return NULL;
298 
299  ct->ce_msgtype = nlh->nlmsg_type;
300 
301  err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
302  ct_policy);
303  if (err < 0)
304  goto errout;
305 
306  nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
307 
308  if (tb[CTA_TUPLE_ORIG]) {
309  err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
310  if (err < 0)
311  goto errout;
312  }
313  if (tb[CTA_TUPLE_REPLY]) {
314  err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
315  if (err < 0)
316  goto errout;
317  }
318 
319  if (tb[CTA_PROTOINFO]) {
320  err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
321  if (err < 0)
322  goto errout;
323  }
324 
325  if (tb[CTA_STATUS])
326  nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
327  if (tb[CTA_TIMEOUT])
328  nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
329  if (tb[CTA_MARK])
330  nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
331  if (tb[CTA_USE])
332  nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
333  if (tb[CTA_ID])
334  nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
335 
336  if (tb[CTA_COUNTERS_ORIG]) {
337  err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
338  if (err < 0)
339  goto errout;
340  }
341 
342  if (tb[CTA_COUNTERS_REPLY]) {
343  err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
344  if (err < 0)
345  goto errout;
346  }
347 
348  return ct;
349 
350 errout:
351  nfnl_ct_put(ct);
352  return NULL;
353 }
354 
355 static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
356  struct nlmsghdr *nlh, struct nl_parser_param *pp)
357 {
358  struct nfnl_ct *ct;
359  int err;
360 
361  ct = nfnlmsg_ct_parse(nlh);
362  if (ct == NULL)
363  goto errout_errno;
364 
365  err = pp->pp_cb((struct nl_object *) ct, pp);
366  if (err < 0)
367  goto errout;
368 
369  err = P_ACCEPT;
370 
371 errout:
372  nfnl_ct_put(ct);
373  return err;
374 
375 errout_errno:
376  err = nl_get_errno();
377  goto errout;
378 }
379 
380 int nfnl_ct_dump_request(struct nl_handle *h)
381 {
382  return nfnl_send_simple(h, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
383  NLM_F_DUMP, AF_UNSPEC, 0);
384 }
385 
386 static int ct_request_update(struct nl_cache *c, struct nl_handle *h)
387 {
388  return nfnl_ct_dump_request(h);
389 }
390 
391 /**
392  * @name Cache Management
393  * @{
394  */
395 
396 /**
397  * Build a conntrack cache holding all conntrack currently in the kernel
398  * @arg handle netlink handle
399  *
400  * Allocates a new cache, initializes it properly and updates it to
401  * contain all conntracks currently in the kernel.
402  *
403  * @note The caller is responsible for destroying and freeing the
404  * cache after using it.
405  * @return The cache or NULL if an error has occured.
406  */
407 struct nl_cache *nfnl_ct_alloc_cache(struct nl_handle *handle)
408 {
409  struct nl_cache *cache;
410 
411  cache = nl_cache_alloc(&nfnl_ct_ops);
412  if (!cache)
413  return NULL;
414 
415  if (handle && nl_cache_refill(handle, cache) < 0) {
416  free(cache);
417  return NULL;
418  }
419 
420  return cache;
421 }
422 
423 /** @} */
424 
425 /**
426  * @name Conntrack Addition
427  * @{
428  */
429 
430 /** @} */
431 
432 static struct nl_af_group ct_groups[] = {
433  { AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
434  { AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
435  { AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
436  { END_OF_GROUP_LIST },
437 };
438 
439 #define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
440 static struct nl_cache_ops nfnl_ct_ops = {
441  .co_name = "netfilter/ct",
442  .co_hdrsize = NFNL_HDRLEN,
443  .co_msgtypes = {
444  { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
445  { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
446  { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
447  END_OF_MSGTYPES_LIST,
448  },
449  .co_protocol = NETLINK_NETFILTER,
450  .co_groups = ct_groups,
451  .co_request_update = ct_request_update,
452  .co_msg_parser = ct_msg_parser,
453  .co_obj_ops = &ct_obj_ops,
454 };
455 
456 static void __init ct_init(void)
457 {
458  nl_cache_mngt_register(&nfnl_ct_ops);
459 }
460 
461 static void __exit ct_exit(void)
462 {
463  nl_cache_mngt_unregister(&nfnl_ct_ops);
464 }
465 
466 /** @} */