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