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