libmnl  1.0.4
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 
11 static 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 
32 static 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 
47 static 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 
77 static 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 
105 static 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 
131 static 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 
144 static 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 
172 static 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 
203 int 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 
237  mnl_socket_close(nl);
238 
239  return 0;
240 }