• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
10  */
11 
12 #define _GNU_SOURCE
13 #include "config.h"
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <time.h>
17 #include <string.h>
18 #include <netinet/ether.h>
19 #include <netinet/in.h>
20 #include <netinet/ip6.h>
21 #include <net/if_arp.h>
22 #include <getopt.h>
23 
24 #include <sys/socket.h>
25 #include <arpa/inet.h>
26 
27 #include <linux/netfilter/nfnetlink.h>
28 #include <linux/netfilter/nf_tables.h>
29 
30 #include <libmnl/libmnl.h>
31 #include <libnftnl/table.h>
32 #include <libnftnl/trace.h>
33 #include <libnftnl/chain.h>
34 #include <libnftnl/rule.h>
35 
36 #include <include/xtables.h>
37 #include "iptables.h" /* for xtables_globals */
38 #include "xtables-multi.h"
39 #include "nft.h"
40 
41 struct cb_arg {
42 	uint32_t nfproto;
43 	bool is_event;
44 	struct nft_handle *h;
45 };
46 
table_cb(const struct nlmsghdr * nlh,void * data)47 static int table_cb(const struct nlmsghdr *nlh, void *data)
48 {
49 	uint32_t type = nlh->nlmsg_type & 0xFF;
50 	const struct cb_arg *arg = data;
51 	struct nftnl_table *t;
52 	char buf[4096];
53 
54 	t = nftnl_table_alloc();
55 	if (t == NULL)
56 		goto err;
57 
58 	if (nftnl_table_nlmsg_parse(nlh, t) < 0)
59 		goto err_free;
60 
61 	if (arg->nfproto && arg->nfproto != nftnl_table_get_u32(t, NFTNL_TABLE_FAMILY))
62 		goto err_free;
63 	nftnl_table_snprintf(buf, sizeof(buf), t, NFTNL_OUTPUT_DEFAULT, 0);
64 	printf(" EVENT: ");
65 	printf("nft: %s table: %s\n", type == NFT_MSG_NEWTABLE ? "NEW" : "DEL", buf);
66 
67 err_free:
68 	nftnl_table_free(t);
69 err:
70 	return MNL_CB_OK;
71 }
72 
family_cmd(int family)73 static const char *family_cmd(int family)
74 {
75 	switch (family) {
76 	case NFPROTO_IPV4:
77 		return "iptables";
78 	case NFPROTO_IPV6:
79 		return "ip6tables";
80 	case NFPROTO_ARP:
81 		return "arptables";
82 	case NFPROTO_BRIDGE:
83 		return "ebtables";
84 	default:
85 		return NULL;
86 	}
87 }
88 
89 static bool counters;
90 static bool trace;
91 static bool events;
92 
rule_cb(const struct nlmsghdr * nlh,void * data)93 static int rule_cb(const struct nlmsghdr *nlh, void *data)
94 {
95 	uint32_t type = nlh->nlmsg_type & 0xFF;
96 	const struct cb_arg *arg = data;
97 	struct nftnl_rule *r;
98 	uint8_t family;
99 
100 	r = nftnl_rule_alloc();
101 	if (r == NULL)
102 		goto err;
103 
104 	if (nftnl_rule_nlmsg_parse(nlh, r) < 0)
105 		goto err_free;
106 
107 	family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
108 	if (arg->nfproto && arg->nfproto != family)
109 		goto err_free;
110 
111 	xtables_set_nfproto(family);
112 	arg->h->ops = nft_family_ops_lookup(family);
113 	arg->h->family = family;
114 
115 	/* ignore policy rules unless tracing,
116 	 * they are reported when deleting user-defined chains */
117 	if (family == NFPROTO_BRIDGE &&
118 	    arg->is_event &&
119 	    nft_rule_is_policy_rule(r))
120 		goto err_free;
121 
122 	if (!family_cmd(family))
123 		goto err_free;
124 
125 	printf("%s%s -t %s ",
126 	       arg->is_event ? " EVENT: " : "",
127 	       family_cmd(family),
128 	       nftnl_rule_get_str(r, NFTNL_RULE_TABLE));
129 	nft_rule_print_save(arg->h, r,
130 			    type == NFT_MSG_NEWRULE ? NFT_RULE_APPEND
131 						    : NFT_RULE_DEL,
132 			    counters ? 0 : FMT_NOCOUNTS);
133 err_free:
134 	nftnl_rule_free(r);
135 err:
136 	return MNL_CB_OK;
137 }
138 
chain_cb(const struct nlmsghdr * nlh,void * data)139 static int chain_cb(const struct nlmsghdr *nlh, void *data)
140 {
141 	uint32_t type = nlh->nlmsg_type & 0xFF;
142 	const struct cb_arg *arg = data;
143 	struct nftnl_chain *c;
144 	char buf[4096];
145 	int family;
146 
147 	c = nftnl_chain_alloc();
148 	if (c == NULL)
149 		goto err;
150 
151 	if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
152 		goto err_free;
153 
154 	family = nftnl_chain_get_u32(c, NFTNL_CHAIN_FAMILY);
155 	if (arg->nfproto && arg->nfproto != family)
156 		goto err_free;
157 
158 	printf(" EVENT: ");
159 
160 	if (nftnl_chain_is_set(c, NFTNL_CHAIN_PRIO) || !family_cmd(family)) {
161 		nftnl_chain_snprintf(buf, sizeof(buf),
162 				     c, NFTNL_OUTPUT_DEFAULT, 0);
163 		printf("nft: %s chain: %s\n",
164 		       type == NFT_MSG_NEWCHAIN ? "NEW" : "DEL", buf);
165 		goto err_free;
166 	}
167 
168 	printf("%s -t %s -%c %s\n",
169 			family_cmd(family),
170 			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE),
171 			type == NFT_MSG_NEWCHAIN ? 'N' : 'X',
172 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
173 err_free:
174 	nftnl_chain_free(c);
175 err:
176 	return MNL_CB_OK;
177 }
178 
newgen_cb(const struct nlmsghdr * nlh,void * data)179 static int newgen_cb(const struct nlmsghdr *nlh, void *data)
180 {
181 	uint32_t genid = 0, pid = 0;
182 	const struct nlattr *attr;
183 	const char *name = NULL;
184 
185 	mnl_attr_for_each(attr, nlh, sizeof(struct nfgenmsg)) {
186 		switch (mnl_attr_get_type(attr)) {
187 		case NFTA_GEN_ID:
188 			if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
189 				break;
190 		        genid = ntohl(mnl_attr_get_u32(attr));
191 			break;
192 		case NFTA_GEN_PROC_NAME:
193 			if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
194 				break;
195 			name = mnl_attr_get_str(attr);
196 			break;
197 		case NFTA_GEN_PROC_PID:
198 			if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
199 				break;
200 			pid = ntohl(mnl_attr_get_u32(attr));
201 			break;
202 		}
203 	}
204 
205 	if (name)
206 		printf("NEWGEN: GENID=%u PID=%u NAME=%s\n", genid, pid, name);
207 
208 	return MNL_CB_OK;
209 }
210 
trace_print_return(const struct nftnl_trace * nlt)211 static void trace_print_return(const struct nftnl_trace *nlt)
212 {
213 	const char *chain = NULL;
214 
215 	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) {
216 		chain = nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET);
217 		printf("%s", chain);
218 	}
219 }
220 
trace_print_rule(const struct nftnl_trace * nlt,struct cb_arg * args)221 static void trace_print_rule(const struct nftnl_trace *nlt, struct cb_arg *args)
222 {
223 	uint64_t handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE);
224 	uint32_t family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
225 	const char *table = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE);
226 	const char *chain = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN);
227         struct nftnl_rule *r;
228 	struct mnl_socket *nl;
229 	struct nlmsghdr *nlh;
230 	uint32_t portid;
231 	char buf[16536];
232 	int ret;
233 
234         r = nftnl_rule_alloc();
235 	if (r == NULL) {
236 		perror("OOM");
237 		exit(EXIT_FAILURE);
238 	}
239 
240 	nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, 0, 0);
241 
242         nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
243 	nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
244 	nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
245 	nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, handle);
246 	nftnl_rule_nlmsg_build_payload(nlh, r);
247 	nftnl_rule_free(r);
248 
249 	nl = mnl_socket_open(NETLINK_NETFILTER);
250 	if (nl == NULL) {
251 		perror("mnl_socket_open");
252 		exit(EXIT_FAILURE);
253 	}
254 
255 	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
256 		perror("mnl_socket_bind");
257 		exit(EXIT_FAILURE);
258 	}
259 
260 	portid = mnl_socket_get_portid(nl);
261 	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
262 		perror("mnl_socket_send");
263 		exit(EXIT_FAILURE);
264 	}
265 
266 	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
267 	if (ret > 0) {
268 		args->is_event = false;
269 		ret = mnl_cb_run(buf, ret, 0, portid, rule_cb, args);
270 	}
271 	if (ret == -1) {
272 		perror("error");
273 		exit(EXIT_FAILURE);
274 	}
275 	mnl_socket_close(nl);
276 }
277 
trace_print_packet(const struct nftnl_trace * nlt,struct cb_arg * args)278 static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *args)
279 {
280 	struct list_head stmts = LIST_HEAD_INIT(stmts);
281 	uint32_t nfproto, family;
282 	uint16_t l4proto = 0;
283 	uint32_t mark;
284 	char name[IFNAMSIZ];
285 
286 	family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
287 	printf("PACKET: %d %08x ", family, nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
288 
289 	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF))
290 		printf("IN=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_IIF), name));
291 	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF))
292 		printf("OUT=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_OIF), name));
293 
294 	nfproto = family;
295 	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) {
296 		nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO);
297 
298 		if (family != nfproto)
299 			printf("NFPROTO=%d ", nfproto);
300 	}
301 
302 	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER)) {
303 		const struct ethhdr *eh;
304 		const char *linklayer;
305 		uint32_t i, len;
306 		uint16_t type = nftnl_trace_get_u16(nlt, NFTNL_TRACE_IIFTYPE);
307 
308 		linklayer = nftnl_trace_get_data(nlt, NFTNL_TRACE_LL_HEADER, &len);
309 		switch (type) {
310 		case ARPHRD_ETHER:
311 			if (len < sizeof(*eh))
312 			       break;
313 			eh = (const void *)linklayer;
314 			printf("MACSRC=%s ", ether_ntoa((const void *)eh->h_source));
315 			printf("MACDST=%s ", ether_ntoa((const void *)eh->h_dest));
316 			printf("MACPROTO=%04x ", ntohs(eh->h_proto));
317 			break;
318 		case ARPHRD_LOOPBACK:
319 			printf("LOOPBACK ");
320 			break;
321 		default:
322 			printf("LL=0x%x ", type);
323 			for (i = 0 ; i < len; i++)
324 				printf("%02x", linklayer[i]);
325 			printf(" ");
326 			break;
327 		}
328 	}
329 
330 	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER)) {
331 		const struct ip6_hdr *ip6h;
332 		const struct iphdr *iph;
333 		uint32_t i, len;
334 		const char *nh;
335 
336 		ip6h = nftnl_trace_get_data(nlt, NFTNL_TRACE_NETWORK_HEADER, &len);
337 
338 		switch (nfproto) {
339 		case NFPROTO_IPV4: {
340 			char addrbuf[INET_ADDRSTRLEN];
341 
342 			if (len < sizeof(*iph))
343 				break;
344 			iph = (const void *)ip6h;
345 
346 
347 			inet_ntop(AF_INET, &iph->saddr, addrbuf, sizeof(addrbuf));
348 			printf("SRC=%s ", addrbuf);
349 			inet_ntop(AF_INET, &iph->daddr, addrbuf, sizeof(addrbuf));
350 			printf("DST=%s ", addrbuf);
351 
352 			printf("LEN=%d TOS=0x%x TTL=%d ID=%d ", ntohs(iph->tot_len), iph->tos, iph->ttl, ntohs(iph->id));
353 			if (iph->frag_off & htons(0x8000))
354 				printf("CE ");
355 			if (iph->frag_off & htons(IP_DF))
356 				printf("DF ");
357 			if (iph->frag_off & htons(IP_MF))
358 				printf("MF ");
359 
360 			if (ntohs(iph->frag_off) & 0x1fff)
361 				printf("FRAG:%u ", ntohs(iph->frag_off) & 0x1fff);
362 
363 			l4proto = iph->protocol;
364 			if (iph->ihl * 4 > sizeof(*iph)) {
365 				unsigned int optsize;
366 				const char *op;
367 
368 				optsize = iph->ihl * 4 - sizeof(*iph);
369 				op = (const char *)iph;
370 				op += sizeof(*iph);
371 
372 				printf("OPT (");
373 				for (i = 0; i < optsize; i++)
374 					printf("%02X", op[i]);
375 				printf(") ");
376 			}
377 			break;
378 		}
379 		case NFPROTO_IPV6: {
380 			uint32_t flowlabel = ntohl(*(uint32_t *)ip6h);
381 			char addrbuf[INET6_ADDRSTRLEN];
382 
383 			if (len < sizeof(*ip6h))
384 				break;
385 
386 			inet_ntop(AF_INET6, &ip6h->ip6_src, addrbuf, sizeof(addrbuf));
387 			printf("SRC=%s ", addrbuf);
388 			inet_ntop(AF_INET6, &ip6h->ip6_dst, addrbuf, sizeof(addrbuf));
389 			printf("DST=%s ", addrbuf);
390 
391 			printf("LEN=%zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
392 				ntohs(ip6h->ip6_plen) + sizeof(*iph),
393 				(flowlabel & 0x0ff00000) >> 20,
394 				ip6h->ip6_hops,
395 				flowlabel & 0x000fffff);
396 
397 			l4proto = ip6h->ip6_nxt;
398 			break;
399 		}
400 		default:
401 			nh = (const char *)ip6h;
402 			printf("NH=");
403 			for (i = 0 ; i < len; i++)
404 				printf("%02x", nh[i]);
405 			printf(" ");
406 		}
407 	}
408 
409 	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TRANSPORT_HEADER)) {
410 		const struct tcphdr *tcph;
411 		uint32_t len;
412 
413 		tcph = nftnl_trace_get_data(nlt, NFTNL_TRACE_TRANSPORT_HEADER, &len);
414 
415 		switch (l4proto) {
416 		case IPPROTO_DCCP:
417 		case IPPROTO_SCTP:
418 		case IPPROTO_UDPLITE:
419 		case IPPROTO_UDP:
420 			if (len < 4)
421 				break;
422 			printf("SPORT=%d DPORT=%d ", ntohs(tcph->source), ntohs(tcph->dest));
423 			break;
424 		case IPPROTO_TCP:
425 			if (len < sizeof(*tcph))
426 				break;
427 			printf("SPORT=%d DPORT=%d ", ntohs(tcph->source), ntohs(tcph->dest));
428 			if (tcph->syn)
429 				printf("SYN ");
430 			if (tcph->ack)
431 				printf("ACK ");
432 			if (tcph->fin)
433 				printf("FIN ");
434 			if (tcph->rst)
435 				printf("RST ");
436 			if (tcph->psh)
437 				printf("PSH ");
438 			if (tcph->urg)
439 				printf("URG ");
440 			break;
441 		default:
442 			break;
443 		}
444 	}
445 
446 	mark = nftnl_trace_get_u32(nlt, NFTNL_TRACE_MARK);
447 	if (mark)
448 		printf("MARK=0x%x ", mark);
449 	puts("");
450 }
451 
trace_print_hdr(const struct nftnl_trace * nlt)452 static void trace_print_hdr(const struct nftnl_trace *nlt)
453 {
454 	printf(" TRACE: %d %08x %s:%s", nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY),
455 					nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID),
456 					nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE),
457 					nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
458 }
459 
print_verdict(const struct nftnl_trace * nlt,uint32_t verdict)460 static void print_verdict(const struct nftnl_trace *nlt, uint32_t verdict)
461 {
462 	const char *chain;
463 
464 	switch (verdict) {
465 	case NF_ACCEPT:
466 		printf("ACCEPT");
467 		break;
468 	case NF_DROP:
469 		printf("DROP");
470 		break;
471 	case NF_QUEUE:
472 		printf("QUEUE");
473 		break;
474 	case NF_STOLEN:
475 		printf("STOLEN");
476 		break;
477 	case NFT_BREAK:
478 		printf("BREAK");
479 		break;
480 	case NFT_CONTINUE:
481 		printf("CONTINUE");
482 		break;
483 	case NFT_GOTO:
484 		printf("GOTO");
485 		if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) {
486 			chain = nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET);
487 			printf(":%s", chain);
488 		}
489 		break;
490 	case NFT_JUMP:
491 		printf("JUMP");
492 		if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) {
493 			chain = nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET);
494 			printf(":%s", chain);
495 		}
496 		break;
497 	default:
498 		printf("0x%x", verdict);
499 		break;
500 	}
501 
502 	printf(" ");
503 }
504 
trace_cb(const struct nlmsghdr * nlh,struct cb_arg * arg)505 static int trace_cb(const struct nlmsghdr *nlh, struct cb_arg *arg)
506 {
507 	struct nftnl_trace *nlt;
508 	uint32_t verdict;
509 
510 	nlt = nftnl_trace_alloc();
511 	if (nlt == NULL)
512 		goto err;
513 
514 	if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0)
515 		goto err_free;
516 
517 	if (arg->nfproto &&
518 	    arg->nfproto != nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY))
519 		goto err_free;
520 
521 	switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) {
522 	case NFT_TRACETYPE_RULE:
523 		verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT);
524 
525 		if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
526 		    nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
527 			trace_print_packet(nlt, arg);
528 
529 		if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) {
530 			trace_print_hdr(nlt);
531 			printf(":rule:0x%" PRIx64":", nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE));
532 			print_verdict(nlt, verdict);
533 			printf(" ");
534 			trace_print_rule(nlt, arg);
535 		}
536 		break;
537 	case NFT_TRACETYPE_POLICY:
538 		trace_print_hdr(nlt);
539 		printf(":policy:");
540 		verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_POLICY);
541 
542 		print_verdict(nlt, verdict);
543 		puts("");
544 		break;
545 	case NFT_TRACETYPE_RETURN:
546 		trace_print_hdr(nlt);
547 		printf(":return:");
548 		trace_print_return(nlt);
549 		puts("");
550 		break;
551 	}
552 err_free:
553 	nftnl_trace_free(nlt);
554 err:
555 	return MNL_CB_OK;
556 }
557 
monitor_cb(const struct nlmsghdr * nlh,void * data)558 static int monitor_cb(const struct nlmsghdr *nlh, void *data)
559 {
560 	uint32_t type = nlh->nlmsg_type & 0xFF;
561 	struct cb_arg *arg = data;
562 	int ret = MNL_CB_OK;
563 
564 	switch(type) {
565 	case NFT_MSG_NEWTABLE:
566 	case NFT_MSG_DELTABLE:
567 		ret = table_cb(nlh, data);
568 		break;
569 	case NFT_MSG_NEWCHAIN:
570 	case NFT_MSG_DELCHAIN:
571 		ret = chain_cb(nlh, data);
572 		break;
573 	case NFT_MSG_NEWRULE:
574 	case NFT_MSG_DELRULE:
575 		arg->is_event = true;
576 		ret = rule_cb(nlh, data);
577 		break;
578 	case NFT_MSG_NEWGEN:
579 		ret = newgen_cb(nlh, data);
580 		break;
581 	case NFT_MSG_TRACE:
582 		ret = trace_cb(nlh, data);
583 		break;
584 	}
585 
586 	fflush(stdout);
587 	return ret;
588 }
589 
590 static const struct option options[] = {
591 	{.name = "counters", .has_arg = false, .val = 'c'},
592 	{.name = "trace", .has_arg = false, .val = 't'},
593 	{.name = "event", .has_arg = false, .val = 'e'},
594 	{.name = "ipv4", .has_arg = false, .val = '4'},
595 	{.name = "ipv6", .has_arg = false, .val = '6'},
596 	{.name = "version", .has_arg = false, .val = 'V'},
597 	{.name = "help", .has_arg = false, .val = 'h'},
598 	{NULL},
599 };
600 
print_usage(void)601 static void print_usage(void)
602 {
603 	printf("%s %s\n", xtables_globals.program_name,
604 			  xtables_globals.program_version);
605 	printf("Usage: %s [ -t | -e ]\n"
606 	       "        --trace    -t    trace ruleset traversal of packets tagged via -j TRACE rule\n"
607 	       "        --event    -e    show events that modify the ruleset\n"
608 	       "Optional arguments:\n"
609 	       "        --ipv4     -4    only monitor IPv4\n"
610 	       "        --ipv6     -6    only monitor IPv6\n"
611 	       "	--counters -c    show counters in rules\n"
612 
613 	       , xtables_globals.program_name);
614 	exit(EXIT_FAILURE);
615 }
616 
xtables_monitor_main(int argc,char * argv[])617 int xtables_monitor_main(int argc, char *argv[])
618 {
619 	struct mnl_socket *nl;
620 	char buf[MNL_SOCKET_BUFFER_SIZE];
621 	uint32_t nfgroup = 0;
622 	struct nft_handle h = {};
623 	struct cb_arg cb_arg = {
624 		.h = &h,
625 	};
626 	int ret, c;
627 
628 	xtables_globals.program_name = "xtables-monitor";
629 	/* XXX xtables_init_all does several things we don't want */
630 	c = xtables_init_all(&xtables_globals, NFPROTO_IPV4);
631 	if (c < 0) {
632 		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
633 				xtables_globals.program_name,
634 				xtables_globals.program_version);
635 		exit(1);
636 	}
637 	init_extensions();
638 	init_extensions4();
639 	init_extensions6();
640 	init_extensionsa();
641 	init_extensionsb();
642 
643 	if (nft_init(&h, AF_INET)) {
644 		fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
645 			xtables_globals.program_name,
646 			xtables_globals.program_version,
647 			strerror(errno));
648 		exit(EXIT_FAILURE);
649 	}
650 
651 	opterr = 0;
652 	while ((c = getopt_long(argc, argv, "ceht46V", options, NULL)) != -1) {
653 		switch (c) {
654 	        case 'c':
655 			counters = true;
656 			break;
657 	        case 't':
658 			trace = true;
659 			break;
660 	        case 'e':
661 			events = true;
662 			break;
663 	        case 'h':
664 			print_usage();
665 			exit(0);
666 		case '4':
667 			cb_arg.nfproto = NFPROTO_IPV4;
668 			break;
669 		case '6':
670 			cb_arg.nfproto = NFPROTO_IPV6;
671 			break;
672 		case 'V':
673 			printf("xtables-monitor %s\n", PACKAGE_VERSION);
674 			exit(0);
675 		default:
676 			fprintf(stderr, "xtables-monitor %s: Bad argument.\n", PACKAGE_VERSION);
677 			fprintf(stderr, "Try `xtables-monitor -h' for more information.\n");
678 			exit(PARAMETER_PROBLEM);
679 		}
680 	}
681 
682 	if (trace)
683 		nfgroup |= 1 << (NFNLGRP_NFTRACE - 1);
684 	if (events)
685 		nfgroup |= 1 << (NFNLGRP_NFTABLES - 1);
686 
687 	if (nfgroup == 0) {
688 		print_usage();
689 		exit(EXIT_FAILURE);
690 	}
691 
692 	nl = mnl_socket_open(NETLINK_NETFILTER);
693 	if (nl == NULL) {
694 		perror("cannot open nfnetlink socket");
695 		exit(EXIT_FAILURE);
696 	}
697 
698 	if (mnl_socket_bind(nl, nfgroup, MNL_SOCKET_AUTOPID) < 0) {
699 		perror("cannot bind to nfnetlink socket");
700 		exit(EXIT_FAILURE);
701 	}
702 
703 	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
704 	while (ret > 0) {
705 		ret = mnl_cb_run(buf, ret, 0, 0, monitor_cb, &cb_arg);
706 		if (ret <= 0)
707 			break;
708 		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
709 	}
710 	if (ret == -1) {
711 		perror("cannot receive from nfnetlink socket");
712 		exit(EXIT_FAILURE);
713 	}
714 	mnl_socket_close(nl);
715 
716 	xtables_fini();
717 
718 	return EXIT_SUCCESS;
719 }
720 
721