xref: /aosp_15_r20/external/libnl/src/nf-ct-events.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2018 Avast software
4  */
5 
6 #include "nl-default.h"
7 
8 #include <linux/netlink.h>
9 #include <linux/netfilter/nfnetlink.h>
10 #include <linux/netfilter/nfnetlink_conntrack.h>
11 
12 #include <netlink/cli/utils.h>
13 #include <netlink/cli/ct.h>
14 
15 struct private_nl_object
16 {
17 	int			ce_refcnt;
18 	struct nl_object_ops *	ce_ops;
19 	struct nl_cache *	ce_cache;
20 	struct nl_list_head	ce_list;
21 	int			ce_msgtype;
22 	int			ce_flags;
23 	uint64_t		ce_mask;
24 };
25 
nf_conntrack_parse_callback(struct nl_object * obj,void * opaque)26 static void nf_conntrack_parse_callback(struct nl_object *obj, void *opaque)
27 {
28 	struct nl_dump_params params = {
29 		.dp_fd = stdout,
30 		.dp_type = NL_DUMP_DETAILS,
31 	};
32 
33 	nl_object_dump(obj, &params);
34 }
35 
nf_conntrack_event_callback(struct nl_msg * msg,void * opaque)36 static int nf_conntrack_event_callback(struct nl_msg *msg, void *opaque)
37 {
38 	int err;
39 	struct nlmsghdr *hdr = nlmsg_hdr(msg);
40 
41 	enum cntl_msg_types type = (enum cntl_msg_types) NFNL_MSG_TYPE(hdr->nlmsg_type);
42 
43 	int flags = hdr->nlmsg_flags;
44 
45 	if (type == IPCTNL_MSG_CT_DELETE) {
46 		printf("DELETE ");
47 	} else if (type == IPCTNL_MSG_CT_NEW) {
48 		if (flags & (NLM_F_CREATE|NLM_F_EXCL)) {
49 			printf("NEW ");
50 		} else {
51 			printf("UPDATE ");
52 		}
53 	} else {
54 		printf("UNKNOWN ");
55 	}
56 
57 	if ((err = nl_msg_parse(msg, &nf_conntrack_parse_callback, opaque)) < 0) {
58 		nl_cli_fatal(err, "nl_msg_parse: %s", nl_geterror(err));
59 	}
60 	/* Continue with next event */
61 	return NL_OK;
62 }
63 
main(int argc,char * argv[])64 int main(int argc, char *argv[])
65 {
66 	struct nl_sock *socket;
67 	int err;
68 
69 	socket = nl_cli_alloc_socket();
70 	if (socket == NULL) {
71 		nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket");
72 	}
73 
74 	/*
75 	 * Disable sequence number checking.
76 	 * This is required to allow messages to be processed which were not requested by
77 	 * a preceding request message, e.g. netlink events.
78 	 */
79 	nl_socket_disable_seq_check(socket);
80 
81 	/* subscribe conntrack events */
82 	nl_join_groups(socket, NF_NETLINK_CONNTRACK_NEW |
83 												 NF_NETLINK_CONNTRACK_UPDATE |
84 												 NF_NETLINK_CONNTRACK_DESTROY |
85 												 NF_NETLINK_CONNTRACK_EXP_NEW |
86 												 NF_NETLINK_CONNTRACK_EXP_UPDATE |
87 												 NF_NETLINK_CONNTRACK_EXP_DESTROY);
88 
89 	nl_cli_connect(socket, NETLINK_NETFILTER);
90 
91 	nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, &nf_conntrack_event_callback, 0);
92 
93 	while (1) {
94 
95 		errno = 0;
96 		if ((err = nl_recvmsgs_default(socket)) < 0) {
97 			switch (errno) {
98 				case 	ENOBUFS:
99 					// just print warning
100 					fprintf(stderr, "Lost events because of ENOBUFS\n");
101 					break;
102 				case EAGAIN:
103 				case EINTR:
104 					// continue reading
105 					break;
106 				default:
107 					nl_cli_fatal(err, "Failed to receive: %s", nl_geterror(err));
108 			}
109 		}
110 	}
111 }
112