]> git.stg.codes - stg.git/blob - stargazer/plugins/capture/nfqueue/nfqueue.cpp
3c79c1b1c2f0376f5c771ff3278cbf7d1e069a0d
[stg.git] / stargazer / plugins / capture / nfqueue / nfqueue.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18 * Author : Maxim Mamontov <faust@stargazer.dp.ua>
19 */
20
21 #include "nfqueue.h"
22
23 #include "stg/traffcounter.h"
24 #include "stg/common.h"
25 #include "stg/raw_ip_packet.h"
26
27 extern "C" {
28
29 #include <linux/netfilter.h>  /* Defines verdicts (NF_ACCEPT, etc) */
30 #include <libnetfilter_queue/libnetfilter_queue.h>
31
32 }
33
34 #include <cerrno>
35 #include <csignal>
36
37 #include <arpa/inet.h> // ntohl
38
39 #include <unistd.h> // read
40
41 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
43 //-----------------------------------------------------------------------------
44 namespace
45 {
46
47 int Callback(struct nfq_q_handle * queueHandle, struct nfgenmsg * /*msg*/,
48              struct nfq_data * nfqData, void *data)
49 {
50 int id = 0;
51
52 struct nfqnl_msg_packet_hdr * packetHeader = nfq_get_msg_packet_hdr(nfqData);
53 if (packetHeader == NULL)
54     return 0;
55
56 id = ntohl(packetHeader->packet_id);
57
58 unsigned char * payload = NULL;
59
60 if (nfq_get_payload(nfqData, &payload) < 0 || payload == NULL)
61     return id;
62
63 STG::RawPacket packet;
64
65 memcpy(&packet.rawPacket, payload, sizeof(packet.rawPacket));
66
67 NFQ_CAP * cap = static_cast<NFQ_CAP *>(data);
68
69 cap->Process(packet);
70
71 return nfq_set_verdict(queueHandle, id, NF_ACCEPT, 0, NULL);
72 }
73
74 }
75
76 extern "C" STG::Plugin* GetPlugin()
77 {
78     static NFQ_CAP plugin;
79     return &plugin;
80 }
81 //-----------------------------------------------------------------------------
82 //-----------------------------------------------------------------------------
83 //-----------------------------------------------------------------------------
84 std::string NFQ_CAP::GetVersion() const
85 {
86 return "cap_nfqueue v.1.0";
87 }
88 //-----------------------------------------------------------------------------
89 NFQ_CAP::NFQ_CAP()
90     : nonstop(false),
91       isRunning(false),
92       queueNumber(0),
93       nfqHandle(NULL),
94       queueHandle(NULL),
95       traffCnt(NULL),
96       logger(STG::PluginLogger::get("cap_nfqueue"))
97 {
98 }
99 //-----------------------------------------------------------------------------
100 int NFQ_CAP::ParseSettings()
101 {
102 for (size_t i = 0; i < settings.moduleParams.size(); i++)
103     if (settings.moduleParams[i].param == "queueNumber" && !settings.moduleParams[i].value.empty())
104         if (str2x(settings.moduleParams[i].value[0], queueNumber) < 0)
105             {
106             errorStr = "Queue number should be a number. Got: '" + settings.moduleParams[i].param + "'";
107             logger(errorStr);
108             return -1;
109             }
110 return 0;
111 }
112 //-----------------------------------------------------------------------------
113 int NFQ_CAP::Start()
114 {
115 if (isRunning)
116     return 0;
117
118 nfqHandle = nfq_open();
119 if (nfqHandle == NULL)
120     {
121     errorStr = "Failed to initialize netfilter queue.";
122     logger(errorStr);
123     return -1;
124     }
125
126 if (nfq_unbind_pf(nfqHandle, AF_INET) < 0)
127     {
128     errorStr = "Failed to unbind netfilter queue from IP handling.";
129     logger(errorStr);
130     return -1;
131     }
132
133 if (nfq_bind_pf(nfqHandle, AF_INET) < 0)
134     {
135     errorStr = "Failed to bind netfilter queue to IP handling.";
136     logger(errorStr);
137     return -1;
138     }
139
140 queueHandle = nfq_create_queue(nfqHandle, queueNumber, &Callback, this);
141 if (queueHandle == NULL)
142     {
143     errorStr = "Failed to create queue " + std::to_string(queueNumber) + ".";
144     logger(errorStr);
145     return -1;
146     }
147
148 if (nfq_set_mode(queueHandle, NFQNL_COPY_PACKET, 0xffFF) < 0)
149     {
150     errorStr = "Failed to set queue " + std::to_string(queueNumber) + " mode.";
151     logger(errorStr);
152     return -1;
153     }
154
155 nonstop = true;
156
157 if (pthread_create(&thread, NULL, Run, this))
158     {
159     errorStr = "Cannot create thread.";
160     logger("Cannot create thread.");
161     printfd(__FILE__, "Cannot create thread\n");
162     return -1;
163     }
164
165 return 0;
166 }
167 //-----------------------------------------------------------------------------
168 int NFQ_CAP::Stop()
169 {
170 if (!isRunning)
171     return 0;
172
173 nonstop = false;
174
175 //5 seconds to thread stops itself
176 for (int i = 0; i < 25 && isRunning; i++)
177     {
178     struct timespec ts = {0, 200000000};
179     nanosleep(&ts, NULL);
180     }
181 //after 5 seconds waiting thread still running. now killing it
182 if (isRunning)
183     {
184     if (pthread_kill(thread, SIGUSR1))
185         {
186         errorStr = "Cannot kill thread.";
187         logger("Cannot send signal to thread.");
188         return -1;
189         }
190     for (int i = 0; i < 25 && isRunning; ++i)
191         {
192         struct timespec ts = {0, 200000000};
193         nanosleep(&ts, NULL);
194         }
195     if (isRunning)
196         {
197         errorStr = "NFQ_CAP not stopped.";
198         logger("Cannot stop thread.");
199         printfd(__FILE__, "Cannot stop thread\n");
200         return -1;
201         }
202     }
203
204 pthread_join(thread, NULL);
205
206 nfq_destroy_queue(queueHandle);
207 nfq_close(nfqHandle);
208
209 return 0;
210 }
211 //-----------------------------------------------------------------------------
212 void * NFQ_CAP::Run(void * d)
213 {
214 sigset_t signalSet;
215 sigfillset(&signalSet);
216 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
217
218 NFQ_CAP * dc = static_cast<NFQ_CAP *>(d);
219 dc->isRunning = true;
220
221 int fd = nfq_fd(dc->nfqHandle);
222 char buf[4096];
223
224 while (dc->nonstop)
225     {
226         if (!WaitPackets(fd))
227             continue;
228
229         int rv = read(fd, buf, sizeof(buf));
230         if (rv < 0)
231             {
232             dc->errorStr = std::string("Read error: ") + strerror(errno);
233             dc->logger(dc->errorStr);
234             break;
235             }
236         nfq_handle_packet(dc->nfqHandle, buf, rv);
237     }
238
239 dc->isRunning = false;
240 return NULL;
241 }
242 //-----------------------------------------------------------------------------
243 void NFQ_CAP::Process(const STG::RawPacket & packet)
244 {
245 traffCnt->process(packet);
246 }