libmnl 1.0.5
nfct-event.c
1/* This example is placed in the public domain. */
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <arpa/inet.h>
6
7#include <libmnl/libmnl.h>
8#include <linux/netfilter/nfnetlink.h>
9#include <linux/netfilter/nfnetlink_conntrack.h>
10
11static int parse_ip_cb(const struct nlattr *attr, void *data)
12{
13 const struct nlattr **tb = data;
14 int type = mnl_attr_get_type(attr);
15
16 if (mnl_attr_type_valid(attr, CTA_IP_MAX) < 0)
17 return MNL_CB_OK;
18
19 switch(type) {
20 case CTA_IP_V4_SRC:
21 case CTA_IP_V4_DST:
22 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
23 perror("mnl_attr_validate");
24 return MNL_CB_ERROR;
25 }
26 break;
27 }
28 tb[type] = attr;
29 return MNL_CB_OK;
30}
31
32static void print_ip(const struct nlattr *nest)
33{
34 struct nlattr *tb[CTA_IP_MAX+1] = {};
35
36 mnl_attr_parse_nested(nest, parse_ip_cb, tb);
37 if (tb[CTA_IP_V4_SRC]) {
38 struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_SRC]);
39 printf("src=%s ", inet_ntoa(*in));
40 }
41 if (tb[CTA_IP_V4_DST]) {
42 struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_DST]);
43 printf("dst=%s ", inet_ntoa(*in));
44 }
45}
46
47static int parse_proto_cb(const struct nlattr *attr, void *data)
48{
49 const struct nlattr **tb = data;
50 int type = mnl_attr_get_type(attr);
51
52 if (mnl_attr_type_valid(attr, CTA_PROTO_MAX) < 0)
53 return MNL_CB_OK;
54
55 switch(type) {
56 case CTA_PROTO_NUM:
57 case CTA_PROTO_ICMP_TYPE:
58 case CTA_PROTO_ICMP_CODE:
59 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
60 perror("mnl_attr_validate");
61 return MNL_CB_ERROR;
62 }
63 break;
64 case CTA_PROTO_SRC_PORT:
65 case CTA_PROTO_DST_PORT:
66 case CTA_PROTO_ICMP_ID:
67 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
68 perror("mnl_attr_validate");
69 return MNL_CB_ERROR;
70 }
71 break;
72 }
73 tb[type] = attr;
74 return MNL_CB_OK;
75}
76
77static void print_proto(const struct nlattr *nest)
78{
79 struct nlattr *tb[CTA_PROTO_MAX+1] = {};
80
81 mnl_attr_parse_nested(nest, parse_proto_cb, tb);
82 if (tb[CTA_PROTO_NUM]) {
83 printf("proto=%u ", mnl_attr_get_u8(tb[CTA_PROTO_NUM]));
84 }
85 if (tb[CTA_PROTO_SRC_PORT]) {
86 printf("sport=%u ",
87 ntohs(mnl_attr_get_u16(tb[CTA_PROTO_SRC_PORT])));
88 }
89 if (tb[CTA_PROTO_DST_PORT]) {
90 printf("dport=%u ",
91 ntohs(mnl_attr_get_u16(tb[CTA_PROTO_DST_PORT])));
92 }
93 if (tb[CTA_PROTO_ICMP_ID]) {
94 printf("id=%u ",
95 ntohs(mnl_attr_get_u16(tb[CTA_PROTO_ICMP_ID])));
96 }
97 if (tb[CTA_PROTO_ICMP_TYPE]) {
98 printf("type=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
99 }
100 if (tb[CTA_PROTO_ICMP_CODE]) {
101 printf("code=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_CODE]));
102 }
103}
104
105static int parse_tuple_cb(const struct nlattr *attr, void *data)
106{
107 const struct nlattr **tb = data;
108 int type = mnl_attr_get_type(attr);
109
110 if (mnl_attr_type_valid(attr, CTA_TUPLE_MAX) < 0)
111 return MNL_CB_OK;
112
113 switch(type) {
114 case CTA_TUPLE_IP:
115 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
116 perror("mnl_attr_validate");
117 return MNL_CB_ERROR;
118 }
119 break;
120 case CTA_TUPLE_PROTO:
121 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
122 perror("mnl_attr_validate");
123 return MNL_CB_ERROR;
124 }
125 break;
126 }
127 tb[type] = attr;
128 return MNL_CB_OK;
129}
130
131static void print_tuple(const struct nlattr *nest)
132{
133 struct nlattr *tb[CTA_TUPLE_MAX+1] = {};
134
135 mnl_attr_parse_nested(nest, parse_tuple_cb, tb);
136 if (tb[CTA_TUPLE_IP]) {
137 print_ip(tb[CTA_TUPLE_IP]);
138 }
139 if (tb[CTA_TUPLE_PROTO]) {
140 print_proto(tb[CTA_TUPLE_PROTO]);
141 }
142}
143
144static int data_attr_cb(const struct nlattr *attr, void *data)
145{
146 const struct nlattr **tb = data;
147 int type = mnl_attr_get_type(attr);
148
149 if (mnl_attr_type_valid(attr, CTA_MAX) < 0)
150 return MNL_CB_OK;
151
152 switch(type) {
153 case CTA_TUPLE_ORIG:
154 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
155 perror("mnl_attr_validate");
156 return MNL_CB_ERROR;
157 }
158 break;
159 case CTA_TIMEOUT:
160 case CTA_MARK:
161 case CTA_SECMARK:
162 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
163 perror("mnl_attr_validate");
164 return MNL_CB_ERROR;
165 }
166 break;
167 }
168 tb[type] = attr;
169 return MNL_CB_OK;
170}
171
172static int data_cb(const struct nlmsghdr *nlh, void *data)
173{
174 struct nlattr *tb[CTA_MAX+1] = {};
175 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
176
177 switch(nlh->nlmsg_type & 0xFF) {
178 case IPCTNL_MSG_CT_NEW:
179 if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
180 printf("%9s ", "[NEW] ");
181 else
182 printf("%9s ", "[UPDATE] ");
183 break;
184 case IPCTNL_MSG_CT_DELETE:
185 printf("%9s ", "[DESTROY] ");
186 break;
187 }
188
189 mnl_attr_parse(nlh, sizeof(*nfg), data_attr_cb, tb);
190 if (tb[CTA_TUPLE_ORIG]) {
191 print_tuple(tb[CTA_TUPLE_ORIG]);
192 }
193 if (tb[CTA_MARK]) {
194 printf("mark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_MARK])));
195 }
196 if (tb[CTA_SECMARK]) {
197 printf("secmark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_SECMARK])));
198 }
199 printf("\n");
200 return MNL_CB_OK;
201}
202
203int main(void)
204{
205 struct mnl_socket *nl;
206 char buf[MNL_SOCKET_BUFFER_SIZE];
207 int ret;
208
209 nl = mnl_socket_open(NETLINK_NETFILTER);
210 if (nl == NULL) {
211 perror("mnl_socket_open");
212 exit(EXIT_FAILURE);
213 }
214
215 if (mnl_socket_bind(nl, NF_NETLINK_CONNTRACK_NEW |
216 NF_NETLINK_CONNTRACK_UPDATE |
217 NF_NETLINK_CONNTRACK_DESTROY,
218 MNL_SOCKET_AUTOPID) < 0) {
219 perror("mnl_socket_bind");
220 exit(EXIT_FAILURE);
221 }
222
223 while (1) {
224 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
225 if (ret == -1) {
226 perror("mnl_socket_recvfrom");
227 exit(EXIT_FAILURE);
228 }
229
230 ret = mnl_cb_run(buf, ret, 0, 0, data_cb, NULL);
231 if (ret == -1) {
232 perror("mnl_cb_run");
233 exit(EXIT_FAILURE);
234 }
235 }
236
238
239 return 0;
240}
uint8_t mnl_attr_get_u8(const struct nlattr *attr)
Definition attr.c:332
int mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_cb_t cb, void *data)
Definition attr.c:282
void * mnl_attr_get_payload(const struct nlattr *attr)
Definition attr.c:72
int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
Definition attr.c:207
int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset, mnl_attr_cb_t cb, void *data)
Definition attr.c:255
int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
Definition attr.c:127
uint16_t mnl_attr_get_type(const struct nlattr *attr)
Definition attr.c:38
uint32_t mnl_attr_get_u32(const struct nlattr *attr)
Definition attr.c:354
uint16_t mnl_attr_get_u16(const struct nlattr *attr)
Definition attr.c:343
int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq, unsigned int portid, mnl_cb_t cb_data, void *data)
Definition callback.c:159
void * mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
Definition nlmsg.c:117
int mnl_socket_close(struct mnl_socket *nl)
Definition socket.c:296
struct mnl_socket * mnl_socket_open(int bus)
Definition socket.c:128
ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf, size_t bufsiz)
Definition socket.c:256
int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid)
Definition socket.c:193