xref: /aosp_15_r20/external/libnl/lib/netfilter/exp.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  * Copyright (c) 2012 Rich Fought <[email protected]>
8  */
9 
10 /**
11  * @ingroup nfnl
12  * @defgroup exp Expectation
13  * @brief
14  * @{
15  */
16 
17 #include "nl-default.h"
18 
19 #include <sys/types.h>
20 
21 #include <linux/netfilter/nfnetlink_conntrack.h>
22 
23 #include <netlink/attr.h>
24 #include <netlink/netfilter/nfnl.h>
25 #include <netlink/netfilter/exp.h>
26 
27 #include "nl-netfilter.h"
28 #include "nl-priv-dynamic-core/nl-core.h"
29 #include "nl-priv-dynamic-core/cache-api.h"
30 
31 static struct nl_cache_ops nfnl_exp_ops;
32 
33 static struct nla_policy exp_policy[CTA_EXPECT_MAX+1] = {
34 	[CTA_EXPECT_MASTER]	= { .type = NLA_NESTED },
35 	[CTA_EXPECT_TUPLE]	= { .type = NLA_NESTED },
36 	[CTA_EXPECT_MASK]	= { .type = NLA_NESTED },
37 	[CTA_EXPECT_TIMEOUT]	= { .type = NLA_U32 },
38 	[CTA_EXPECT_ID]		= { .type = NLA_U32 },
39 	[CTA_EXPECT_HELP_NAME]	= { .type = NLA_STRING },
40 	[CTA_EXPECT_ZONE]	= { .type = NLA_U16 },
41 	[CTA_EXPECT_FLAGS]	= { .type = NLA_U32 },    // Added in kernel 2.6.37
42 	[CTA_EXPECT_CLASS]	= { .type = NLA_U32 },    // Added in kernel 3.5
43 	[CTA_EXPECT_NAT]	= { .type = NLA_NESTED }, // Added in kernel 3.5
44 	[CTA_EXPECT_FN]		= { .type = NLA_STRING }, // Added in kernel 3.5
45 };
46 
47 static struct nla_policy exp_tuple_policy[CTA_TUPLE_MAX+1] = {
48 	[CTA_TUPLE_IP]		= { .type = NLA_NESTED },
49 	[CTA_TUPLE_PROTO]	= { .type = NLA_NESTED },
50 };
51 
52 static struct nla_policy exp_ip_policy[CTA_IP_MAX+1] = {
53 	[CTA_IP_V4_SRC]		= { .type = NLA_U32 },
54 	[CTA_IP_V4_DST]		= { .type = NLA_U32 },
55 	[CTA_IP_V6_SRC]		= { .minlen = 16 },
56 	[CTA_IP_V6_DST]		= { .minlen = 16 },
57 };
58 
59 static struct nla_policy exp_proto_policy[CTA_PROTO_MAX+1] = {
60 	[CTA_PROTO_NUM]		= { .type = NLA_U8 },
61 	[CTA_PROTO_SRC_PORT]	= { .type = NLA_U16 },
62 	[CTA_PROTO_DST_PORT]	= { .type = NLA_U16 },
63 	[CTA_PROTO_ICMP_ID]	= { .type = NLA_U16 },
64 	[CTA_PROTO_ICMP_TYPE]	= { .type = NLA_U8 },
65 	[CTA_PROTO_ICMP_CODE]	= { .type = NLA_U8 },
66 	[CTA_PROTO_ICMPV6_ID]	= { .type = NLA_U16 },
67 	[CTA_PROTO_ICMPV6_TYPE]	= { .type = NLA_U8 },
68 	[CTA_PROTO_ICMPV6_CODE]	= { .type = NLA_U8 },
69 };
70 
71 static struct nla_policy exp_nat_policy[CTA_EXPECT_NAT_MAX+1] = {
72 	[CTA_EXPECT_NAT_DIR]	= { .type = NLA_U32 },
73 	[CTA_EXPECT_NAT_TUPLE]	= { .type = NLA_NESTED },
74 };
75 
exp_parse_ip(struct nfnl_exp * exp,int tuple,struct nlattr * attr)76 static int exp_parse_ip(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
77 {
78 	struct nlattr *tb[CTA_IP_MAX+1];
79 	struct nl_addr *addr;
80 	int err;
81 
82 	err = nla_parse_nested(tb, CTA_IP_MAX, attr, exp_ip_policy);
83 	if (err < 0)
84 		goto errout;
85 
86 	if (tb[CTA_IP_V4_SRC]) {
87 		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
88 		if (addr == NULL)
89 			goto errout_enomem;
90 		err = nfnl_exp_set_src(exp, tuple, addr);
91 		nl_addr_put(addr);
92 		if (err < 0)
93 			goto errout;
94 	}
95 	if (tb[CTA_IP_V4_DST]) {
96 		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
97 		if (addr == NULL)
98 			goto errout_enomem;
99 		err = nfnl_exp_set_dst(exp, tuple, addr);
100 		nl_addr_put(addr);
101 		if (err < 0)
102 			goto errout;
103 	}
104 	if (tb[CTA_IP_V6_SRC]) {
105 		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
106 		if (addr == NULL)
107 			goto errout_enomem;
108 		err = nfnl_exp_set_src(exp, tuple, addr);
109 		nl_addr_put(addr);
110 		if (err < 0)
111 			goto errout;
112 	}
113 	if (tb[CTA_IP_V6_DST]) {
114 		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
115 		if (addr == NULL)
116 			goto errout_enomem;
117 		err = nfnl_exp_set_dst(exp, tuple, addr);
118 		nl_addr_put(addr);
119 		if (err < 0)
120 			goto errout;
121 	}
122 
123 	return 0;
124 
125 errout_enomem:
126 	err = -NLE_NOMEM;
127 errout:
128 	return err;
129 }
130 
exp_parse_proto(struct nfnl_exp * exp,int tuple,struct nlattr * attr)131 static int exp_parse_proto(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
132 {
133 	struct nlattr *tb[CTA_PROTO_MAX+1];
134 	int err;
135 	uint16_t srcport = 0, dstport = 0, icmpid = 0;
136 	uint8_t icmptype = 0, icmpcode = 0;
137 
138 	err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, exp_proto_policy);
139 	if (err < 0)
140 		return err;
141 
142 	if (tb[CTA_PROTO_NUM])
143 		nfnl_exp_set_l4protonum(exp, tuple, nla_get_u8(tb[CTA_PROTO_NUM]));
144 
145 	if (tb[CTA_PROTO_SRC_PORT])
146 		srcport = ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT]));
147 	if (tb[CTA_PROTO_DST_PORT])
148 		dstport = ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT]));
149 	if (tb[CTA_PROTO_SRC_PORT] || tb[CTA_PROTO_DST_PORT])
150 		nfnl_exp_set_ports(exp, tuple, srcport, dstport);
151 
152 	if (tb[CTA_PROTO_ICMP_ID])
153 		icmpid = ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID]));
154 	if (tb[CTA_PROTO_ICMP_TYPE])
155 		icmptype = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]);
156 	if (tb[CTA_PROTO_ICMP_CODE])
157 		icmpcode = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]);
158 	if (tb[CTA_PROTO_ICMP_ID] || tb[CTA_PROTO_ICMP_TYPE] || tb[CTA_PROTO_ICMP_CODE])
159 		nfnl_exp_set_icmp(exp, tuple, icmpid, icmptype, icmpcode);
160 	return 0;
161 }
162 
exp_parse_tuple(struct nfnl_exp * exp,int tuple,struct nlattr * attr)163 static int exp_parse_tuple(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
164 {
165 	struct nlattr *tb[CTA_TUPLE_MAX+1];
166 	int err;
167 
168 	err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, exp_tuple_policy);
169 	if (err < 0)
170 		return err;
171 
172 	if (tb[CTA_TUPLE_IP]) {
173 		err = exp_parse_ip(exp, tuple, tb[CTA_TUPLE_IP]);
174 		if (err < 0)
175 			return err;
176 	}
177 
178 	if (tb[CTA_TUPLE_PROTO]) {
179 		err = exp_parse_proto(exp, tuple, tb[CTA_TUPLE_PROTO]);
180 		if (err < 0)
181 			return err;
182 	}
183 
184 	return 0;
185 }
186 
exp_parse_nat(struct nfnl_exp * exp,struct nlattr * attr)187 static int exp_parse_nat(struct nfnl_exp *exp, struct nlattr *attr)
188 {
189 	struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
190 	int err;
191 
192 	err = nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_policy);
193 	if (err < 0)
194 		return err;
195 
196 	if (tb[CTA_EXPECT_NAT_DIR])
197 		nfnl_exp_set_nat_dir(exp, nla_get_u32(tb[CTA_EXPECT_NAT_DIR]));
198 
199 	if (tb[CTA_EXPECT_NAT_TUPLE]) {
200 		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_NAT, tb[CTA_EXPECT_NAT_TUPLE]);
201 		if (err < 0)
202 			return err;
203 	}
204 
205 	return 0;
206 }
207 
nfnlmsg_exp_group(struct nlmsghdr * nlh)208 int nfnlmsg_exp_group(struct nlmsghdr *nlh)
209 {
210 	switch (nfnlmsg_subtype(nlh)) {
211 	case IPCTNL_MSG_EXP_NEW:
212 		if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
213 			return NFNLGRP_CONNTRACK_EXP_NEW;
214 		else
215 			return NFNLGRP_CONNTRACK_EXP_UPDATE;
216 	case IPCTNL_MSG_EXP_DELETE:
217 		return NFNLGRP_CONNTRACK_EXP_DESTROY;
218 	default:
219 		return NFNLGRP_NONE;
220 	}
221 }
222 
nfnlmsg_exp_parse(struct nlmsghdr * nlh,struct nfnl_exp ** result)223 int nfnlmsg_exp_parse(struct nlmsghdr *nlh, struct nfnl_exp **result)
224 {
225 	struct nfnl_exp *exp;
226 	struct nlattr *tb[CTA_MAX+1];
227 	int err;
228 
229 	exp = nfnl_exp_alloc();
230 	if (!exp)
231 		return -NLE_NOMEM;
232 
233 	exp->ce_msgtype = nlh->nlmsg_type;
234 
235 	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_EXPECT_MAX,
236 			  exp_policy);
237 	if (err < 0)
238 		goto errout;
239 
240 	nfnl_exp_set_family(exp, nfnlmsg_family(nlh));
241 
242 	if (tb[CTA_EXPECT_TUPLE]) {
243 		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_EXPECT, tb[CTA_EXPECT_TUPLE]);
244 		if (err < 0)
245 			goto errout;
246 	}
247 	if (tb[CTA_EXPECT_MASTER]) {
248 		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASTER, tb[CTA_EXPECT_MASTER]);
249 		if (err < 0)
250 			goto errout;
251 	}
252 	if (tb[CTA_EXPECT_MASK]) {
253 		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASK, tb[CTA_EXPECT_MASK]);
254 		if (err < 0)
255 			goto errout;
256 	}
257 
258 	if (tb[CTA_EXPECT_NAT]) {
259 		err = exp_parse_nat(exp, tb[CTA_EXPECT_MASK]);
260 		if (err < 0)
261 			goto errout;
262 	}
263 
264 	if (tb[CTA_EXPECT_CLASS])
265 		nfnl_exp_set_class(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_CLASS])));
266 
267 	if (tb[CTA_EXPECT_FN])
268 		nfnl_exp_set_fn(exp, nla_data(tb[CTA_EXPECT_FN]));
269 
270 	if (tb[CTA_EXPECT_TIMEOUT])
271 		nfnl_exp_set_timeout(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_TIMEOUT])));
272 
273 	if (tb[CTA_EXPECT_ID])
274 		nfnl_exp_set_id(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_ID])));
275 
276 	if (tb[CTA_EXPECT_HELP_NAME])
277 		nfnl_exp_set_helper_name(exp, nla_data(tb[CTA_EXPECT_HELP_NAME]));
278 
279 	if (tb[CTA_EXPECT_ZONE])
280 		nfnl_exp_set_zone(exp, ntohs(nla_get_u16(tb[CTA_EXPECT_ZONE])));
281 
282 	if (tb[CTA_EXPECT_FLAGS])
283 		nfnl_exp_set_flags(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_FLAGS])));
284 
285 	*result = exp;
286 	return 0;
287 
288 errout:
289 	nfnl_exp_put(exp);
290 	return err;
291 }
292 
exp_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * nlh,struct nl_parser_param * pp)293 static int exp_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
294 			 struct nlmsghdr *nlh, struct nl_parser_param *pp)
295 {
296 	struct nfnl_exp *exp;
297 	int err;
298 
299 	if ((err = nfnlmsg_exp_parse(nlh, &exp)) < 0)
300 		return err;
301 
302 	err = pp->pp_cb((struct nl_object *) exp, pp);
303 	nfnl_exp_put(exp);
304 	return err;
305 }
306 
307 /**
308  * Send nfnl exp dump request
309  * @arg sk    Netlink socket.
310  *
311  * @return 0 on success or a negative error code. Due to a bug, this function
312  * returns the number of bytes sent. Treat any non-negative number as success.
313  */
nfnl_exp_dump_request(struct nl_sock * sk)314 int nfnl_exp_dump_request(struct nl_sock *sk)
315 {
316 	return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET,
317 				NLM_F_DUMP, AF_UNSPEC, 0);
318 }
319 
exp_request_update(struct nl_cache * cache,struct nl_sock * sk)320 static int exp_request_update(struct nl_cache *cache, struct nl_sock *sk)
321 {
322 	return nfnl_exp_dump_request(sk);
323 }
324 
exp_get_tuple_attr(int tuple)325 static int exp_get_tuple_attr(int tuple)
326 {
327 	int attr = 0;
328 
329 	switch (tuple) {
330 		case CTA_EXPECT_MASTER:
331 			attr = NFNL_EXP_TUPLE_MASTER;
332 			break;
333 		case CTA_EXPECT_MASK:
334 			attr = NFNL_EXP_TUPLE_MASK;
335 			break;
336 		case CTA_EXPECT_NAT:
337 			attr = NFNL_EXP_TUPLE_NAT;
338 			break;
339 		case CTA_EXPECT_TUPLE:
340 		default :
341 			attr = NFNL_EXP_TUPLE_EXPECT;
342 			break;
343 	}
344 
345 	return attr;
346 }
347 
nfnl_exp_build_tuple(struct nl_msg * msg,const struct nfnl_exp * exp,int cta)348 static int nfnl_exp_build_tuple(struct nl_msg *msg, const struct nfnl_exp *exp,
349 			       int cta)
350 {
351 	struct nlattr *tuple, *ip, *proto;
352 	struct nl_addr *addr;
353 	int family;
354 	int type;
355 
356 	family = nfnl_exp_get_family(exp);
357 
358 	type = exp_get_tuple_attr(cta);
359 
360 	if (cta == CTA_EXPECT_NAT)
361 		tuple = nla_nest_start(msg, CTA_EXPECT_NAT_TUPLE);
362 	else
363 		tuple = nla_nest_start(msg, cta);
364 
365 	if (!tuple)
366 		goto nla_put_failure;
367 
368 	ip = nla_nest_start(msg, CTA_TUPLE_IP);
369 	if (!ip)
370 		goto nla_put_failure;
371 
372 	addr = nfnl_exp_get_src(exp, type);
373 	if (addr)
374 		NLA_PUT_ADDR(msg,
375 			     family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
376 			     addr);
377 
378 	addr = nfnl_exp_get_dst(exp, type);
379 	if (addr)
380 		NLA_PUT_ADDR(msg,
381 			     family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
382 			     addr);
383 
384 	nla_nest_end(msg, ip);
385 
386 	proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
387 	if (!proto)
388 		goto nla_put_failure;
389 
390 	if (nfnl_exp_test_l4protonum(exp, type))
391 		NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_exp_get_l4protonum(exp, type));
392 
393 	if (nfnl_exp_test_ports(exp, type)) {
394 		NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
395 			htons(nfnl_exp_get_src_port(exp, type)));
396 
397 		NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
398 			htons(nfnl_exp_get_dst_port(exp, type)));
399 	}
400 
401 	if (nfnl_exp_test_icmp(exp, type)) {
402 		NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
403 			htons(nfnl_exp_get_icmp_id(exp, type)));
404 
405 		NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
406 			    nfnl_exp_get_icmp_type(exp, type));
407 
408 		NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
409 			    nfnl_exp_get_icmp_code(exp, type));
410 	}
411 
412 	nla_nest_end(msg, proto);
413 
414 	nla_nest_end(msg, tuple);
415 	return 0;
416 
417 nla_put_failure:
418 	return -NLE_MSGSIZE;
419 }
420 
nfnl_exp_build_nat(struct nl_msg * msg,const struct nfnl_exp * exp)421 static int nfnl_exp_build_nat(struct nl_msg *msg, const struct nfnl_exp *exp)
422 {
423 	struct nlattr *nat;
424 
425 	nat = nla_nest_start(msg, CTA_EXPECT_NAT);
426 
427 	if (nfnl_exp_test_nat_dir(exp)) {
428 		NLA_PUT_U32(msg, CTA_EXPECT_NAT_DIR,
429 				nfnl_exp_get_nat_dir(exp));
430 	}
431 
432 	if (nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_NAT) < 0)
433 		goto nla_put_failure;
434 
435 	nla_nest_end(msg, nat);
436 	return 0;
437 
438 nla_put_failure:
439 	return -NLE_MSGSIZE;
440 }
441 
nfnl_exp_build_message(const struct nfnl_exp * exp,int cmd,int flags,struct nl_msg ** result)442 static int nfnl_exp_build_message(const struct nfnl_exp *exp, int cmd, int flags,
443 				 struct nl_msg **result)
444 {
445 	struct nl_msg *msg;
446 	int err;
447 
448 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK_EXP, cmd, flags,
449 				   nfnl_exp_get_family(exp), 0);
450 	if (msg == NULL)
451 		return -NLE_NOMEM;
452 
453 	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_TUPLE)) < 0)
454 		goto err_out;
455 
456 	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASTER)) < 0)
457 		goto err_out;
458 
459 	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASK)) < 0)
460 		goto err_out;
461 
462 	if (nfnl_exp_test_src(exp, NFNL_EXP_TUPLE_NAT)) {
463 		if ((err = nfnl_exp_build_nat(msg, exp)) < 0)
464 			goto err_out;
465 	}
466 
467 	if (nfnl_exp_test_class(exp))
468 		NLA_PUT_U32(msg, CTA_EXPECT_CLASS, htonl(nfnl_exp_get_class(exp)));
469 
470 	if (nfnl_exp_test_fn(exp))
471 		NLA_PUT_STRING(msg, CTA_EXPECT_FN, nfnl_exp_get_fn(exp));
472 
473 	if (nfnl_exp_test_id(exp))
474 		NLA_PUT_U32(msg, CTA_EXPECT_ID, htonl(nfnl_exp_get_id(exp)));
475 
476 	if (nfnl_exp_test_timeout(exp))
477 		NLA_PUT_U32(msg, CTA_EXPECT_TIMEOUT, htonl(nfnl_exp_get_timeout(exp)));
478 
479 	if (nfnl_exp_test_helper_name(exp))
480 		NLA_PUT_STRING(msg, CTA_EXPECT_HELP_NAME, nfnl_exp_get_helper_name(exp));
481 
482 	if (nfnl_exp_test_zone(exp))
483 		NLA_PUT_U16(msg, CTA_EXPECT_ZONE, htons(nfnl_exp_get_zone(exp)));
484 
485 	if (nfnl_exp_test_flags(exp))
486 		NLA_PUT_U32(msg, CTA_EXPECT_FLAGS, htonl(nfnl_exp_get_flags(exp)));
487 
488 	*result = msg;
489 	return 0;
490 
491 nla_put_failure:
492 	err = -NLE_NOMEM;
493 
494 err_out:
495 	nlmsg_free(msg);
496 	return err;
497 }
498 
nfnl_exp_build_add_request(const struct nfnl_exp * exp,int flags,struct nl_msg ** result)499 int nfnl_exp_build_add_request(const struct nfnl_exp *exp, int flags,
500 			      struct nl_msg **result)
501 {
502 	return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_NEW, flags, result);
503 }
504 
nfnl_exp_add(struct nl_sock * sk,const struct nfnl_exp * exp,int flags)505 int nfnl_exp_add(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
506 {
507 	struct nl_msg *msg;
508 	int err;
509 
510 	if ((err = nfnl_exp_build_add_request(exp, flags, &msg)) < 0)
511 		return err;
512 
513 	err = nl_send_auto_complete(sk, msg);
514 	nlmsg_free(msg);
515 	if (err < 0)
516 		return err;
517 
518 	return wait_for_ack(sk);
519 }
520 
nfnl_exp_build_delete_request(const struct nfnl_exp * exp,int flags,struct nl_msg ** result)521 int nfnl_exp_build_delete_request(const struct nfnl_exp *exp, int flags,
522 				 struct nl_msg **result)
523 {
524 	return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_DELETE, flags, result);
525 }
526 
nfnl_exp_del(struct nl_sock * sk,const struct nfnl_exp * exp,int flags)527 int nfnl_exp_del(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
528 {
529 	struct nl_msg *msg;
530 	int err;
531 
532 	if ((err = nfnl_exp_build_delete_request(exp, flags, &msg)) < 0)
533 		return err;
534 
535 	err = nl_send_auto_complete(sk, msg);
536 	nlmsg_free(msg);
537 	if (err < 0)
538 		return err;
539 
540 	return wait_for_ack(sk);
541 }
542 
nfnl_exp_build_query_request(const struct nfnl_exp * exp,int flags,struct nl_msg ** result)543 int nfnl_exp_build_query_request(const struct nfnl_exp *exp, int flags,
544 				struct nl_msg **result)
545 {
546 	return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_GET, flags, result);
547 }
548 
nfnl_exp_query(struct nl_sock * sk,const struct nfnl_exp * exp,int flags)549 int nfnl_exp_query(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
550 {
551 	struct nl_msg *msg;
552 	int err;
553 
554 	if ((err = nfnl_exp_build_query_request(exp, flags, &msg)) < 0)
555 		return err;
556 
557 	err = nl_send_auto_complete(sk, msg);
558 	nlmsg_free(msg);
559 	if (err < 0)
560 		return err;
561 
562 	return wait_for_ack(sk);
563 }
564 
565 /**
566  * @name Cache Management
567  * @{
568  */
569 
570 /**
571  * Build a expectation cache holding all expectations currently in the kernel
572  * @arg sk		Netlink socket.
573  * @arg result		Pointer to store resulting cache.
574  *
575  * Allocates a new cache, initializes it properly and updates it to
576  * contain all expectations currently in the kernel.
577  *
578  * @return 0 on success or a negative error code.
579  */
nfnl_exp_alloc_cache(struct nl_sock * sk,struct nl_cache ** result)580 int nfnl_exp_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
581 {
582 	return nl_cache_alloc_and_fill(&nfnl_exp_ops, sk, result);
583 }
584 
585 /** @} */
586 
587 /**
588  * @name Expectation Addition
589  * @{
590  */
591 
592 /** @} */
593 
594 static struct nl_af_group exp_groups[] = {
595 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_NEW },
596 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_UPDATE },
597 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_DESTROY },
598 	{ END_OF_GROUP_LIST },
599 };
600 
601 #define NFNLMSG_EXP_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK_EXP, (type))
602 static struct nl_cache_ops nfnl_exp_ops = {
603 	.co_name		    = "netfilter/exp",
604 	.co_hdrsize		    = NFNL_HDRLEN,
605 	.co_msgtypes		= {
606 		{ NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_NEW), NL_ACT_NEW, "new" },
607 		{ NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_GET), NL_ACT_GET, "get" },
608 		{ NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_DELETE), NL_ACT_DEL, "del" },
609 		END_OF_MSGTYPES_LIST,
610 	},
611 	.co_protocol		= NETLINK_NETFILTER,
612 	.co_groups		= exp_groups,
613 	.co_request_update	= exp_request_update,
614 	.co_msg_parser		= exp_msg_parser,
615 	.co_obj_ops		= &exp_obj_ops,
616 };
617 
exp_init(void)618 static void _nl_init exp_init(void)
619 {
620 	nl_cache_mngt_register(&nfnl_exp_ops);
621 }
622 
exp_exit(void)623 static void _nl_exit exp_exit(void)
624 {
625 	nl_cache_mngt_unregister(&nfnl_exp_ops);
626 }
627 
628 /** @} */
629