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
30static struct nl_cache_ops nfnl_ct_ops;
31
32#if __BYTE_ORDER == __BIG_ENDIAN
33static uint64_t ntohll(uint64_t x)
34{
35 return x;
36}
37#elif __BYTE_ORDER == __LITTLE_ENDIAN
38static uint64_t ntohll(uint64_t x)
39{
40 return __bswap_64(x);
41}
42#endif
43
44static 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
60static 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
65static 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
72static 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
84static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
85 [CTA_PROTOINFO_TCP] = { .type = NLA_NESTED },
86};
87
88static 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
97static 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
104static 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
153errout_errno:
154 return nl_get_errno();
155errout:
156 return err;
157}
158
159static 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
189static 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
213static 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
230static 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
249static 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
274int nfnlmsg_ct_group(struct nlmsghdr *nlh)
275{
276 switch (nfnlmsg_subtype(nlh)) {
277 case IPCTNL_MSG_CT_NEW:
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
289struct 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
350errout:
351 nfnl_ct_put(ct);
352 return NULL;
353}
354
355static 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
371errout:
372 nfnl_ct_put(ct);
373 return err;
374
375errout_errno:
376 err = nl_get_errno();
377 goto errout;
378}
379
380int 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
386static 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 */
407struct 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
432static 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))
440static 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
456static void __init ct_init(void)
457{
458 nl_cache_mngt_register(&nfnl_ct_ops);
459}
460
461static void __exit ct_exit(void)
462{
463 nl_cache_mngt_unregister(&nfnl_ct_ops);
464}
465
466/** @} */
struct nl_addr * nla_get_addr(struct nlattr *nla, int family)
Return payload of address attribute.
Definition: attr.c:765
uint64_t nla_get_u64(struct nlattr *nla)
Return payload of u64 attribute.
Definition: attr.c:720
uint16_t nla_get_u16(struct nlattr *nla)
Return payload of u16 attribute.
Definition: attr.c:702
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, struct nla_policy *policy)
parse nested attributes
Definition: attr.c:307
uint8_t nla_get_u8(struct nlattr *nla)
Return payload of u8 attribute.
Definition: attr.c:711
uint32_t nla_get_u32(struct nlattr *nla)
Return payload of u32 attribute.
Definition: attr.c:693
@ NLA_U64
64bit integer
Definition: attr.h:40
@ NLA_U8
8bit integer
Definition: attr.h:37
@ NLA_U16
16bit integer
Definition: attr.h:38
@ NLA_NESTED
nested attributes
Definition: attr.h:44
@ NLA_U32
32bit integer
Definition: attr.h:39
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:261
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:226
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate an empty cache.
Definition: cache.c:170
int nl_cache_refill(struct nl_handle *handle, struct nl_cache *cache)
(Re)fill a cache with the contents in the kernel.
Definition: cache.c:680
struct nl_cache * nfnl_ct_alloc_cache(struct nl_handle *handle)
Build a conntrack cache holding all conntrack currently in the kernel.
Definition: ct.c:407
#define NLM_F_EXCL
Don't replace the config object if it already exists.
#define NLM_F_CREATE
Create config object if it doesn't already exist.
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, struct nla_policy *policy)
parse attributes of a netlink message
Definition: msg.c:319
#define NLM_F_DUMP
Dump all entries.
int nfnl_send_simple(struct nl_handle *handle, uint8_t subsys_id, uint8_t type, int flags, uint8_t family, uint16_t res_id)
Send trivial netfilter netlink message.
Definition: nfnl.c:108
uint8_t nfnlmsg_family(struct nlmsghdr *nlh)
Get netfilter family from message.
Definition: nfnl.c:150
uint8_t nfnlmsg_subtype(struct nlmsghdr *nlh)
Get netfilter message type from message.
Definition: nfnl.c:141
Address family to netlink group association.
Definition: cache-api.h:144
Cache Operations.
Definition: cache-api.h:164
attribute validation policy
Definition: attr.h:73
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:75
Netlink message header.
uint16_t nlmsg_type
Message type (content type)
uint16_t nlmsg_flags
Message flags.
Netlink socket address.
Definition: netlink-kernel.h:9