DTS Application Library  0.2.3
Application library containing referenced objects and interfaces to common libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
nf_queue.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 2012 Gregory Nietsky <gregory@distrotetch.co.za>
3  http://www.distrotech.co.za
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 as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
25 #include "config.h"
26 
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <sys/ioctl.h>
35 #include <netinet/in.h>
36 #include <linux/types.h>
37 #include <linux/netfilter.h>
38 #include <libnetfilter_queue/libnetfilter_queue.h>
39 
40 #include "include/dtsapp.h"
41 #include "include/private.h"
42 
44  NFQUEUE_DONE = 1 << 0
45 };
46 
47 struct nfq_struct {
48  struct nfq_handle *h;
49  uint16_t pf;
50  int fd;
51  int flags;
52 };
53 
54 struct nfq_queue {
55  struct nfq_struct *nfq;
56  struct nfq_q_handle *qh;
58  void *data;
59  uint16_t num;
60 };
61 
62 static struct nfq_list {
63  struct bucket_list *queues;
64 } *nfqueues = NULL;
65 
66 static int32_t nfqueue_hash(const void *data, int key) {
67  const struct nfq_struct *nfq = data;
68  const uint16_t *hashkey = (key) ? data : &nfq->pf;
69 
70  return (*hashkey);
71 }
72 
73 static void nfqueues_close(void *data) {
74 
75  if (nfqueues->queues) {
76  objunref(nfqueues->queues);
77  }
78  nfqueues = NULL;
79 }
80 
81 static void nfqueue_close(void *data) {
82  struct nfq_struct *nfq = data;
83 
84  nfq_unbind_pf(nfq->h, nfq->pf);
85  nfq_close(nfq->h);
86  objunref(nfqueues);
87 }
88 
89 static void nfqueue_close_q(void *data) {
90  struct nfq_queue *nfq_q = data;
91 
92  if (nfq_q->qh) {
93  nfq_destroy_queue(nfq_q->qh);
94  }
95 
96  /*im here in the list and running thread*/
97  objlock(nfqueues);
98  if (objcnt(nfq_q->nfq) <= 3) {
99  setflag(nfq_q->nfq, NFQUEUE_DONE);
100  remove_bucket_item(nfqueues->queues, nfq_q->nfq);
101  }
102  objunlock(nfqueues);
103  objunref(nfq_q->nfq);
104 }
105 
106 static void *nfqueue_thread(void *data) {
107  struct nfq_struct *nfq = data;
108  fd_set rd_set, act_set;
109  struct timeval tv;
110  int len, selfd;
111  char buf[4096];
112  int opt = 1;
113 
114  FD_ZERO(&rd_set);
115  FD_SET(nfq->fd, &rd_set);
116  fcntl(nfq->fd, F_SETFD, O_NONBLOCK);
117  ioctl(nfq->fd, FIONBIO, &opt);
118 
119  while (!testflag(nfq, NFQUEUE_DONE) && framework_threadok()) {
120  act_set = rd_set;
121  tv.tv_sec = 0;
122  tv.tv_usec = 20000;
123 
124  selfd = select(nfq->fd + 1, &act_set, NULL, NULL, &tv);
125 
126  /*returned due to interupt continue or timed out*/
127  if ((selfd < 0 && errno == EINTR) || (!selfd)) {
128  continue;
129  } else
130  if (selfd < 0) {
131  break;
132  }
133 
134  if ((FD_ISSET(nfq->fd, &act_set)) &&
135  ((len = recv(nfq->fd, buf, sizeof(buf), 0)) >= 0)) {
136  objlock(nfq);
137  nfq_handle_packet(nfq->h, buf, len);
138  objunlock(nfq);
139  }
140  }
141 
142  return (NULL);
143 }
144 
145 static struct nfq_struct *nfqueue_init(uint16_t pf) {
146  struct nfq_struct *nfq;
147 
148  if (!(nfq = objalloc(sizeof(*nfq), nfqueue_close))) {
149  return (NULL);
150  }
151  nfq->pf = pf;
152 
153  if (!(nfq->h = nfq_open())) {
154  objunref(nfq);
155  return (NULL);
156  }
157 
158  if (nfq_unbind_pf(nfq->h, pf)) {
159  objunref(nfq);
160  return (NULL);
161  }
162 
163  if (nfq_bind_pf(nfq->h, pf)) {
164  objunref(nfq);
165  return (NULL);
166  }
167 
168  if ((nfq->fd = nfq_fd(nfq->h)) < 0) {
169  objunref(nfq);
170  return (NULL);
171  }
172 
173  if (nfqueues) {
174  objref(nfqueues);
175  } else
176  if (!(nfqueues = objalloc(sizeof(*nfqueues), nfqueues_close))) {
177  objunref(nfq);
178  return (NULL);
179  }
180 
181  objlock(nfqueues);
182  if ((nfqueues->queues || (nfqueues->queues = create_bucketlist(0, nfqueue_hash))) &&
183  !addtobucket(nfqueues->queues, nfq)) {
184  objunref(nfqueues);
185  objunref(nfq);
186  return (NULL);
187  }
188  objunlock(nfqueues);
189 
190  framework_mkthread(nfqueue_thread, NULL, NULL, nfq, 0);
191 
192  return (nfq);
193 }
194 
195 static int nfqueue_callback(struct nfq_q_handle *qh, struct nfgenmsg *msg, struct nfq_data *nfad, void *data) {
196  struct nfq_queue *nfq_q = data;
197  unsigned char *pkt;
198  struct nfqnl_msg_packet_hdr *ph;
199  void *mangle = NULL;
200  uint32_t ret, mark;
201  uint32_t id = 0;
202  uint32_t len = 0;
203  uint32_t verdict = NF_DROP;
204 
205  if ((ph = nfq_get_msg_packet_hdr(nfad))) {
206  id = ntohl(ph->packet_id);
207  }
208  mark = nfq_get_nfmark(nfad);
209 
210  if ((len = nfq_get_payload(nfad, &pkt)) <= 0) {
211  pkt = NULL;
212  }
213 
214  if (nfq_q->cb) {
215  verdict = nfq_q->cb(nfad, ph, (char *)pkt, len, nfq_q->data, &mark, &mangle);
216  }
217 
218  if (mangle && !(len = objsize(mangle))) {
219  objunref(mangle);
220  mangle = NULL;
221  }
222 
223  ret = nfq_set_verdict2(qh, id, verdict, mark, len, (mangle) ? mangle : pkt);
224  if (mangle) {
225  objunref(mangle);
226  }
227 
228  return (ret);
229 }
230 
231 extern struct nfq_queue *nfqueue_attach(uint16_t pf, uint16_t num, uint8_t mode, uint32_t range, nfqueue_cb cb, void *data) {
232  struct nfq_queue *nfq_q;
233 
234  if (!(nfq_q = objalloc(sizeof(*nfq_q), nfqueue_close_q))) {
235  return (NULL);
236  }
237 
238  objlock(nfqueues);
239  if (!(nfqueues && (nfq_q->nfq = bucket_list_find_key(nfqueues->queues, &pf))) &&
240  !(nfq_q->nfq || (nfq_q->nfq = nfqueue_init(pf)))) {
241  objunlock(nfqueues);
242  objunref(nfq_q);
243  return (NULL);
244  }
245  objunlock(nfqueues);
246 
247  if (!(nfq_q->qh = nfq_create_queue(nfq_q->nfq->h, num, &nfqueue_callback, nfq_q))) {
248  objunref(nfq_q);
249  return (NULL);
250  }
251 
252  if (cb) {
253  nfq_q->cb = cb;
254  }
255 
256  if (data) {
257  nfq_q->data = data;
258  }
259 
260  nfq_set_mode(nfq_q->qh, mode, range);
261 
262  return (nfq_q);
263 }
264 
265 extern uint16_t snprintf_pkt(struct nfq_data *tb, struct nfqnl_msg_packet_hdr *ph, uint8_t *pkt, char *buff, uint16_t len) {
266  struct iphdr *ip = (struct iphdr *)pkt;
267  char *tmp = buff;
268  uint32_t id, mark, ifi;
269  uint16_t tlen, left = len;
270  char saddr[INET_ADDRSTRLEN], daddr[INET_ADDRSTRLEN];
271 
272  if (ph) {
273  id = ntohl(ph->packet_id);
274  snprintf(tmp, left, "hw_protocol=0x%04x hook=%u id=%u ",
275  ntohs(ph->hw_protocol), ph->hook, id);
276  tlen = strlen(tmp);
277  tmp += tlen;
278  left -= tlen;
279  }
280 
281  if ((mark = nfq_get_nfmark(tb))) {
282  snprintf(tmp, left, "mark=%u ", mark);
283  tlen = strlen(tmp);
284  tmp += tlen;
285  left -= tlen;
286  }
287 
288  if ((ifi = nfq_get_indev(tb))) {
289  snprintf(tmp, left, "indev=%u ", ifi);
290  tlen = strlen(tmp);
291  tmp += tlen;
292  left -= tlen;
293  }
294 
295  if ((ifi = nfq_get_outdev(tb))) {
296  snprintf(tmp, left, "outdev=%u ", ifi);
297  tlen = strlen(tmp);
298  tmp += tlen;
299  left -= tlen;
300  }
301 
302  if (pkt && (ip->version == 4)) {
303  union l4hdr *l4 = (union l4hdr *)(pkt + (ip->ihl*4));
304 
305  inet_ntop(AF_INET, &ip->saddr, saddr, INET_ADDRSTRLEN);
306  inet_ntop(AF_INET, &ip->daddr, daddr, INET_ADDRSTRLEN);
307 
308  snprintf(tmp, left, "src=%s dst=%s proto=%i ", saddr, daddr, ip->protocol);
309  tlen = strlen(tmp);
310  tmp += tlen;
311  left -= tlen;
312 
313  switch(ip->protocol) {
314  case IPPROTO_TCP:
315  snprintf(tmp, left, "sport=%i dport=%i ", ntohs(l4->tcp.source), ntohs(l4->tcp.dest));
316  break;
317  case IPPROTO_UDP:
318  snprintf(tmp, left, "sport=%i dport=%i ", ntohs(l4->udp.source), ntohs(l4->udp.dest));
319  break;
320  case IPPROTO_ICMP:
321  snprintf(tmp, left, "type=%i code=%i id=%i ", l4->icmp.type, l4->icmp.code, ntohs(l4->icmp.un.echo.id));
322  break;
323  }
324  tlen = strlen(tmp);
325  tmp += tlen;
326  left -= tlen;
327  }
328 
329  return (len - left);
330 }
331 
void * data
Definition: nf_queue.c:58
void * create_bucketlist(int bitmask, blisthash hash_function)
Definition: refobj.c:356
struct nfq_struct * nfq
Definition: nf_queue.c:55
int objref(void *data)
Reference a object.
Definition: refobj.c:153
#define testflag(obj, flag)
Atomically test a flag in the flags field of a referenced object.
Definition: dtsapp.h:932
int objlock(void *data)
Lock the reference.
Definition: refobj.c:269
uint32_t(* nfqueue_cb)(struct nfq_data *, struct nfqnl_msg_packet_hdr *, char *, uint32_t, void *, uint32_t *, void **)
Definition: dtsapp.h:300
void * objalloc(int size, objdestroy)
Allocate a referenced lockable object.
Definition: refobj.c:129
struct nfq_handle * h
Definition: nf_queue.c:48
struct nfq_data nfq_data
Forward decleration of structure.
Definition: dtsapp.h:201
#define setflag(obj, flag)
Atomically set a flag in the flags field of a referenced object.
Definition: dtsapp.h:925
int objcnt(void *data)
Return current reference count.
Definition: refobj.c:222
int fd
Definition: nf_queue.c:50
DTS Application library API Include file.
uint16_t snprintf_pkt(struct nfq_data *tb, struct nfqnl_msg_packet_hdr *ph, uint8_t *pkt, char *buff, uint16_t len)
Definition: nf_queue.c:265
struct thread_pvt * framework_mkthread(threadfunc, threadcleanup, threadsighandler, void *data, int flags)
create a thread result must be unreferenced
Definition: thread.c:387
NF_QUEUE_FLAGS
Definition: nf_queue.c:43
struct nfqnl_msg_packet_hdr nfqnl_msg_packet_hdr
Forward decleration of structure.
Definition: dtsapp.h:209
int objunlock(void *data)
Unlock a reference.
Definition: refobj.c:301
int framework_threadok(void)
let threads check there status.
Definition: thread.c:143
int flags
Definition: nf_queue.c:51
int objsize(void *data)
Size requested for data.
Definition: refobj.c:246
const char * inet_ntop(int af, const void *src, char *dest, socklen_t size)
Win32 implementation of inet_ntop.
Definition: winiface.cpp:43
uint16_t pf
Definition: nf_queue.c:49
int addtobucket(struct bucket_list *blist, void *data)
Add a reference to the bucketlist.
Definition: refobj.c:428
void * bucket_list_find_key(struct bucket_list *list, const void *key)
Find and return a reference to a item matching supplied key.
Definition: refobj.c:572
void remove_bucket_item(struct bucket_list *blist, void *data)
Remove and unreference a item from the list.
Definition: refobj.c:517
int objunref(void *data)
Drop reference held.
Definition: refobj.c:184
nfqueue_cb cb
Definition: nf_queue.c:57
struct nfq_q_handle * qh
Definition: nf_queue.c:56
uint16_t num
Definition: nf_queue.c:59
Bucket list, hold hashed objects in buckets.
Definition: refobj.c:75
struct nfq_queue * nfqueue_attach(uint16_t pf, uint16_t num, uint8_t mode, uint32_t range, nfqueue_cb cb, void *data)
Definition: nf_queue.c:231