libmnl  1.0.4
nf-log.c
1 /* This example is placed in the public domain. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <time.h>
7 #include <arpa/inet.h>
8 
9 #include <libmnl/libmnl.h>
10 #include <linux/netfilter.h>
11 #include <linux/netfilter/nfnetlink.h>
12 #include <linux/netfilter/nfnetlink_log.h>
13 
14 static int parse_attr_cb(const struct nlattr *attr, void *data)
15 {
16  const struct nlattr **tb = data;
17  int type = mnl_attr_get_type(attr);
18 
19  /* skip unsupported attribute in user-space */
20  if (mnl_attr_type_valid(attr, NFULA_MAX) < 0)
21  return MNL_CB_OK;
22 
23  switch(type) {
24  case NFULA_MARK:
25  case NFULA_IFINDEX_INDEV:
26  case NFULA_IFINDEX_OUTDEV:
27  case NFULA_IFINDEX_PHYSINDEV:
28  case NFULA_IFINDEX_PHYSOUTDEV:
29  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
30  perror("mnl_attr_validate");
31  return MNL_CB_ERROR;
32  }
33  break;
34  case NFULA_TIMESTAMP:
35  if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
36  sizeof(struct nfulnl_msg_packet_timestamp)) < 0) {
37  perror("mnl_attr_validate2");
38  return MNL_CB_ERROR;
39  }
40  break;
41  case NFULA_HWADDR:
42  if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
43  sizeof(struct nfulnl_msg_packet_hw)) < 0) {
44  perror("mnl_attr_validate2");
45  return MNL_CB_ERROR;
46  }
47  break;
48  case NFULA_PREFIX:
49  if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) {
50  perror("mnl_attr_validate");
51  return MNL_CB_ERROR;
52  }
53  break;
54  case NFULA_PAYLOAD:
55  break;
56  }
57  tb[type] = attr;
58  return MNL_CB_OK;
59 }
60 
61 static int log_cb(const struct nlmsghdr *nlh, void *data)
62 {
63  struct nlattr *tb[NFULA_MAX+1] = {};
64  struct nfulnl_msg_packet_hdr *ph = NULL;
65  const char *prefix = NULL;
66  uint32_t mark = 0;
67 
68  mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
69  if (tb[NFULA_PACKET_HDR])
70  ph = mnl_attr_get_payload(tb[NFULA_PACKET_HDR]);
71  if (tb[NFULA_PREFIX])
72  prefix = mnl_attr_get_str(tb[NFULA_PREFIX]);
73  if (tb[NFULA_MARK])
74  mark = ntohl(mnl_attr_get_u32(tb[NFULA_MARK]));
75 
76  printf("log received (prefix=\"%s\" hw=0x%04x hook=%u mark=%u)\n",
77  prefix ? prefix : "", ntohs(ph->hw_protocol), ph->hook,
78  mark);
79 
80  return MNL_CB_OK;
81 }
82 
83 static struct nlmsghdr *
84 nflog_build_cfg_pf_request(char *buf, uint8_t command)
85 {
86  struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
87  nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
88  nlh->nlmsg_flags = NLM_F_REQUEST;
89 
90  struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
91  nfg->nfgen_family = AF_INET;
92  nfg->version = NFNETLINK_V0;
93 
94  struct nfulnl_msg_config_cmd cmd = {
95  .command = command,
96  };
97  mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
98 
99  return nlh;
100 }
101 
102 static struct nlmsghdr *
103 nflog_build_cfg_request(char *buf, uint8_t command, int qnum)
104 {
105  struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
106  nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
107  nlh->nlmsg_flags = NLM_F_REQUEST;
108 
109  struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
110  nfg->nfgen_family = AF_INET;
111  nfg->version = NFNETLINK_V0;
112  nfg->res_id = htons(qnum);
113 
114  struct nfulnl_msg_config_cmd cmd = {
115  .command = command,
116  };
117  mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
118 
119  return nlh;
120 }
121 
122 static struct nlmsghdr *
123 nflog_build_cfg_params(char *buf, uint8_t mode, int range, int qnum)
124 {
125  struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
126  nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
127  nlh->nlmsg_flags = NLM_F_REQUEST;
128 
129  struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
130  nfg->nfgen_family = AF_UNSPEC;
131  nfg->version = NFNETLINK_V0;
132  nfg->res_id = htons(qnum);
133 
134  struct nfulnl_msg_config_mode params = {
135  .copy_range = htonl(range),
136  .copy_mode = mode,
137  };
138  mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), &params);
139 
140  return nlh;
141 }
142 
143 int main(int argc, char *argv[])
144 {
145  struct mnl_socket *nl;
146  char buf[MNL_SOCKET_BUFFER_SIZE];
147  struct nlmsghdr *nlh;
148  int ret;
149  unsigned int portid, qnum;
150 
151  if (argc != 2) {
152  printf("Usage: %s [queue_num]\n", argv[0]);
153  exit(EXIT_FAILURE);
154  }
155  qnum = atoi(argv[1]);
156 
157  nl = mnl_socket_open(NETLINK_NETFILTER);
158  if (nl == NULL) {
159  perror("mnl_socket_open");
160  exit(EXIT_FAILURE);
161  }
162 
163  if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
164  perror("mnl_socket_bind");
165  exit(EXIT_FAILURE);
166  }
167  portid = mnl_socket_get_portid(nl);
168 
169  nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_UNBIND);
170 
171  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
172  perror("mnl_socket_sendto");
173  exit(EXIT_FAILURE);
174  }
175 
176  nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_BIND);
177 
178  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
179  perror("mnl_socket_sendto");
180  exit(EXIT_FAILURE);
181  }
182 
183  nlh = nflog_build_cfg_request(buf, NFULNL_CFG_CMD_BIND, qnum);
184 
185  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
186  perror("mnl_socket_sendto");
187  exit(EXIT_FAILURE);
188  }
189 
190  nlh = nflog_build_cfg_params(buf, NFULNL_COPY_PACKET, 0xFFFF, qnum);
191 
192  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
193  perror("mnl_socket_sendto");
194  exit(EXIT_FAILURE);
195  }
196 
197  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
198  if (ret == -1) {
199  perror("mnl_socket_recvfrom");
200  exit(EXIT_FAILURE);
201  }
202  while (ret > 0) {
203  ret = mnl_cb_run(buf, ret, 0, portid, log_cb, NULL);
204  if (ret < 0){
205  perror("mnl_cb_run");
206  exit(EXIT_FAILURE);
207  }
208 
209  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
210  if (ret == -1) {
211  perror("mnl_socket_recvfrom");
212  exit(EXIT_FAILURE);
213  }
214  }
215 
216  mnl_socket_close(nl);
217 
218  return 0;
219 }