libmnl  1.0.3
nf-queue.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 
13 #ifndef aligned_be64
14 #define aligned_be64 u_int64_t __attribute__((aligned(8)))
15 #endif
16 
17 #include <linux/netfilter/nfnetlink_queue.h>
18 
19 static int parse_attr_cb(const struct nlattr *attr, void *data)
20 {
21  const struct nlattr **tb = data;
22  int type = mnl_attr_get_type(attr);
23 
24  /* skip unsupported attribute in user-space */
25  if (mnl_attr_type_valid(attr, NFQA_MAX) < 0)
26  return MNL_CB_OK;
27 
28  switch(type) {
29  case NFQA_MARK:
30  case NFQA_IFINDEX_INDEV:
31  case NFQA_IFINDEX_OUTDEV:
32  case NFQA_IFINDEX_PHYSINDEV:
33  case NFQA_IFINDEX_PHYSOUTDEV:
34  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
35  perror("mnl_attr_validate");
36  return MNL_CB_ERROR;
37  }
38  break;
39  case NFQA_TIMESTAMP:
40  if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
41  sizeof(struct nfqnl_msg_packet_timestamp)) < 0) {
42  perror("mnl_attr_validate");
43  return MNL_CB_ERROR;
44  }
45  break;
46  case NFQA_HWADDR:
47  if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
48  sizeof(struct nfqnl_msg_packet_hw)) < 0) {
49  perror("mnl_attr_validate");
50  return MNL_CB_ERROR;
51  }
52  break;
53  case NFQA_PAYLOAD:
54  break;
55  }
56  tb[type] = attr;
57  return MNL_CB_OK;
58 }
59 
60 static int queue_cb(const struct nlmsghdr *nlh, void *data)
61 {
62  struct nlattr *tb[NFQA_MAX+1] = {};
63  struct nfqnl_msg_packet_hdr *ph = NULL;
64  uint32_t id = 0;
65 
66  mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
67  if (tb[NFQA_PACKET_HDR]) {
68  ph = mnl_attr_get_payload(tb[NFQA_PACKET_HDR]);
69  id = ntohl(ph->packet_id);
70  }
71  printf("packet received (id=%u hw=0x%04x hook=%u)\n",
72  id, ntohs(ph->hw_protocol), ph->hook);
73 
74  return MNL_CB_OK + id;
75 }
76 
77 static struct nlmsghdr *
78 nfq_build_cfg_pf_request(char *buf, uint8_t command)
79 {
80  struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
81  nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG;
82  nlh->nlmsg_flags = NLM_F_REQUEST;
83 
84  struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
85  nfg->nfgen_family = AF_UNSPEC;
86  nfg->version = NFNETLINK_V0;
87 
88  struct nfqnl_msg_config_cmd cmd = {
89  .command = command,
90  .pf = htons(AF_INET),
91  };
92  mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(cmd), &cmd);
93 
94  return nlh;
95 }
96 
97 static struct nlmsghdr *
98 nfq_build_cfg_request(char *buf, uint8_t command, int queue_num)
99 {
100  struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
101  nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG;
102  nlh->nlmsg_flags = NLM_F_REQUEST;
103 
104  struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
105  nfg->nfgen_family = AF_UNSPEC;
106  nfg->version = NFNETLINK_V0;
107  nfg->res_id = htons(queue_num);
108 
109  struct nfqnl_msg_config_cmd cmd = {
110  .command = command,
111  .pf = htons(AF_INET),
112  };
113  mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(cmd), &cmd);
114 
115  return nlh;
116 }
117 
118 static struct nlmsghdr *
119 nfq_build_cfg_params(char *buf, uint8_t mode, int range, int queue_num)
120 {
121  struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
122  nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG;
123  nlh->nlmsg_flags = NLM_F_REQUEST;
124 
125  struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
126  nfg->nfgen_family = AF_UNSPEC;
127  nfg->version = NFNETLINK_V0;
128  nfg->res_id = htons(queue_num);
129 
130  struct nfqnl_msg_config_params params = {
131  .copy_range = htonl(range),
132  .copy_mode = mode,
133  };
134  mnl_attr_put(nlh, NFQA_CFG_PARAMS, sizeof(params), &params);
135 
136  return nlh;
137 }
138 
139 static struct nlmsghdr *
140 nfq_build_verdict(char *buf, int id, int queue_num, int verd)
141 {
142  struct nlmsghdr *nlh;
143  struct nfgenmsg *nfg;
144 
145  nlh = mnl_nlmsg_put_header(buf);
146  nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT;
147  nlh->nlmsg_flags = NLM_F_REQUEST;
148  nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
149  nfg->nfgen_family = AF_UNSPEC;
150  nfg->version = NFNETLINK_V0;
151  nfg->res_id = htons(queue_num);
152 
153  struct nfqnl_msg_verdict_hdr vh = {
154  .verdict = htonl(verd),
155  .id = htonl(id),
156  };
157  mnl_attr_put(nlh, NFQA_VERDICT_HDR, sizeof(vh), &vh);
158 
159  return nlh;
160 }
161 
162 int main(int argc, char *argv[])
163 {
164  struct mnl_socket *nl;
165  char buf[MNL_SOCKET_BUFFER_SIZE];
166  struct nlmsghdr *nlh;
167  int ret;
168  unsigned int portid, queue_num;
169 
170  if (argc != 2) {
171  printf("Usage: %s [queue_num]\n", argv[0]);
172  exit(EXIT_FAILURE);
173  }
174  queue_num = atoi(argv[1]);
175 
176  nl = mnl_socket_open(NETLINK_NETFILTER);
177  if (nl == NULL) {
178  perror("mnl_socket_open");
179  exit(EXIT_FAILURE);
180  }
181 
182  if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
183  perror("mnl_socket_bind");
184  exit(EXIT_FAILURE);
185  }
186  portid = mnl_socket_get_portid(nl);
187 
188  nlh = nfq_build_cfg_pf_request(buf, NFQNL_CFG_CMD_PF_UNBIND);
189 
190  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
191  perror("mnl_socket_send");
192  exit(EXIT_FAILURE);
193  }
194 
195  nlh = nfq_build_cfg_pf_request(buf, NFQNL_CFG_CMD_PF_BIND);
196 
197  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
198  perror("mnl_socket_send");
199  exit(EXIT_FAILURE);
200  }
201 
202  nlh = nfq_build_cfg_request(buf, NFQNL_CFG_CMD_BIND, queue_num);
203 
204  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
205  perror("mnl_socket_send");
206  exit(EXIT_FAILURE);
207  }
208 
209  nlh = nfq_build_cfg_params(buf, NFQNL_COPY_PACKET, 0xFFFF, queue_num);
210 
211  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
212  perror("mnl_socket_send");
213  exit(EXIT_FAILURE);
214  }
215 
216  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
217  if (ret == -1) {
218  perror("mnl_socket_recvfrom");
219  exit(EXIT_FAILURE);
220  }
221  while (ret > 0) {
222  uint32_t id;
223 
224  ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, NULL);
225  if (ret < 0){
226  perror("mnl_cb_run");
227  exit(EXIT_FAILURE);
228  }
229 
230  id = ret - MNL_CB_OK;
231  nlh = nfq_build_verdict(buf, id, queue_num, NF_ACCEPT);
232  if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
233  perror("mnl_socket_send");
234  exit(EXIT_FAILURE);
235  }
236 
237  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
238  if (ret == -1) {
239  perror("mnl_socket_recvfrom");
240  exit(EXIT_FAILURE);
241  }
242  }
243 
244  mnl_socket_close(nl);
245 
246  return 0;
247 }