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