-
Notifications
You must be signed in to change notification settings - Fork 0
/
go_nfq.h
155 lines (131 loc) · 3.44 KB
/
go_nfq.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright (C) 2015 Martin Garton <[email protected]>
#ifndef _NETFILTER_H
#define _NETFILTER_H
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/netfilter.h>
#include <linux/socket.h>
#include <linux/types.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
extern uint callback(int id, unsigned char *data, int len, void *nfqp);
static int nf_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfa, void *nfqp)
{
uint32_t id = -1;
struct nfqnl_msg_packet_hdr *ph = NULL;
unsigned char *buffer = NULL;
int ret = 0;
int verdict = 0;
ph = nfq_get_msg_packet_hdr(nfa);
id = ntohl(ph->packet_id);
ret = nfq_get_payload(nfa, &buffer);
verdict = callback(id, buffer, ret, nfqp);
return nfq_set_verdict(qh, id, verdict, 0, NULL);
}
struct go_nfq_params {
struct nfq_handle *h;
struct nfq_q_handle *qh;
u_int16_t queue;
void *nfqp;
u_int32_t maxInQueue;
u_int packetSize;
int fd;
int closePipefd[2];
};
static inline int go_nfq_init(struct go_nfq_params *params, u_int16_t queue,
void *nfqp, u_int32_t maxInQueue,
u_int packetSize)
{
params->h = nfq_open();
if (!params->h) {
fprintf(stderr, "error during nfq_open()\n");
return -1;
}
if (nfq_unbind_pf(params->h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_unbind_pf()\n");
return -1;
}
if (nfq_bind_pf(params->h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_bind_pf()\n");
return -1;
}
params->qh = nfq_create_queue(params->h, queue, &nf_callback, nfqp);
if (!params->qh) {
perror("error during nfq_create_queue()\n");
nfq_close(params->h);
return -1;
}
if (nfq_set_queue_maxlen(params->qh, maxInQueue) < 0) {
fprintf(stderr, "error during nfq_set_queue_maxlen()\n");
nfq_destroy_queue(params->qh);
nfq_close(params->h);
return -1;
}
if (nfq_set_mode(params->qh, NFQNL_COPY_PACKET, packetSize) < 0) {
fprintf(stderr, "error during nfq_set_mode()\n");
nfq_destroy_queue(params->qh);
nfq_close(params->h);
return -1;
}
params->fd = nfq_fd(params->h);
if (params->fd <= 0) {
fprintf(stderr, "error during nfq_fd()\n");
nfq_destroy_queue(params->qh);
nfq_close(params->h);
return -1;
}
if (pipe(params->closePipefd) == -1) {
perror("pipe");
nfq_destroy_queue(params->qh);
nfq_close(params->h);
return -1;
}
return 0;
}
static inline void go_nfq_run(struct go_nfq_params *params)
{
char buf[4096] __attribute__ ((aligned));
int rv;
int maxfd = params->fd;
if (maxfd < params->closePipefd[0]) {
maxfd = params->closePipefd[0];
}
while (1) {
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(params->fd, &fdset);
FD_SET(params->closePipefd[0], &fdset);
int selected = select(maxfd + 1, &fdset, NULL, NULL, NULL);
if (selected <= 0) {
perror("select failed, returning");
return;
}
if (FD_ISSET(params->closePipefd[0], &fdset)) {
nfq_destroy_queue(params->qh);
nfq_close(params->h);
return;
} else if (FD_ISSET(params->fd, &fdset)) {
rv = recv(params->fd, buf, sizeof(buf), 0);
if (rv == 0) {
perror("read failed, exiting read loop");
return;
}
nfq_handle_packet(params->h, buf, rv);
} else {
fprintf(stderr,
"unexpected fd: %d is not %d or %d. exiting read loop\n",
selected, params->fd, params->closePipefd[0]);
return;
}
}
}
static inline void go_nfq_stop(struct go_nfq_params *params)
{
close(params->closePipefd[1]);
}
#endif