xref: /aosp_15_r20/external/libnl/lib/netfilter/ct.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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