libnetfilter_queue 1.0.5
nfqnl_test.c
1
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <netinet/in.h>
6#include <linux/types.h>
7#include <linux/netfilter.h> /* for NF_ACCEPT */
8#include <errno.h>
9
10#include <libnetfilter_queue/libnetfilter_queue.h>
11
12/* returns packet id */
13static uint32_t print_pkt (struct nfq_data *tb)
14{
15 int id = 0;
16 struct nfqnl_msg_packet_hdr *ph;
17 struct nfqnl_msg_packet_hw *hwph;
18 uint32_t mark, ifi, uid, gid;
19 int ret;
20 unsigned char *data, *secdata;
21
23 if (ph) {
24 id = ntohl(ph->packet_id);
25 printf("hw_protocol=0x%04x hook=%u id=%u ",
26 ntohs(ph->hw_protocol), ph->hook, id);
27 }
28
29 hwph = nfq_get_packet_hw(tb);
30 if (hwph) {
31 int i, hlen = ntohs(hwph->hw_addrlen);
32
33 printf("hw_src_addr=");
34 for (i = 0; i < hlen-1; i++)
35 printf("%02x:", hwph->hw_addr[i]);
36 printf("%02x ", hwph->hw_addr[hlen-1]);
37 }
38
39 mark = nfq_get_nfmark(tb);
40 if (mark)
41 printf("mark=%u ", mark);
42
43 ifi = nfq_get_indev(tb);
44 if (ifi)
45 printf("indev=%u ", ifi);
46
47 ifi = nfq_get_outdev(tb);
48 if (ifi)
49 printf("outdev=%u ", ifi);
50 ifi = nfq_get_physindev(tb);
51 if (ifi)
52 printf("physindev=%u ", ifi);
53
54 ifi = nfq_get_physoutdev(tb);
55 if (ifi)
56 printf("physoutdev=%u ", ifi);
57
58 if (nfq_get_uid(tb, &uid))
59 printf("uid=%u ", uid);
60
61 if (nfq_get_gid(tb, &gid))
62 printf("gid=%u ", gid);
63
64 ret = nfq_get_secctx(tb, &secdata);
65 if (ret > 0)
66 printf("secctx=\"%.*s\" ", ret, secdata);
67
68 ret = nfq_get_payload(tb, &data);
69 if (ret >= 0)
70 printf("payload_len=%d ", ret);
71
72 fputc('\n', stdout);
73
74 return id;
75}
76
77
78static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
79 struct nfq_data *nfa, void *data)
80{
81 uint32_t id = print_pkt(nfa);
82 printf("entering callback\n");
83 return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
84}
85
86int main(int argc, char **argv)
87{
88 struct nfq_handle *h;
89 struct nfq_q_handle *qh;
90 int fd;
91 int rv;
92 uint32_t queue = 0;
93 char buf[4096] __attribute__ ((aligned));
94
95 if (argc == 2) {
96 queue = atoi(argv[1]);
97 if (queue > 65535) {
98 fprintf(stderr, "Usage: %s [<0-65535>]\n", argv[0]);
99 exit(EXIT_FAILURE);
100 }
101 }
102
103 printf("opening library handle\n");
104 h = nfq_open();
105 if (!h) {
106 fprintf(stderr, "error during nfq_open()\n");
107 exit(1);
108 }
109
110 printf("unbinding existing nf_queue handler for AF_INET (if any)\n");
111 if (nfq_unbind_pf(h, AF_INET) < 0) {
112 fprintf(stderr, "error during nfq_unbind_pf()\n");
113 exit(1);
114 }
115
116 printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
117 if (nfq_bind_pf(h, AF_INET) < 0) {
118 fprintf(stderr, "error during nfq_bind_pf()\n");
119 exit(1);
120 }
121
122 printf("binding this socket to queue '%d'\n", queue);
123 qh = nfq_create_queue(h, queue, &cb, NULL);
124 if (!qh) {
125 fprintf(stderr, "error during nfq_create_queue()\n");
126 exit(1);
127 }
128
129 printf("setting copy_packet mode\n");
130 if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
131 fprintf(stderr, "can't set packet_copy mode\n");
132 exit(1);
133 }
134
135 printf("setting flags to request UID and GID\n");
136 if (nfq_set_queue_flags(qh, NFQA_CFG_F_UID_GID, NFQA_CFG_F_UID_GID)) {
137 fprintf(stderr, "This kernel version does not allow to "
138 "retrieve process UID/GID.\n");
139 }
140
141 printf("setting flags to request security context\n");
142 if (nfq_set_queue_flags(qh, NFQA_CFG_F_SECCTX, NFQA_CFG_F_SECCTX)) {
143 fprintf(stderr, "This kernel version does not allow to "
144 "retrieve security context.\n");
145 }
146
147 printf("Waiting for packets...\n");
148
149 fd = nfq_fd(h);
150
151 for (;;) {
152 if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) {
153 printf("pkt received\n");
154 nfq_handle_packet(h, buf, rv);
155 continue;
156 }
157 /* if your application is too slow to digest the packets that
158 * are sent from kernel-space, the socket buffer that we use
159 * to enqueue packets may fill up returning ENOBUFS. Depending
160 * on your application, this error may be ignored. Please, see
161 * the doxygen documentation of this library on how to improve
162 * this situation.
163 */
164 if (rv < 0 && errno == ENOBUFS) {
165 printf("losing packets!\n");
166 continue;
167 }
168 perror("recv failed");
169 break;
170 }
171
172 printf("unbinding from queue 0\n");
174
175#ifdef INSANE
176 /* normally, applications SHOULD NOT issue this command, since
177 * it detaches other programs/sockets from AF_INET, too ! */
178 printf("unbinding from AF_INET\n");
179 nfq_unbind_pf(h, AF_INET);
180#endif
181
182 printf("closing library handle\n");
183 nfq_close(h);
184
185 exit(0);
186}
int nfq_unbind_pf(struct nfq_handle *h, uint16_t pf)
struct nfq_handle * nfq_open(void)
int nfq_bind_pf(struct nfq_handle *h, uint16_t pf)
int nfq_close(struct nfq_handle *h)
int nfq_get_secctx(struct nfq_data *nfad, unsigned char **secdata)
struct nfqnl_msg_packet_hw * nfq_get_packet_hw(struct nfq_data *nfad)
uint32_t nfq_get_physoutdev(struct nfq_data *nfad)
uint32_t nfq_get_physindev(struct nfq_data *nfad)
int nfq_get_gid(struct nfq_data *nfad, uint32_t *gid)
uint32_t nfq_get_nfmark(struct nfq_data *nfad)
struct nfqnl_msg_packet_hdr * nfq_get_msg_packet_hdr(struct nfq_data *nfad)
int nfq_get_uid(struct nfq_data *nfad, uint32_t *uid)
uint32_t nfq_get_outdev(struct nfq_data *nfad)
uint32_t nfq_get_indev(struct nfq_data *nfad)
int nfq_get_payload(struct nfq_data *nfad, unsigned char **data)
int nfq_fd(struct nfq_handle *h)
int nfq_destroy_queue(struct nfq_q_handle *qh)
struct nfq_q_handle * nfq_create_queue(struct nfq_handle *h, uint16_t num, nfq_callback *cb, void *data)
int nfq_set_verdict(struct nfq_q_handle *qh, uint32_t id, uint32_t verdict, uint32_t data_len, const unsigned char *buf)
int nfq_handle_packet(struct nfq_handle *h, char *buf, int len)
int nfq_set_mode(struct nfq_q_handle *qh, uint8_t mode, uint32_t range)
int nfq_set_queue_flags(struct nfq_q_handle *qh, uint32_t mask, uint32_t flags)