libmnl 1.0.5
nfct-dump.c
1/* This example is placed in the public domain. */
2#include <endian.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <time.h>
7#include <arpa/inet.h>
8#include <inttypes.h>
9
10#include <libmnl/libmnl.h>
11#include <linux/netfilter/nfnetlink.h>
12#include <linux/netfilter/nfnetlink_conntrack.h>
13
14static int parse_counters_cb(const struct nlattr *attr, void *data)
15{
16 const struct nlattr **tb = data;
17 int type = mnl_attr_get_type(attr);
18
19 if (mnl_attr_type_valid(attr, CTA_COUNTERS_MAX) < 0)
20 return MNL_CB_OK;
21
22 switch(type) {
23 case CTA_COUNTERS_PACKETS:
24 case CTA_COUNTERS_BYTES:
25 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
26 perror("mnl_attr_validate");
27 return MNL_CB_ERROR;
28 }
29 break;
30 }
31 tb[type] = attr;
32 return MNL_CB_OK;
33}
34
35static void print_counters(const struct nlattr *nest)
36{
37 struct nlattr *tb[CTA_COUNTERS_MAX+1] = {};
38
39 mnl_attr_parse_nested(nest, parse_counters_cb, tb);
40 if (tb[CTA_COUNTERS_PACKETS]) {
41 printf("packets=%"PRIu64" ",
42 be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS])));
43 }
44 if (tb[CTA_COUNTERS_BYTES]) {
45 printf("bytes=%"PRIu64" ",
46 be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES])));
47 }
48}
49
50static int parse_ip_cb(const struct nlattr *attr, void *data)
51{
52 const struct nlattr **tb = data;
53 int type = mnl_attr_get_type(attr);
54
55 if (mnl_attr_type_valid(attr, CTA_IP_MAX) < 0)
56 return MNL_CB_OK;
57
58 switch(type) {
59 case CTA_IP_V4_SRC:
60 case CTA_IP_V4_DST:
61 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
62 perror("mnl_attr_validate");
63 return MNL_CB_ERROR;
64 }
65 break;
66 case CTA_IP_V6_SRC:
67 case CTA_IP_V6_DST:
68 if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
69 sizeof(struct in6_addr)) < 0) {
70 perror("mnl_attr_validate2");
71 return MNL_CB_ERROR;
72 }
73 break;
74 }
75 tb[type] = attr;
76 return MNL_CB_OK;
77}
78
79static void print_ip(const struct nlattr *nest)
80{
81 struct nlattr *tb[CTA_IP_MAX+1] = {};
82
83 mnl_attr_parse_nested(nest, parse_ip_cb, tb);
84 if (tb[CTA_IP_V4_SRC]) {
85 struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_SRC]);
86 printf("src=%s ", inet_ntoa(*in));
87 }
88 if (tb[CTA_IP_V4_DST]) {
89 struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_DST]);
90 printf("dst=%s ", inet_ntoa(*in));
91 }
92 if (tb[CTA_IP_V6_SRC]) {
93 struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_SRC]);
94 char out[INET6_ADDRSTRLEN];
95
96 if (!inet_ntop(AF_INET6, in, out, sizeof(out)))
97 printf("src=%s ", out);
98 }
99 if (tb[CTA_IP_V6_DST]) {
100 struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_DST]);
101 char out[INET6_ADDRSTRLEN];
102
103 if (!inet_ntop(AF_INET6, in, out, sizeof(out)))
104 printf("dst=%s ", out);
105 }
106}
107
108static int parse_proto_cb(const struct nlattr *attr, void *data)
109{
110 const struct nlattr **tb = data;
111 int type = mnl_attr_get_type(attr);
112
113 if (mnl_attr_type_valid(attr, CTA_PROTO_MAX) < 0)
114 return MNL_CB_OK;
115
116 switch(type) {
117 case CTA_PROTO_NUM:
118 case CTA_PROTO_ICMP_TYPE:
119 case CTA_PROTO_ICMP_CODE:
120 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
121 perror("mnl_attr_validate");
122 return MNL_CB_ERROR;
123 }
124 break;
125 case CTA_PROTO_SRC_PORT:
126 case CTA_PROTO_DST_PORT:
127 case CTA_PROTO_ICMP_ID:
128 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
129 perror("mnl_attr_validate");
130 return MNL_CB_ERROR;
131 }
132 break;
133 }
134 tb[type] = attr;
135 return MNL_CB_OK;
136}
137
138static void print_proto(const struct nlattr *nest)
139{
140 struct nlattr *tb[CTA_PROTO_MAX+1] = {};
141
142 mnl_attr_parse_nested(nest, parse_proto_cb, tb);
143 if (tb[CTA_PROTO_NUM]) {
144 printf("proto=%u ", mnl_attr_get_u8(tb[CTA_PROTO_NUM]));
145 }
146 if (tb[CTA_PROTO_SRC_PORT]) {
147 printf("sport=%u ",
148 ntohs(mnl_attr_get_u16(tb[CTA_PROTO_SRC_PORT])));
149 }
150 if (tb[CTA_PROTO_DST_PORT]) {
151 printf("dport=%u ",
152 ntohs(mnl_attr_get_u16(tb[CTA_PROTO_DST_PORT])));
153 }
154 if (tb[CTA_PROTO_ICMP_ID]) {
155 printf("id=%u ",
156 ntohs(mnl_attr_get_u16(tb[CTA_PROTO_ICMP_ID])));
157 }
158 if (tb[CTA_PROTO_ICMP_TYPE]) {
159 printf("type=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
160 }
161 if (tb[CTA_PROTO_ICMP_CODE]) {
162 printf("code=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_CODE]));
163 }
164}
165
166static int parse_tuple_cb(const struct nlattr *attr, void *data)
167{
168 const struct nlattr **tb = data;
169 int type = mnl_attr_get_type(attr);
170
171 if (mnl_attr_type_valid(attr, CTA_TUPLE_MAX) < 0)
172 return MNL_CB_OK;
173
174 switch(type) {
175 case CTA_TUPLE_IP:
176 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
177 perror("mnl_attr_validate");
178 return MNL_CB_ERROR;
179 }
180 break;
181 case CTA_TUPLE_PROTO:
182 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
183 perror("mnl_attr_validate");
184 return MNL_CB_ERROR;
185 }
186 break;
187 }
188 tb[type] = attr;
189 return MNL_CB_OK;
190}
191
192static void print_tuple(const struct nlattr *nest)
193{
194 struct nlattr *tb[CTA_TUPLE_MAX+1] = {};
195
196 mnl_attr_parse_nested(nest, parse_tuple_cb, tb);
197 if (tb[CTA_TUPLE_IP]) {
198 print_ip(tb[CTA_TUPLE_IP]);
199 }
200 if (tb[CTA_TUPLE_PROTO]) {
201 print_proto(tb[CTA_TUPLE_PROTO]);
202 }
203}
204
205static int data_attr_cb(const struct nlattr *attr, void *data)
206{
207 const struct nlattr **tb = data;
208 int type = mnl_attr_get_type(attr);
209
210 if (mnl_attr_type_valid(attr, CTA_MAX) < 0)
211 return MNL_CB_OK;
212
213 switch(type) {
214 case CTA_TUPLE_ORIG:
215 case CTA_COUNTERS_ORIG:
216 case CTA_COUNTERS_REPLY:
217 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
218 perror("mnl_attr_validate");
219 return MNL_CB_ERROR;
220 }
221 break;
222 case CTA_TIMEOUT:
223 case CTA_MARK:
224 case CTA_SECMARK:
225 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
226 perror("mnl_attr_validate");
227 return MNL_CB_ERROR;
228 }
229 break;
230 }
231 tb[type] = attr;
232 return MNL_CB_OK;
233}
234
235static int data_cb(const struct nlmsghdr *nlh, void *data)
236{
237 struct nlattr *tb[CTA_MAX+1] = {};
238 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
239
240 mnl_attr_parse(nlh, sizeof(*nfg), data_attr_cb, tb);
241 if (tb[CTA_TUPLE_ORIG])
242 print_tuple(tb[CTA_TUPLE_ORIG]);
243
244 if (tb[CTA_MARK])
245 printf("mark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_MARK])));
246
247 if (tb[CTA_SECMARK])
248 printf("secmark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_SECMARK])));
249
250 if (tb[CTA_COUNTERS_ORIG]) {
251 printf("original ");
252 print_counters(tb[CTA_COUNTERS_ORIG]);
253 }
254
255 if (tb[CTA_COUNTERS_REPLY]) {
256 printf("reply ");
257 print_counters(tb[CTA_COUNTERS_REPLY]);
258 }
259
260 printf("\n");
261 return MNL_CB_OK;
262}
263
264int main(void)
265{
266 char buf[MNL_SOCKET_DUMP_SIZE];
267 struct mnl_socket *nl;
268 struct nlmsghdr *nlh;
269 struct nfgenmsg *nfh;
270 uint32_t seq, portid;
271 int ret;
272
273 nl = mnl_socket_open(NETLINK_NETFILTER);
274 if (nl == NULL) {
275 perror("mnl_socket_open");
276 exit(EXIT_FAILURE);
277 }
278
279 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
280 perror("mnl_socket_bind");
281 exit(EXIT_FAILURE);
282 }
283
284 nlh = mnl_nlmsg_put_header(buf);
285 nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET;
286 nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
287 nlh->nlmsg_seq = seq = time(NULL);
288
289 nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
290 nfh->nfgen_family = AF_INET;
291 nfh->version = NFNETLINK_V0;
292 nfh->res_id = 0;
293
294 ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
295 if (ret == -1) {
296 perror("mnl_socket_sendto");
297 exit(EXIT_FAILURE);
298 }
299 portid = mnl_socket_get_portid(nl);
300
301 while (1) {
302 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
303 if (ret == -1) {
304 perror("mnl_socket_recvfrom");
305 exit(EXIT_FAILURE);
306 }
307
308 ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL);
309 if (ret == -1) {
310 perror("mnl_cb_run");
311 exit(EXIT_FAILURE);
312 } else if (ret <= MNL_CB_STOP)
313 break;
314 }
315
317
318 return 0;
319}
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
uint64_t mnl_attr_get_u64(const struct nlattr *attr)
Definition attr.c:367
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
int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type, size_t exp_len)
Definition attr.c:229
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
struct nlmsghdr * mnl_nlmsg_put_header(void *buf)
Definition nlmsg.c:80
void * mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size)
Definition nlmsg.c:101
int mnl_socket_close(struct mnl_socket *nl)
Definition socket.c:296
unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
Definition socket.c:99
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
ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *buf, size_t len)
Definition socket.c:232