• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/netfilter/ct.c	Conntrack
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
11  * Copyright (c) 2007 Secure Computing Corporation
12  * Copyright (c= 2008 Patrick McHardy <kaber@trash.net>
13  */
14 
15 /**
16  * @ingroup nfnl
17  * @defgroup ct Conntrack
18  * @brief
19  * @{
20  */
21 
22 #include <byteswap.h>
23 #include <sys/types.h>
24 #include <linux/netfilter/nfnetlink_conntrack.h>
25 
26 #include <netlink-private/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/netfilter/nfnl.h>
29 #include <netlink/netfilter/ct.h>
30 
31 static struct nl_cache_ops nfnl_ct_ops;
32 
33 #if __BYTE_ORDER == __BIG_ENDIAN
ntohll(uint64_t x)34 static uint64_t ntohll(uint64_t x)
35 {
36 	return x;
37 }
htonll(uint64_t x)38 static uint64_t htonll(uint64_t x)
39 {
40 	return x;
41 }
42 #elif __BYTE_ORDER == __LITTLE_ENDIAN
ntohll(uint64_t x)43 static uint64_t ntohll(uint64_t x)
44 {
45 	return bswap_64(x);
46 }
htonll(uint64_t x)47 static uint64_t htonll(uint64_t x)
48 {
49 	return bswap_64(x);
50 }
51 #endif
52 
53 static struct nla_policy ct_policy[CTA_MAX+1] = {
54 	[CTA_TUPLE_ORIG]	= { .type = NLA_NESTED },
55 	[CTA_TUPLE_REPLY]	= { .type = NLA_NESTED },
56 	[CTA_STATUS]		= { .type = NLA_U32 },
57 	[CTA_PROTOINFO]		= { .type = NLA_NESTED },
58 	//[CTA_HELP]
59 	//[CTA_NAT_SRC]
60 	[CTA_TIMEOUT]		= { .type = NLA_U32 },
61 	[CTA_MARK]		= { .type = NLA_U32 },
62 	[CTA_COUNTERS_ORIG]	= { .type = NLA_NESTED },
63 	[CTA_COUNTERS_REPLY]	= { .type = NLA_NESTED },
64 	[CTA_USE]		= { .type = NLA_U32 },
65 	[CTA_ID]		= { .type = NLA_U32 },
66 	[CTA_ZONE]		= { .type = NLA_U16 },
67 	//[CTA_NAT_DST]
68 };
69 
70 static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
71 	[CTA_TUPLE_IP]		= { .type = NLA_NESTED },
72 	[CTA_TUPLE_PROTO]	= { .type = NLA_NESTED },
73 };
74 
75 static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
76 	[CTA_IP_V4_SRC]		= { .type = NLA_U32 },
77 	[CTA_IP_V4_DST]		= { .type = NLA_U32 },
78 	[CTA_IP_V6_SRC]		= { .minlen = 16 },
79 	[CTA_IP_V6_DST]		= { .minlen = 16 },
80 };
81 
82 static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
83 	[CTA_PROTO_NUM]		= { .type = NLA_U8 },
84 	[CTA_PROTO_SRC_PORT]	= { .type = NLA_U16 },
85 	[CTA_PROTO_DST_PORT]	= { .type = NLA_U16 },
86 	[CTA_PROTO_ICMP_ID]	= { .type = NLA_U16 },
87 	[CTA_PROTO_ICMP_TYPE]	= { .type = NLA_U8 },
88 	[CTA_PROTO_ICMP_CODE]	= { .type = NLA_U8 },
89 	[CTA_PROTO_ICMPV6_ID]	= { .type = NLA_U16 },
90 	[CTA_PROTO_ICMPV6_TYPE]	= { .type = NLA_U8 },
91 	[CTA_PROTO_ICMPV6_CODE]	= { .type = NLA_U8 },
92 };
93 
94 static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
95 	[CTA_PROTOINFO_TCP]	= { .type = NLA_NESTED },
96 };
97 
98 static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
99 	[CTA_PROTOINFO_TCP_STATE]		= { .type = NLA_U8 },
100 	[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]	= { .type = NLA_U8 },
101 	[CTA_PROTOINFO_TCP_WSCALE_REPLY]	= { .type = NLA_U8 },
102 	[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]	= { .minlen = 2 },
103 	[CTA_PROTOINFO_TCP_FLAGS_REPLY]		= { .minlen = 2 },
104 
105 };
106 
107 static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
108 	[CTA_COUNTERS_PACKETS]	= { .type = NLA_U64 },
109 	[CTA_COUNTERS_BYTES]	= { .type = NLA_U64 },
110 	[CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
111 	[CTA_COUNTERS32_BYTES]	= { .type = NLA_U32 },
112 };
113 
114 static struct nla_policy ct_timestamp_policy[CTA_TIMESTAMP_MAX + 1] = {
115 	[CTA_TIMESTAMP_START]	= { .type = NLA_U64 },
116 	[CTA_TIMESTAMP_STOP]	= { .type = NLA_U64 },
117 };
118 
ct_parse_ip(struct nfnl_ct * ct,int repl,struct nlattr * attr)119 static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
120 {
121 	struct nlattr *tb[CTA_IP_MAX+1];
122 	struct nl_addr *addr;
123 	int err;
124 
125         err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
126 	if (err < 0)
127 		goto errout;
128 
129 	if (tb[CTA_IP_V4_SRC]) {
130 		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
131 		if (addr == NULL)
132 			goto errout_enomem;
133 		err = nfnl_ct_set_src(ct, repl, addr);
134 		nl_addr_put(addr);
135 		if (err < 0)
136 			goto errout;
137 	}
138 	if (tb[CTA_IP_V4_DST]) {
139 		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
140 		if (addr == NULL)
141 			goto errout_enomem;
142 		err = nfnl_ct_set_dst(ct, repl, addr);
143 		nl_addr_put(addr);
144 		if (err < 0)
145 			goto errout;
146 	}
147 	if (tb[CTA_IP_V6_SRC]) {
148 		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
149 		if (addr == NULL)
150 			goto errout_enomem;
151 		err = nfnl_ct_set_src(ct, repl, addr);
152 		nl_addr_put(addr);
153 		if (err < 0)
154 			goto errout;
155 	}
156 	if (tb[CTA_IP_V6_DST]) {
157 		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
158 		if (addr == NULL)
159 			goto errout_enomem;
160 		err = nfnl_ct_set_dst(ct, repl, addr);
161 		nl_addr_put(addr);
162 		if (err < 0)
163 			goto errout;
164 	}
165 
166 	return 0;
167 
168 errout_enomem:
169 	err = -NLE_NOMEM;
170 errout:
171 	return err;
172 }
173 
ct_parse_proto(struct nfnl_ct * ct,int repl,struct nlattr * attr)174 static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
175 {
176 	struct nlattr *tb[CTA_PROTO_MAX+1];
177 	int err;
178 
179 	err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
180 	if (err < 0)
181 		return err;
182 
183 	if (!repl && tb[CTA_PROTO_NUM])
184 		nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
185 	if (tb[CTA_PROTO_SRC_PORT])
186 		nfnl_ct_set_src_port(ct, repl,
187 			ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT])));
188 	if (tb[CTA_PROTO_DST_PORT])
189 		nfnl_ct_set_dst_port(ct, repl,
190 			ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
191 
192 	if (ct->ct_family == AF_INET) {
193 		if (tb[CTA_PROTO_ICMP_ID])
194 			nfnl_ct_set_icmp_id(ct, repl,
195 				ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
196 		if (tb[CTA_PROTO_ICMP_TYPE])
197 			nfnl_ct_set_icmp_type(ct, repl,
198 				nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
199 		if (tb[CTA_PROTO_ICMP_CODE])
200 			nfnl_ct_set_icmp_code(ct, repl,
201 				nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
202 	} else if (ct->ct_family == AF_INET6) {
203 		if (tb[CTA_PROTO_ICMPV6_ID])
204 			nfnl_ct_set_icmp_id(ct, repl,
205 			    ntohs(nla_get_u16(tb[CTA_PROTO_ICMPV6_ID])));
206 		if (tb[CTA_PROTO_ICMPV6_TYPE])
207 			nfnl_ct_set_icmp_type(ct, repl,
208 				nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]));
209 		if (tb[CTA_PROTO_ICMPV6_CODE])
210 			nfnl_ct_set_icmp_code(ct, repl,
211 				nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]));
212 	}
213 
214 	return 0;
215 }
216 
ct_parse_tuple(struct nfnl_ct * ct,int repl,struct nlattr * attr)217 static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
218 {
219 	struct nlattr *tb[CTA_TUPLE_MAX+1];
220 	int err;
221 
222 	err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
223 	if (err < 0)
224 		return err;
225 
226 	if (tb[CTA_TUPLE_IP]) {
227 		err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
228 		if (err < 0)
229 			return err;
230 	}
231 
232 	if (tb[CTA_TUPLE_PROTO]) {
233 		err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
234 		if (err < 0)
235 			return err;
236 	}
237 
238 	return 0;
239 }
240 
ct_parse_protoinfo_tcp(struct nfnl_ct * ct,struct nlattr * attr)241 static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
242 {
243 	struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
244 	int err;
245 
246 	err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
247 			       ct_protoinfo_tcp_policy);
248 	if (err < 0)
249 		return err;
250 
251 	if (tb[CTA_PROTOINFO_TCP_STATE])
252 		nfnl_ct_set_tcp_state(ct,
253 				nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
254 
255 	return 0;
256 }
257 
ct_parse_protoinfo(struct nfnl_ct * ct,struct nlattr * attr)258 static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
259 {
260 	struct nlattr *tb[CTA_PROTOINFO_MAX+1];
261 	int err;
262 
263 	err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
264 			       ct_protoinfo_policy);
265 	if (err < 0)
266 		return err;
267 
268 	if (tb[CTA_PROTOINFO_TCP]) {
269 		err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
270 		if (err < 0)
271 			return err;
272 	}
273 
274 	return 0;
275 }
276 
ct_parse_counters(struct nfnl_ct * ct,int repl,struct nlattr * attr)277 static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
278 {
279 	struct nlattr *tb[CTA_COUNTERS_MAX+1];
280 	int err;
281 
282 	err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
283 	if (err < 0)
284 		return err;
285 
286 	if (tb[CTA_COUNTERS_PACKETS])
287 		nfnl_ct_set_packets(ct, repl,
288 			ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
289 	if (tb[CTA_COUNTERS32_PACKETS])
290 		nfnl_ct_set_packets(ct, repl,
291 			ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
292 	if (tb[CTA_COUNTERS_BYTES])
293 		nfnl_ct_set_bytes(ct, repl,
294 			ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
295 	if (tb[CTA_COUNTERS32_BYTES])
296 		nfnl_ct_set_bytes(ct, repl,
297 			ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
298 
299 	return 0;
300 }
301 
nfnlmsg_ct_group(struct nlmsghdr * nlh)302 int nfnlmsg_ct_group(struct nlmsghdr *nlh)
303 {
304 	switch (nfnlmsg_subtype(nlh)) {
305 	case IPCTNL_MSG_CT_NEW:
306 		if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
307 			return NFNLGRP_CONNTRACK_NEW;
308 		else
309 			return NFNLGRP_CONNTRACK_UPDATE;
310 	case IPCTNL_MSG_CT_DELETE:
311 		return NFNLGRP_CONNTRACK_DESTROY;
312 	default:
313 		return NFNLGRP_NONE;
314 	}
315 }
316 
ct_parse_timestamp(struct nfnl_ct * ct,struct nlattr * attr)317 static int ct_parse_timestamp(struct nfnl_ct *ct, struct nlattr *attr)
318 {
319 	struct nlattr *tb[CTA_TIMESTAMP_MAX + 1];
320 	int err;
321 
322 	err = nla_parse_nested(tb, CTA_TIMESTAMP_MAX, attr,
323 			       ct_timestamp_policy);
324 	if (err < 0)
325 		return err;
326 
327 	if (tb[CTA_TIMESTAMP_START] && tb[CTA_TIMESTAMP_STOP])
328 		nfnl_ct_set_timestamp(ct,
329 			      ntohll(nla_get_u64(tb[CTA_TIMESTAMP_START])),
330 			      ntohll(nla_get_u64(tb[CTA_TIMESTAMP_STOP])));
331 
332 	return 0;
333 }
334 
nfnlmsg_ct_parse(struct nlmsghdr * nlh,struct nfnl_ct ** result)335 int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
336 {
337 	struct nfnl_ct *ct;
338 	struct nlattr *tb[CTA_MAX+1];
339 	int err;
340 
341 	ct = nfnl_ct_alloc();
342 	if (!ct)
343 		return -NLE_NOMEM;
344 
345 	ct->ce_msgtype = nlh->nlmsg_type;
346 
347 	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
348 			  ct_policy);
349 	if (err < 0)
350 		goto errout;
351 
352 	nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
353 
354 	if (tb[CTA_TUPLE_ORIG]) {
355 		err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
356 		if (err < 0)
357 			goto errout;
358 	}
359 	if (tb[CTA_TUPLE_REPLY]) {
360 		err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
361 		if (err < 0)
362 			goto errout;
363 	}
364 
365 	if (tb[CTA_PROTOINFO]) {
366 		err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
367 		if (err < 0)
368 			goto errout;
369 	}
370 
371 	if (tb[CTA_STATUS])
372 		nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
373 	if (tb[CTA_TIMEOUT])
374 		nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
375 	if (tb[CTA_MARK])
376 		nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
377 	if (tb[CTA_USE])
378 		nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
379 	if (tb[CTA_ID])
380 		nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
381 	if (tb[CTA_ZONE])
382 		nfnl_ct_set_zone(ct, ntohs(nla_get_u16(tb[CTA_ZONE])));
383 
384 	if (tb[CTA_COUNTERS_ORIG]) {
385 		err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
386 		if (err < 0)
387 			goto errout;
388 	}
389 
390 	if (tb[CTA_COUNTERS_REPLY]) {
391 		err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
392 		if (err < 0)
393 			goto errout;
394 	}
395 
396 	if (tb[CTA_TIMESTAMP]) {
397 		err = ct_parse_timestamp(ct, tb[CTA_TIMESTAMP]);
398 		if (err < 0)
399 			goto errout;
400 	}
401 
402 	*result = ct;
403 	return 0;
404 
405 errout:
406 	nfnl_ct_put(ct);
407 	return err;
408 }
409 
ct_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * nlh,struct nl_parser_param * pp)410 static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
411 			 struct nlmsghdr *nlh, struct nl_parser_param *pp)
412 {
413 	struct nfnl_ct *ct;
414 	int err;
415 
416 	if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
417 		return err;
418 
419 	err = pp->pp_cb((struct nl_object *) ct, pp);
420 	nfnl_ct_put(ct);
421 	return err;
422 }
423 
nfnl_ct_dump_request(struct nl_sock * sk)424 int nfnl_ct_dump_request(struct nl_sock *sk)
425 {
426 	return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
427 				NLM_F_DUMP, AF_UNSPEC, 0);
428 }
429 
ct_request_update(struct nl_cache * cache,struct nl_sock * sk)430 static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk)
431 {
432 	return nfnl_ct_dump_request(sk);
433 }
434 
nfnl_ct_build_tuple(struct nl_msg * msg,const struct nfnl_ct * ct,int repl)435 static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct,
436 			       int repl)
437 {
438 	struct nlattr *tuple, *ip, *proto;
439 	struct nl_addr *addr;
440 	int family;
441 
442 	family = nfnl_ct_get_family(ct);
443 
444 	tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG);
445 	if (!tuple)
446 		goto nla_put_failure;
447 
448 	ip = nla_nest_start(msg, CTA_TUPLE_IP);
449 	if (!ip)
450 		goto nla_put_failure;
451 
452 	addr = nfnl_ct_get_src(ct, repl);
453 	if (addr)
454 		NLA_PUT_ADDR(msg,
455 			     family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
456 			     addr);
457 
458 	addr = nfnl_ct_get_dst(ct, repl);
459 	if (addr)
460 		NLA_PUT_ADDR(msg,
461 			     family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
462 			     addr);
463 
464 	nla_nest_end(msg, ip);
465 
466 	proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
467 	if (!proto)
468 		goto nla_put_failure;
469 
470 	if (nfnl_ct_test_proto(ct))
471 		NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct));
472 
473 	if (nfnl_ct_test_src_port(ct, repl))
474 		NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
475 			htons(nfnl_ct_get_src_port(ct, repl)));
476 
477 	if (nfnl_ct_test_dst_port(ct, repl))
478 		NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
479 			htons(nfnl_ct_get_dst_port(ct, repl)));
480 
481 	if (family == AF_INET) {
482 		if (nfnl_ct_test_icmp_id(ct, repl))
483 			NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
484 						htons(nfnl_ct_get_icmp_id(ct, repl)));
485 
486 		if (nfnl_ct_test_icmp_type(ct, repl))
487 			NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
488 					   nfnl_ct_get_icmp_type(ct, repl));
489 
490 		if (nfnl_ct_test_icmp_code(ct, repl))
491 			NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
492 					   nfnl_ct_get_icmp_code(ct, repl));
493 	} else if (family == AF_INET6) {
494 		if (nfnl_ct_test_icmp_id(ct, repl))
495 			NLA_PUT_U16(msg, CTA_PROTO_ICMPV6_ID,
496 						htons(nfnl_ct_get_icmp_id(ct, repl)));
497 
498 		if (nfnl_ct_test_icmp_type(ct, repl))
499 			NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_TYPE,
500 					   nfnl_ct_get_icmp_type(ct, repl));
501 
502 		if (nfnl_ct_test_icmp_code(ct, repl))
503 			NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_CODE,
504 					   nfnl_ct_get_icmp_code(ct, repl));
505 	}
506 
507 	nla_nest_end(msg, proto);
508 
509 	nla_nest_end(msg, tuple);
510 	return 0;
511 
512 nla_put_failure:
513 	return -NLE_MSGSIZE;
514 }
515 
nfnl_ct_build_message(const struct nfnl_ct * ct,int cmd,int flags,struct nl_msg ** result)516 static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags,
517 				 struct nl_msg **result)
518 {
519 	struct nl_msg *msg;
520 	int err;
521 
522 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags,
523 				   nfnl_ct_get_family(ct), 0);
524 	if (msg == NULL)
525 		return -NLE_NOMEM;
526 
527 	if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
528 		goto err_out;
529 
530 	/* REPLY tuple is optional, dont add unless at least src/dst specified */
531 
532 	if ( nfnl_ct_get_src(ct, 1) && nfnl_ct_get_dst(ct, 1) )
533 		if ((err = nfnl_ct_build_tuple(msg, ct, 1)) < 0)
534 			goto err_out;
535 
536 	if (nfnl_ct_test_status(ct))
537 		NLA_PUT_U32(msg, CTA_STATUS, htonl(nfnl_ct_get_status(ct)));
538 
539 	if (nfnl_ct_test_timeout(ct))
540 		NLA_PUT_U32(msg, CTA_TIMEOUT, htonl(nfnl_ct_get_timeout(ct)));
541 
542 	if (nfnl_ct_test_mark(ct))
543 		NLA_PUT_U32(msg, CTA_MARK, htonl(nfnl_ct_get_mark(ct)));
544 
545 	if (nfnl_ct_test_id(ct))
546 		NLA_PUT_U32(msg, CTA_ID, htonl(nfnl_ct_get_id(ct)));
547 
548 	if (nfnl_ct_test_zone(ct))
549 		NLA_PUT_U16(msg, CTA_ZONE, htons(nfnl_ct_get_zone(ct)));
550 
551 	*result = msg;
552 	return 0;
553 
554 nla_put_failure:
555 err_out:
556 	nlmsg_free(msg);
557 	return err;
558 }
559 
nfnl_ct_build_add_request(const struct nfnl_ct * ct,int flags,struct nl_msg ** result)560 int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags,
561 			      struct nl_msg **result)
562 {
563 	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result);
564 }
565 
nfnl_ct_add(struct nl_sock * sk,const struct nfnl_ct * ct,int flags)566 int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
567 {
568 	struct nl_msg *msg;
569 	int err;
570 
571 	if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
572 		return err;
573 
574 	err = nl_send_auto_complete(sk, msg);
575 	nlmsg_free(msg);
576 	if (err < 0)
577 		return err;
578 
579 	return wait_for_ack(sk);
580 }
581 
nfnl_ct_build_delete_request(const struct nfnl_ct * ct,int flags,struct nl_msg ** result)582 int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags,
583 				 struct nl_msg **result)
584 {
585 	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result);
586 }
587 
nfnl_ct_del(struct nl_sock * sk,const struct nfnl_ct * ct,int flags)588 int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
589 {
590 	struct nl_msg *msg;
591 	int err;
592 
593 	if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
594 		return err;
595 
596 	err = nl_send_auto_complete(sk, msg);
597 	nlmsg_free(msg);
598 	if (err < 0)
599 		return err;
600 
601 	return wait_for_ack(sk);
602 }
603 
nfnl_ct_build_query_request(const struct nfnl_ct * ct,int flags,struct nl_msg ** result)604 int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags,
605 				struct nl_msg **result)
606 {
607 	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result);
608 }
609 
nfnl_ct_query(struct nl_sock * sk,const struct nfnl_ct * ct,int flags)610 int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
611 {
612 	struct nl_msg *msg;
613 	int err;
614 
615 	if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
616 		return err;
617 
618 	err = nl_send_auto_complete(sk, msg);
619 	nlmsg_free(msg);
620 	if (err < 0)
621 		return err;
622 
623 	return wait_for_ack(sk);
624 }
625 
626 /**
627  * @name Cache Management
628  * @{
629  */
630 
631 /**
632  * Build a conntrack cache holding all conntrack currently in the kernel
633  * @arg sk		Netlink socket.
634  * @arg result		Pointer to store resulting cache.
635  *
636  * Allocates a new cache, initializes it properly and updates it to
637  * contain all conntracks currently in the kernel.
638  *
639  * @return 0 on success or a negative error code.
640  */
nfnl_ct_alloc_cache(struct nl_sock * sk,struct nl_cache ** result)641 int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
642 {
643 	return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result);
644 }
645 
646 /** @} */
647 
648 /**
649  * @name Conntrack Addition
650  * @{
651  */
652 
653 /** @} */
654 
655 static struct nl_af_group ct_groups[] = {
656 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
657 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
658 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
659 	{ END_OF_GROUP_LIST },
660 };
661 
662 #define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
663 static struct nl_cache_ops nfnl_ct_ops = {
664 	.co_name		= "netfilter/ct",
665 	.co_hdrsize		= NFNL_HDRLEN,
666 	.co_msgtypes		= {
667 		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
668 		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
669 		{ NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
670 		END_OF_MSGTYPES_LIST,
671 	},
672 	.co_protocol		= NETLINK_NETFILTER,
673 	.co_groups		= ct_groups,
674 	.co_request_update	= ct_request_update,
675 	.co_msg_parser		= ct_msg_parser,
676 	.co_obj_ops		= &ct_obj_ops,
677 };
678 
ct_init(void)679 static void __init ct_init(void)
680 {
681 	nl_cache_mngt_register(&nfnl_ct_ops);
682 }
683 
ct_exit(void)684 static void __exit ct_exit(void)
685 {
686 	nl_cache_mngt_unregister(&nfnl_ct_ops);
687 }
688 
689 /** @} */
690