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