1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2003-2008 Thomas Graf <[email protected]>
4 * Copyright (c) 2007 Philip Craig <[email protected]>
5 * Copyright (c) 2007 Secure Computing Corporation
6 * Copyright (c) 2008 Patrick McHardy <[email protected]>
7 */
8
9 /**
10 * @ingroup nfnl
11 * @defgroup ct Conntrack
12 * @brief
13 * @{
14 */
15
16 #include "nl-default.h"
17
18 #include <sys/types.h>
19
20 #include <linux/netfilter/nfnetlink_conntrack.h>
21
22 #include <netlink/attr.h>
23 #include <netlink/netfilter/nfnl.h>
24 #include <netlink/netfilter/ct.h>
25
26 #include "nl-netfilter.h"
27 #include "nl-priv-dynamic-core/nl-core.h"
28 #include "nl-priv-dynamic-core/cache-api.h"
29
30 static struct nl_cache_ops nfnl_ct_ops;
31
32
33 static struct nla_policy ct_policy[CTA_MAX+1] = {
34 [CTA_TUPLE_ORIG] = { .type = NLA_NESTED },
35 [CTA_TUPLE_REPLY] = { .type = NLA_NESTED },
36 [CTA_STATUS] = { .type = NLA_U32 },
37 [CTA_PROTOINFO] = { .type = NLA_NESTED },
38 //[CTA_HELP]
39 //[CTA_NAT_SRC]
40 [CTA_TIMEOUT] = { .type = NLA_U32 },
41 [CTA_MARK] = { .type = NLA_U32 },
42 [CTA_COUNTERS_ORIG] = { .type = NLA_NESTED },
43 [CTA_COUNTERS_REPLY] = { .type = NLA_NESTED },
44 [CTA_USE] = { .type = NLA_U32 },
45 [CTA_ID] = { .type = NLA_U32 },
46 [CTA_ZONE] = { .type = NLA_U16 },
47 //[CTA_NAT_DST]
48 };
49
50 static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
51 [CTA_TUPLE_IP] = { .type = NLA_NESTED },
52 [CTA_TUPLE_PROTO] = { .type = NLA_NESTED },
53 };
54
55 static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
56 [CTA_IP_V4_SRC] = { .type = NLA_U32 },
57 [CTA_IP_V4_DST] = { .type = NLA_U32 },
58 [CTA_IP_V6_SRC] = { .minlen = 16 },
59 [CTA_IP_V6_DST] = { .minlen = 16 },
60 };
61
62 static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
63 [CTA_PROTO_NUM] = { .type = NLA_U8 },
64 [CTA_PROTO_SRC_PORT] = { .type = NLA_U16 },
65 [CTA_PROTO_DST_PORT] = { .type = NLA_U16 },
66 [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 },
67 [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 },
68 [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 },
69 [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 },
70 [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 },
71 [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 },
72 };
73
74 static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
75 [CTA_PROTOINFO_TCP] = { .type = NLA_NESTED },
76 };
77
78 static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
79 [CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 },
80 [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 },
81 [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 },
82 [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .minlen = 2 },
83 [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .minlen = 2 },
84
85 };
86
87 static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
88 [CTA_COUNTERS_PACKETS] = { .type = NLA_U64 },
89 [CTA_COUNTERS_BYTES] = { .type = NLA_U64 },
90 [CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
91 [CTA_COUNTERS32_BYTES] = { .type = NLA_U32 },
92 };
93
94 static struct nla_policy ct_timestamp_policy[CTA_TIMESTAMP_MAX + 1] = {
95 [CTA_TIMESTAMP_START] = { .type = NLA_U64 },
96 [CTA_TIMESTAMP_STOP] = { .type = NLA_U64 },
97 };
98
ct_parse_ip(struct nfnl_ct * ct,int repl,struct nlattr * attr)99 static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
100 {
101 struct nlattr *tb[CTA_IP_MAX+1];
102 struct nl_addr *addr;
103 int err;
104
105 err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
106 if (err < 0)
107 goto errout;
108
109 if (tb[CTA_IP_V4_SRC]) {
110 addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
111 if (addr == NULL)
112 goto errout_enomem;
113 err = nfnl_ct_set_src(ct, repl, addr);
114 nl_addr_put(addr);
115 if (err < 0)
116 goto errout;
117 }
118 if (tb[CTA_IP_V4_DST]) {
119 addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
120 if (addr == NULL)
121 goto errout_enomem;
122 err = nfnl_ct_set_dst(ct, repl, addr);
123 nl_addr_put(addr);
124 if (err < 0)
125 goto errout;
126 }
127 if (tb[CTA_IP_V6_SRC]) {
128 addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
129 if (addr == NULL)
130 goto errout_enomem;
131 err = nfnl_ct_set_src(ct, repl, addr);
132 nl_addr_put(addr);
133 if (err < 0)
134 goto errout;
135 }
136 if (tb[CTA_IP_V6_DST]) {
137 addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
138 if (addr == NULL)
139 goto errout_enomem;
140 err = nfnl_ct_set_dst(ct, repl, addr);
141 nl_addr_put(addr);
142 if (err < 0)
143 goto errout;
144 }
145
146 return 0;
147
148 errout_enomem:
149 err = -NLE_NOMEM;
150 errout:
151 return err;
152 }
153
ct_parse_proto(struct nfnl_ct * ct,int repl,struct nlattr * attr)154 static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
155 {
156 struct nlattr *tb[CTA_PROTO_MAX+1];
157 int err;
158
159 err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
160 if (err < 0)
161 return err;
162
163 if (!repl && tb[CTA_PROTO_NUM])
164 nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
165 if (tb[CTA_PROTO_SRC_PORT])
166 nfnl_ct_set_src_port(ct, repl,
167 ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT])));
168 if (tb[CTA_PROTO_DST_PORT])
169 nfnl_ct_set_dst_port(ct, repl,
170 ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
171
172 if (ct->ct_family == AF_INET) {
173 if (tb[CTA_PROTO_ICMP_ID])
174 nfnl_ct_set_icmp_id(ct, repl,
175 ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
176 if (tb[CTA_PROTO_ICMP_TYPE])
177 nfnl_ct_set_icmp_type(ct, repl,
178 nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
179 if (tb[CTA_PROTO_ICMP_CODE])
180 nfnl_ct_set_icmp_code(ct, repl,
181 nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
182 } else if (ct->ct_family == AF_INET6) {
183 if (tb[CTA_PROTO_ICMPV6_ID])
184 nfnl_ct_set_icmp_id(ct, repl,
185 ntohs(nla_get_u16(tb[CTA_PROTO_ICMPV6_ID])));
186 if (tb[CTA_PROTO_ICMPV6_TYPE])
187 nfnl_ct_set_icmp_type(ct, repl,
188 nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]));
189 if (tb[CTA_PROTO_ICMPV6_CODE])
190 nfnl_ct_set_icmp_code(ct, repl,
191 nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]));
192 }
193
194 return 0;
195 }
196
ct_parse_tuple(struct nfnl_ct * ct,int repl,struct nlattr * attr)197 static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
198 {
199 struct nlattr *tb[CTA_TUPLE_MAX+1];
200 int err;
201
202 err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
203 if (err < 0)
204 return err;
205
206 if (tb[CTA_TUPLE_IP]) {
207 err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
208 if (err < 0)
209 return err;
210 }
211
212 if (tb[CTA_TUPLE_PROTO]) {
213 err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
214 if (err < 0)
215 return err;
216 }
217
218 return 0;
219 }
220
ct_parse_protoinfo_tcp(struct nfnl_ct * ct,struct nlattr * attr)221 static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
222 {
223 struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
224 int err;
225
226 err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
227 ct_protoinfo_tcp_policy);
228 if (err < 0)
229 return err;
230
231 if (tb[CTA_PROTOINFO_TCP_STATE])
232 nfnl_ct_set_tcp_state(ct,
233 nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
234
235 return 0;
236 }
237
ct_parse_protoinfo(struct nfnl_ct * ct,struct nlattr * attr)238 static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
239 {
240 struct nlattr *tb[CTA_PROTOINFO_MAX+1];
241 int err;
242
243 err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
244 ct_protoinfo_policy);
245 if (err < 0)
246 return err;
247
248 if (tb[CTA_PROTOINFO_TCP]) {
249 err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
250 if (err < 0)
251 return err;
252 }
253
254 return 0;
255 }
256
ct_parse_counters(struct nfnl_ct * ct,int repl,struct nlattr * attr)257 static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
258 {
259 struct nlattr *tb[CTA_COUNTERS_MAX+1];
260 int err;
261
262 err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
263 if (err < 0)
264 return err;
265
266 if (tb[CTA_COUNTERS_PACKETS])
267 nfnl_ct_set_packets(ct, repl,
268 ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
269 if (tb[CTA_COUNTERS32_PACKETS])
270 nfnl_ct_set_packets(ct, repl,
271 ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
272 if (tb[CTA_COUNTERS_BYTES])
273 nfnl_ct_set_bytes(ct, repl,
274 ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
275 if (tb[CTA_COUNTERS32_BYTES])
276 nfnl_ct_set_bytes(ct, repl,
277 ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
278
279 return 0;
280 }
281
nfnlmsg_ct_group(struct nlmsghdr * nlh)282 int nfnlmsg_ct_group(struct nlmsghdr *nlh)
283 {
284 switch (nfnlmsg_subtype(nlh)) {
285 case IPCTNL_MSG_CT_NEW:
286 if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
287 return NFNLGRP_CONNTRACK_NEW;
288 else
289 return NFNLGRP_CONNTRACK_UPDATE;
290 case IPCTNL_MSG_CT_DELETE:
291 return NFNLGRP_CONNTRACK_DESTROY;
292 default:
293 return NFNLGRP_NONE;
294 }
295 }
296
ct_parse_timestamp(struct nfnl_ct * ct,struct nlattr * attr)297 static int ct_parse_timestamp(struct nfnl_ct *ct, struct nlattr *attr)
298 {
299 struct nlattr *tb[CTA_TIMESTAMP_MAX + 1];
300 int err;
301
302 err = nla_parse_nested(tb, CTA_TIMESTAMP_MAX, attr,
303 ct_timestamp_policy);
304 if (err < 0)
305 return err;
306
307 if (tb[CTA_TIMESTAMP_START] && tb[CTA_TIMESTAMP_STOP])
308 nfnl_ct_set_timestamp(ct,
309 ntohll(nla_get_u64(tb[CTA_TIMESTAMP_START])),
310 ntohll(nla_get_u64(tb[CTA_TIMESTAMP_STOP])));
311
312 return 0;
313 }
314
_nfnlmsg_ct_parse(struct nlattr ** tb,struct nfnl_ct * ct)315 static int _nfnlmsg_ct_parse(struct nlattr **tb, struct nfnl_ct *ct)
316 {
317 int err;
318
319 if (tb[CTA_TUPLE_ORIG]) {
320 err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
321 if (err < 0)
322 return err;
323 }
324 if (tb[CTA_TUPLE_REPLY]) {
325 err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
326 if (err < 0)
327 return err;
328 }
329
330 if (tb[CTA_PROTOINFO]) {
331 err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
332 if (err < 0)
333 return err;
334 }
335
336 if (tb[CTA_STATUS])
337 nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
338 if (tb[CTA_TIMEOUT])
339 nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
340 if (tb[CTA_MARK])
341 nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
342 if (tb[CTA_USE])
343 nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
344 if (tb[CTA_ID])
345 nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
346 if (tb[CTA_ZONE])
347 nfnl_ct_set_zone(ct, ntohs(nla_get_u16(tb[CTA_ZONE])));
348
349 if (tb[CTA_COUNTERS_ORIG]) {
350 err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
351 if (err < 0)
352 return err;
353 }
354
355 if (tb[CTA_COUNTERS_REPLY]) {
356 err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
357 if (err < 0)
358 return err;
359 }
360
361 if (tb[CTA_TIMESTAMP]) {
362 err = ct_parse_timestamp(ct, tb[CTA_TIMESTAMP]);
363 if (err < 0)
364 return err;
365 }
366
367 return 0;
368 }
369
nfnlmsg_ct_parse(struct nlmsghdr * nlh,struct nfnl_ct ** result)370 int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
371 {
372 struct nfnl_ct *ct;
373 struct nlattr *tb[CTA_MAX+1];
374 int err;
375
376 ct = nfnl_ct_alloc();
377 if (!ct)
378 return -NLE_NOMEM;
379
380 ct->ce_msgtype = nlh->nlmsg_type;
381
382 err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
383 ct_policy);
384 if (err < 0)
385 goto errout;
386
387 nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
388
389 err = _nfnlmsg_ct_parse(tb, ct);
390 if (err < 0)
391 goto errout;
392
393 *result = ct;
394 return 0;
395 errout:
396 nfnl_ct_put(ct);
397 return err;
398 }
399
nfnlmsg_ct_parse_nested(struct nlattr * attr,struct nfnl_ct ** result)400 int nfnlmsg_ct_parse_nested(struct nlattr *attr, struct nfnl_ct **result)
401 {
402 struct nfnl_ct *ct;
403 struct nlattr *tb[CTA_MAX+1];
404 int err;
405
406 ct = nfnl_ct_alloc();
407 if (!ct)
408 return -NLE_NOMEM;
409
410 // msgtype not given for nested
411 //ct->ce_msgtype = nlh->nlmsg_type;
412
413 err = nla_parse_nested(tb, CTA_MAX, attr, ct_policy);
414 if (err < 0)
415 goto errout;
416
417 // family not known
418 //nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
419
420 err = _nfnlmsg_ct_parse(tb, ct);
421 if (err < 0)
422 goto errout;
423
424 *result = ct;
425 return 0;
426 errout:
427 nfnl_ct_put(ct);
428 return err;
429 }
430
ct_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * nlh,struct nl_parser_param * pp)431 static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
432 struct nlmsghdr *nlh, struct nl_parser_param *pp)
433 {
434 struct nfnl_ct *ct;
435 int err;
436
437 if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
438 return err;
439
440 err = pp->pp_cb((struct nl_object *) ct, pp);
441 nfnl_ct_put(ct);
442 return err;
443 }
444
445 /**
446 * Send nfnl ct dump request
447 * @arg sk Netlink socket.
448 *
449 * @return 0 on success or a negative error code. Due to a bug, this function
450 * returns the number of bytes sent. Treat any non-negative number as success.
451 */
nfnl_ct_dump_request(struct nl_sock * sk)452 int nfnl_ct_dump_request(struct nl_sock *sk)
453 {
454 return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
455 NLM_F_DUMP, AF_UNSPEC, 0);
456 }
457
ct_request_update(struct nl_cache * cache,struct nl_sock * sk)458 static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk)
459 {
460 return nfnl_ct_dump_request(sk);
461 }
462
nfnl_ct_build_tuple(struct nl_msg * msg,const struct nfnl_ct * ct,int repl)463 static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct,
464 int repl)
465 {
466 struct nlattr *tuple, *ip, *proto;
467 struct nl_addr *addr;
468 int family;
469
470 family = nfnl_ct_get_family(ct);
471
472 tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG);
473 if (!tuple)
474 goto nla_put_failure;
475
476 ip = nla_nest_start(msg, CTA_TUPLE_IP);
477 if (!ip)
478 goto nla_put_failure;
479
480 addr = nfnl_ct_get_src(ct, repl);
481 if (addr)
482 NLA_PUT_ADDR(msg,
483 family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
484 addr);
485
486 addr = nfnl_ct_get_dst(ct, repl);
487 if (addr)
488 NLA_PUT_ADDR(msg,
489 family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
490 addr);
491
492 nla_nest_end(msg, ip);
493
494 proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
495 if (!proto)
496 goto nla_put_failure;
497
498 if (nfnl_ct_test_proto(ct))
499 NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct));
500
501 if (nfnl_ct_test_src_port(ct, repl))
502 NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
503 htons(nfnl_ct_get_src_port(ct, repl)));
504
505 if (nfnl_ct_test_dst_port(ct, repl))
506 NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
507 htons(nfnl_ct_get_dst_port(ct, repl)));
508
509 if (family == AF_INET) {
510 if (nfnl_ct_test_icmp_id(ct, repl))
511 NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
512 htons(nfnl_ct_get_icmp_id(ct, repl)));
513
514 if (nfnl_ct_test_icmp_type(ct, repl))
515 NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
516 nfnl_ct_get_icmp_type(ct, repl));
517
518 if (nfnl_ct_test_icmp_code(ct, repl))
519 NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
520 nfnl_ct_get_icmp_code(ct, repl));
521 } else if (family == AF_INET6) {
522 if (nfnl_ct_test_icmp_id(ct, repl))
523 NLA_PUT_U16(msg, CTA_PROTO_ICMPV6_ID,
524 htons(nfnl_ct_get_icmp_id(ct, repl)));
525
526 if (nfnl_ct_test_icmp_type(ct, repl))
527 NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_TYPE,
528 nfnl_ct_get_icmp_type(ct, repl));
529
530 if (nfnl_ct_test_icmp_code(ct, repl))
531 NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_CODE,
532 nfnl_ct_get_icmp_code(ct, repl));
533 }
534
535 nla_nest_end(msg, proto);
536
537 nla_nest_end(msg, tuple);
538 return 0;
539
540 nla_put_failure:
541 return -NLE_MSGSIZE;
542 }
543
nfnl_ct_build_message(const struct nfnl_ct * ct,int cmd,int flags,struct nl_msg ** result)544 static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags,
545 struct nl_msg **result)
546 {
547 struct nl_msg *msg;
548 int err;
549 int reply = 0;
550
551 msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags,
552 nfnl_ct_get_family(ct), 0);
553 if (msg == NULL)
554 return -NLE_NOMEM;
555
556 /* We use REPLY || ORIG, depending on requests. */
557 if (nfnl_ct_get_src(ct, 1) || nfnl_ct_get_dst(ct, 1)) {
558 reply = 1;
559 if ((err = nfnl_ct_build_tuple(msg, ct, 1)) < 0)
560 goto err_out;
561 }
562
563 if (!reply || nfnl_ct_get_src(ct, 0) || nfnl_ct_get_dst(ct, 0)) {
564 if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
565 goto err_out;
566 }
567
568 if (nfnl_ct_test_status(ct))
569 NLA_PUT_U32(msg, CTA_STATUS, htonl(nfnl_ct_get_status(ct)));
570
571 if (nfnl_ct_test_timeout(ct))
572 NLA_PUT_U32(msg, CTA_TIMEOUT, htonl(nfnl_ct_get_timeout(ct)));
573
574 if (nfnl_ct_test_mark(ct))
575 NLA_PUT_U32(msg, CTA_MARK, htonl(nfnl_ct_get_mark(ct)));
576
577 if (nfnl_ct_test_id(ct))
578 NLA_PUT_U32(msg, CTA_ID, htonl(nfnl_ct_get_id(ct)));
579
580 if (nfnl_ct_test_zone(ct))
581 NLA_PUT_U16(msg, CTA_ZONE, htons(nfnl_ct_get_zone(ct)));
582
583 *result = msg;
584 return 0;
585
586 nla_put_failure:
587 err_out:
588 nlmsg_free(msg);
589 return err;
590 }
591
nfnl_ct_build_add_request(const struct nfnl_ct * ct,int flags,struct nl_msg ** result)592 int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags,
593 struct nl_msg **result)
594 {
595 return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result);
596 }
597
nfnl_ct_add(struct nl_sock * sk,const struct nfnl_ct * ct,int flags)598 int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
599 {
600 struct nl_msg *msg;
601 int err;
602
603 if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
604 return err;
605
606 err = nl_send_auto_complete(sk, msg);
607 nlmsg_free(msg);
608 if (err < 0)
609 return err;
610
611 return wait_for_ack(sk);
612 }
613
nfnl_ct_build_delete_request(const struct nfnl_ct * ct,int flags,struct nl_msg ** result)614 int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags,
615 struct nl_msg **result)
616 {
617 return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result);
618 }
619
nfnl_ct_del(struct nl_sock * sk,const struct nfnl_ct * ct,int flags)620 int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
621 {
622 struct nl_msg *msg;
623 int err;
624
625 if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
626 return err;
627
628 err = nl_send_auto_complete(sk, msg);
629 nlmsg_free(msg);
630 if (err < 0)
631 return err;
632
633 return wait_for_ack(sk);
634 }
635
nfnl_ct_build_query_request(const struct nfnl_ct * ct,int flags,struct nl_msg ** result)636 int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags,
637 struct nl_msg **result)
638 {
639 return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result);
640 }
641
nfnl_ct_query(struct nl_sock * sk,const struct nfnl_ct * ct,int flags)642 int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
643 {
644 struct nl_msg *msg;
645 int err;
646
647 if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
648 return err;
649
650 err = nl_send_auto_complete(sk, msg);
651 nlmsg_free(msg);
652 if (err < 0)
653 return err;
654
655 return wait_for_ack(sk);
656 }
657
658 /**
659 * @name Cache Management
660 * @{
661 */
662
663 /**
664 * Build a conntrack cache holding all conntrack currently in the kernel
665 * @arg sk Netlink socket.
666 * @arg result Pointer to store resulting cache.
667 *
668 * Allocates a new cache, initializes it properly and updates it to
669 * contain all conntracks currently in the kernel.
670 *
671 * @return 0 on success or a negative error code.
672 */
nfnl_ct_alloc_cache(struct nl_sock * sk,struct nl_cache ** result)673 int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
674 {
675 return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result);
676 }
677
678 /** @} */
679
680 /**
681 * @name Conntrack Addition
682 * @{
683 */
684
685 /** @} */
686
687 static struct nl_af_group ct_groups[] = {
688 { AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
689 { AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
690 { AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
691 { END_OF_GROUP_LIST },
692 };
693
694 #define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
695 static struct nl_cache_ops nfnl_ct_ops = {
696 .co_name = "netfilter/ct",
697 .co_hdrsize = NFNL_HDRLEN,
698 .co_msgtypes = {
699 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
700 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
701 { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
702 END_OF_MSGTYPES_LIST,
703 },
704 .co_protocol = NETLINK_NETFILTER,
705 .co_groups = ct_groups,
706 .co_request_update = ct_request_update,
707 .co_msg_parser = ct_msg_parser,
708 .co_obj_ops = &ct_obj_ops,
709 };
710
ct_init(void)711 static void _nl_init ct_init(void)
712 {
713 nl_cache_mngt_register(&nfnl_ct_ops);
714 }
715
ct_exit(void)716 static void _nl_exit ct_exit(void)
717 {
718 nl_cache_mngt_unregister(&nfnl_ct_ops);
719 }
720
721 /** @} */
722