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