-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathnfq_wrapper.cpp
165 lines (131 loc) · 4 KB
/
nfq_wrapper.cpp
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
156
157
158
159
160
161
162
163
164
165
#include <stdexcept>
#include <iostream>
#include <string.h>
#include <arpa/inet.h>
#include <assert.h>
#include "nfq_wrapper.hpp"
nfq_wrapper::nfq_wrapper(
const unsigned int p_queue_index,
cb_t p_cb,
const address_family_t p_family
):
m_buffer(0xffff + (MNL_SOCKET_BUFFER_SIZE/2)),
m_socket(mnl_socket_open(NETLINK_NETFILTER), &mnl_socket_close),
m_queue_index(p_queue_index),
m_cb(p_cb)
{
if (m_socket == NULL) {
throw std::runtime_error("mnl_socket_open() failed");
}
if (mnl_socket_bind(m_socket.get(), 0, MNL_SOCKET_AUTOPID) < 0) {
throw std::runtime_error("mnl_socket_bind() failed");
}
struct nlmsghdr *l_header = nfq_nlmsg_put(
m_buffer.data(),
NFQNL_MSG_CONFIG,
p_queue_index
);
if (l_header == NULL) {
throw std::runtime_error("nfq_nlmsg_put() failed");
}
nfq_nlmsg_cfg_put_cmd(
l_header,
static_cast<uint16_t>(p_family),
NFQNL_CFG_CMD_BIND
);
if (mnl_socket_sendto(m_socket.get(), l_header, l_header->nlmsg_len) < 0) {
throw std::runtime_error("mnl_socket_sendto() failed");
}
l_header = nfq_nlmsg_put(m_buffer.data(), NFQNL_MSG_CONFIG, p_queue_index);
if (l_header == NULL) {
throw std::runtime_error("nfq_nlmsg_put() failed");
}
nfq_nlmsg_cfg_put_params(l_header, NFQNL_COPY_PACKET, 0xffff);
mnl_attr_put_u32(l_header, NFQA_CFG_FLAGS, htonl(NFQA_CFG_F_GSO));
mnl_attr_put_u32(l_header, NFQA_CFG_MASK, htonl(NFQA_CFG_F_GSO));
if (mnl_socket_sendto(m_socket.get(), l_header, l_header->nlmsg_len) < 0) {
throw std::runtime_error("mnl_socket_sendto() failed");
}
m_port_id = mnl_socket_get_portid(m_socket.get());
}
nfq_wrapper::~nfq_wrapper() {}
int
nfq_wrapper::get_fd()
{
return mnl_socket_get_fd(m_socket.get());
}
int
nfq_wrapper::queue_cb_proxy(
const struct nlmsghdr *const p_header,
void *const p_context
) {
nfq_wrapper *const l_self = static_cast<nfq_wrapper *>(p_context);
assert(l_self != NULL);
struct nlattr *l_attributes[NFQA_MAX + 1] = {};
if (nfq_nlmsg_parse(p_header, l_attributes) < 0) {
return MNL_CB_ERROR;
}
struct nfqnl_msg_packet_hdr *const l_packet_header =
static_cast<struct nfqnl_msg_packet_hdr *>(
mnl_attr_get_payload(l_attributes[NFQA_PACKET_HDR])
);
const std::span<const std::byte> l_payload(
static_cast<std::byte *>(
mnl_attr_get_payload(l_attributes[NFQA_PAYLOAD])
),
mnl_attr_get_payload_len(
l_attributes[NFQA_PAYLOAD]
)
);
l_self->m_cb(l_self, ntohl(l_packet_header->packet_id), l_payload);
return 0;
}
void
nfq_wrapper::step()
{
const int l_status = mnl_socket_recvfrom(
m_socket.get(),
m_buffer.data(),
m_buffer.size()
);
if (l_status < 0) {
if (errno == ENOBUFS) {
return;
} else {
throw std::runtime_error(
"mnl_socket_recvfrom() " + std::string(strerror(errno))
);
}
}
const int l_status2 = mnl_cb_run(
m_buffer.data(),
l_status,
0,
m_port_id,
&nfq_wrapper::queue_cb_proxy,
this
);
if (l_status2 < 0) {
throw std::runtime_error(
"mnl_cb_run() " + std::string(strerror(errno))
);
}
}
void
nfq_wrapper::send_verdict(const uint32_t p_id, const nfq_verdict_t p_verdict)
{
char l_buffer[MNL_SOCKET_BUFFER_SIZE];
std::lock_guard<std::mutex> l_guard(m_send_lock);
struct nlmsghdr *const l_header = nfq_nlmsg_put(
l_buffer,
NFQNL_MSG_VERDICT,
m_queue_index
);
if (l_header == NULL) {
throw std::runtime_error("nfq_nlmsg_put()");
}
nfq_nlmsg_verdict_put(l_header, p_id, static_cast<int>(p_verdict));
if (mnl_socket_sendto(m_socket.get(), l_header, l_header->nlmsg_len) < 0) {
throw std::runtime_error("mnl_socket_sendto() failed");
}
}