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