abstract 'nfattr' in 'nfnl_q_data'
[platform/upstream/libnetfilter_queue.git] / src / libnetfilter_queue.c
1 /* libnfqnetlink.c: generic library for access to nf_queue
2  *
3  * (C) 2005 by Harald Welte <laforge@gnumonks.org>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License version 2 
7  *  as published by the Free Software Foundation
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <time.h>
25 #include <errno.h>
26 #include <netinet/in.h>
27 #include <sys/socket.h>
28
29 #include <libnfnetlink/libnfnetlink.h>
30 #include <libnetfilter_queue/libnetfilter_queue.h>
31
32 struct nfqnl_handle
33 {
34         struct nfnl_handle nfnlh;
35         struct nfqnl_q_handle *qh_list;
36 };
37
38 struct nfqnl_q_handle
39 {
40         struct nfqnl_q_handle *next;
41         struct nfqnl_handle *h;
42         u_int16_t id;
43
44         nfqnl_callback *cb;
45         void *data;
46 };
47
48 struct nfnl_q_data {
49         struct nfattr **data;
50 };
51
52 int nfqnl_errno;
53
54 /***********************************************************************
55  * low level stuff 
56  ***********************************************************************/
57
58 static void del_qh(struct nfqnl_q_handle *qh)
59 {
60         struct nfqnl_q_handle *cur_qh, *prev_qh = NULL;
61
62         for (cur_qh = qh->h->qh_list; cur_qh; cur_qh = cur_qh->next) {
63                 if (cur_qh == qh) {
64                         if (prev_qh)
65                                 prev_qh->next = qh->next;
66                         else
67                                 qh->h->qh_list = qh->next;
68                         return;
69                 }
70                 prev_qh = cur_qh;
71         }
72 }
73
74 static void add_qh(struct nfqnl_q_handle *qh)
75 {
76         qh->next = qh->h->qh_list;
77         qh->h->qh_list = qh;
78 }
79
80 static struct nfqnl_q_handle *find_qh(struct nfqnl_handle *h, u_int16_t id)
81 {
82         struct nfqnl_q_handle *qh;
83
84         for (qh = h->qh_list; qh; qh = qh->next) {
85                 if (qh->id == id)
86                         return qh;
87         }
88         return NULL;
89 }
90
91 /* build a NFQNL_MSG_CONFIG message */
92         static int
93 __build_send_cfg_msg(struct nfqnl_handle *h, u_int8_t command,
94                 u_int16_t queuenum, u_int16_t pf)
95 {
96         char buf[NFNL_HEADER_LEN
97                 +NFA_LENGTH(sizeof(struct nfqnl_msg_config_cmd))];
98         struct nfqnl_msg_config_cmd cmd;
99         struct nlmsghdr *nmh = (struct nlmsghdr *) buf;
100
101         nfnl_fill_hdr(&h->nfnlh, nmh, 0, AF_UNSPEC, queuenum,
102                         NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
103
104         cmd.command = command;
105         cmd.pf = htons(pf);
106         nfnl_addattr_l(nmh, sizeof(buf), NFQA_CFG_CMD, &cmd, sizeof(cmd));
107
108         return nfnl_talk(&h->nfnlh, nmh, 0, 0, NULL, NULL, NULL);
109 }
110
111 static int __nfqnl_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[],
112                 void *data)
113 {
114         struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
115         struct nfqnl_handle *h = data;
116         u_int16_t queue_num = ntohs(nfmsg->res_id);
117         struct nfqnl_q_handle *qh = find_qh(h, queue_num);
118         struct nfnl_q_data nfqa;
119
120         if (!qh)
121                 return -ENODEV;
122
123         if (!qh->cb)
124                 return -ENODEV;
125
126         nfqa.data = nfa;
127
128         return qh->cb(qh, nfmsg, &nfqa, qh->data);
129 }
130
131 static struct nfnl_callback pkt_cb = {
132         .call           = &__nfqnl_rcv_pkt,
133         .attr_count     = NFQA_MAX,
134 };
135
136 /* public interface */
137
138 struct nfnl_handle *nfqnl_nfnlh(struct nfqnl_handle *h)
139 {
140         return &h->nfnlh;
141 }
142
143 int nfqnl_fd(struct nfqnl_handle *h)
144 {
145         return nfnl_fd(nfqnl_nfnlh(h));
146 }
147
148 struct nfqnl_handle *nfqnl_open(void)
149 {
150         struct nfqnl_handle *h;
151         int err;
152
153         h = malloc(sizeof(*h));
154         if (!h)
155                 return NULL;
156
157         memset(h, 0, sizeof(*h));
158
159         err = nfnl_open(&h->nfnlh, NFNL_SUBSYS_QUEUE, NFQNL_MSG_MAX, 0);
160         if (err < 0) {
161                 nfqnl_errno = err;
162                 goto out_free;
163         }
164
165         pkt_cb.data = h;
166         err = nfnl_callback_register(&h->nfnlh, NFQNL_MSG_PACKET, &pkt_cb);
167         if (err < 0) {
168                 nfqnl_errno = err;
169                 goto out_close;
170         }
171
172         return h;
173 out_close:
174         nfnl_close(&h->nfnlh);
175 out_free:
176         free(h);
177         return NULL;
178 }
179
180 int nfqnl_close(struct nfqnl_handle *h)
181 {
182         int ret = nfnl_close(&h->nfnlh);
183         if (ret == 0)
184                 free(h);
185         return ret;
186 }
187
188 /* bind nf_queue from a specific protocol family */
189 int nfqnl_bind_pf(struct nfqnl_handle *h, u_int16_t pf)
190 {
191         return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_BIND, 0, pf);
192 }
193
194 /* unbind nf_queue from a specific protocol family */
195 int nfqnl_unbind_pf(struct nfqnl_handle *h, u_int16_t pf)
196 {
197         return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_UNBIND, 0, pf);
198 }
199
200 /* bind this socket to a specific queue number */
201 struct nfqnl_q_handle *nfqnl_create_queue(struct nfqnl_handle *h, 
202                 u_int16_t num,
203                 nfqnl_callback *cb,
204                 void *data)
205 {
206         int ret;
207         struct nfqnl_q_handle *qh;
208
209         if (find_qh(h, num))
210                 return NULL;
211
212         qh = malloc(sizeof(*qh));
213
214         memset(qh, 0, sizeof(*qh));
215         qh->h = h;
216         qh->id = num;
217         qh->cb = cb;
218         qh->data = data;
219
220         ret = __build_send_cfg_msg(h, NFQNL_CFG_CMD_BIND, num, 0);
221         if (ret < 0) {
222                 nfqnl_errno = ret;
223                 free(qh);
224                 return NULL;
225         }
226
227         add_qh(qh);
228         return qh;
229 }
230
231 /* unbind this socket from a specific queue number */
232 int nfqnl_destroy_queue(struct nfqnl_q_handle *qh)
233 {
234         int ret = __build_send_cfg_msg(qh->h, NFQNL_CFG_CMD_UNBIND, qh->id, 0);
235         if (ret == 0) {
236                 del_qh(qh);
237                 free(qh);
238         }
239
240         return ret;
241 }
242
243 int nfqnl_handle_packet(struct nfqnl_handle *h, char *buf, int len)
244 {
245         return nfnl_handle_packet(&h->nfnlh, buf, len);
246 }
247
248 int nfqnl_set_mode(struct nfqnl_q_handle *qh,
249                 u_int8_t mode, u_int32_t range)
250 {
251         char buf[NFNL_HEADER_LEN
252                 +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))];
253         struct nfqnl_msg_config_params params;
254         struct nlmsghdr *nmh = (struct nlmsghdr *) buf;
255
256         nfnl_fill_hdr(&qh->h->nfnlh, nmh, 0, AF_UNSPEC, qh->id,
257                         NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
258
259         params.copy_range = htonl(range);
260         params.copy_mode = mode;
261         nfnl_addattr_l(nmh, sizeof(buf), NFQA_CFG_PARAMS, &params,
262                         sizeof(params));
263
264         return nfnl_talk(&qh->h->nfnlh, nmh, 0, 0, NULL, NULL, NULL);
265 }
266
267 static int __set_verdict(struct nfqnl_q_handle *qh, u_int32_t id,
268                 u_int32_t verdict, u_int32_t mark, int set_mark,
269                 u_int32_t data_len, unsigned char *data)
270 {
271         struct nfqnl_msg_verdict_hdr vh;
272         char buf[NFNL_HEADER_LEN
273                 +NFA_LENGTH(sizeof(mark))
274                 +NFA_LENGTH(sizeof(vh))];
275         struct nlmsghdr *nmh = (struct nlmsghdr *) buf;
276
277         struct iovec iov[3];
278         int nvecs;
279
280         memset(iov, 0, sizeof(iov));
281
282         vh.verdict = htonl(verdict);
283         vh.id = htonl(id);
284
285         nfnl_fill_hdr(&qh->h->nfnlh, nmh, 0, AF_UNSPEC, qh->id,
286                         NFQNL_MSG_VERDICT, NLM_F_REQUEST);
287
288         /* add verdict header */
289         nfnl_addattr_l(nmh, sizeof(buf), NFQA_VERDICT_HDR, &vh, sizeof(vh));
290
291         if (set_mark)
292                 nfnl_addattr32(nmh, sizeof(buf), NFQA_MARK, mark);
293
294         iov[0].iov_base = nmh;
295         iov[0].iov_len = NLMSG_TAIL(nmh) - (void *)nmh;
296         nvecs = 1;
297
298         if (data_len) {
299                 struct nfattr data_attr;
300
301                 nfnl_build_nfa_iovec(&iov[1], &data_attr, NFQA_PAYLOAD,
302                                 data_len, data);
303                 nvecs += 2;
304         }
305
306         return nfnl_sendiov(&qh->h->nfnlh, iov, nvecs, 0);
307 }
308
309 int nfqnl_set_verdict(struct nfqnl_q_handle *qh, u_int32_t id,
310                 u_int32_t verdict, u_int32_t data_len, 
311                 unsigned char *buf)
312 {
313         return __set_verdict(qh, id, verdict, 0, 0, data_len, buf);
314 }       
315
316 int nfqnl_set_verdict_mark(struct nfqnl_q_handle *qh, u_int32_t id,
317                 u_int32_t verdict, u_int32_t mark,
318                 u_int32_t datalen, unsigned char *buf)
319 {
320         return __set_verdict(qh, id, verdict, mark, 1, datalen, buf);
321 }
322
323 /*************************************************************
324  * Message parsing functions 
325  *************************************************************/
326
327 struct nfqnl_msg_packet_hdr *nfqnl_get_msg_packet_hdr(struct nfnl_q_data *nfad)
328 {
329         return nfnl_get_pointer_to_data(nfad->data, NFQA_PACKET_HDR,
330                                         struct nfqnl_msg_packet_hdr);
331 }
332
333 uint32_t nfqnl_get_nfmark(struct nfnl_q_data *nfad)
334 {
335         return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, u_int32_t));
336 }
337
338 struct nfqnl_msg_packet_timestamp *nfqnl_get_timestamp(struct nfnl_q_data *nfad)
339 {
340         return nfnl_get_pointer_to_data(nfad->data, NFQA_TIMESTAMP,
341                                         struct nfqnl_msg_packet_timestamp);
342 }
343
344 /* all nfqnl_get_*dev() functions return 0 if not set, since linux only allows
345  * ifindex >= 1, see net/core/dev.c:2600  (in 2.6.13.1) */
346 u_int32_t nfqnl_get_indev(struct nfnl_q_data *nfad)
347 {
348         return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_INDEV, u_int32_t));
349 }
350
351 u_int32_t nfqnl_get_physindev(struct nfnl_q_data *nfad)
352 {
353         return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSINDEV, u_int32_t));
354 }
355
356 u_int32_t nfqnl_get_outdev(struct nfnl_q_data *nfad)
357 {
358         return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_OUTDEV, u_int32_t));
359 }
360
361 u_int32_t nfqnl_get_physoutdev(struct nfnl_q_data *nfad)
362 {
363         return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSOUTDEV, u_int32_t));
364 }
365
366 struct nfqnl_msg_packet_hw *nfqnl_get_packet_hw(struct nfnl_q_data *nfad)
367 {
368         return nfnl_get_pointer_to_data(nfad->data, NFQA_HWADDR,
369                                         struct nfqnl_msg_packet_hw);
370 }
371
372 int nfqnl_get_payload(struct nfnl_q_data *nfad, char **data,
373                       unsigned int *datalen)
374 {
375         *data = nfnl_get_pointer_to_data(nfad->data, NFQA_PAYLOAD, char);
376         if (*data) {
377                 *datalen = NFA_PAYLOAD(nfad->data[NFQA_PAYLOAD-1]);
378                 return 1;
379         }
380         return 0;
381 }