]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp
Merge branch 'master' into full-month-stats
[stg.git] / projects / stargazer / plugins / capture / cap_nf / cap_nf.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 Date: 16.05.2008
19 */
20
21 /*
22 * Author : Maxim Mamontov <faust@stg.dp.ua>
23 */
24
25 /*
26 $Revision: 1.11 $
27 $Date: 2010/09/10 06:41:06 $
28 $Author: faust $
29 */
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <unistd.h>
35
36 #include <csignal>
37 #include <cerrno>
38 #include <cstring>
39
40 #include <vector>
41
42 #include "stg/common.h" 
43 #include "stg/raw_ip_packet.h"
44 #include "stg/traffcounter.h"
45 #include "stg/plugin_creator.h"
46 #include "cap_nf.h"
47
48 PLUGIN_CREATOR<NF_CAP> cnc;
49
50 PLUGIN * GetPlugin()
51 {
52 return cnc.GetPlugin();
53 }
54
55 NF_CAP::NF_CAP()
56     : traffCnt(NULL),
57       settings(),
58       tidTCP(),
59       tidUDP(),
60       runningTCP(false),
61       runningUDP(false),
62       stoppedTCP(true),
63       stoppedUDP(true),
64       portT(0),
65       portU(0),
66       sockTCP(-1),
67       sockUDP(-1),
68       errorStr()
69 {
70 }
71
72 NF_CAP::~NF_CAP()
73 {
74 }
75
76 int NF_CAP::ParseSettings()
77 {
78 std::vector<PARAM_VALUE>::iterator it;
79 for (it = settings.moduleParams.begin(); it != settings.moduleParams.end(); ++it)
80     {
81     if (it->param == "TCPPort")
82         {
83         if (str2x(it->value[0], portT))
84             {
85             errorStr = "Invalid TCPPort value";
86             printfd(__FILE__, "Error: Invalid TCPPort value\n");
87             return -1;
88             }
89         continue;
90         }
91     if (it->param == "UDPPort")
92         {
93         if (str2x(it->value[0], portU))
94             {
95             errorStr = "Invalid UDPPort value";
96             printfd(__FILE__, "Error: Invalid UDPPort value\n");
97             return -1;
98             }
99         continue;
100         }
101     printfd(__FILE__, "'%s' is not a valid module param\n", it->param.c_str());
102     }
103 return 0;
104 }
105
106 int NF_CAP::Start()
107 {
108 if (portU > 0)
109     {
110     if (OpenUDP())
111         {
112         return -1;
113         }
114     runningUDP = true;
115     if (pthread_create(&tidUDP, NULL, RunUDP, this))
116         {
117         runningUDP = false;
118         CloseUDP();
119         errorStr = "Cannot create UDP thread";
120         printfd(__FILE__, "Error: Cannot create UDP thread\n");
121         return -1;
122         }
123     }
124 if (portT > 0)
125     {
126     if (OpenTCP())
127         {
128         return -1;
129         }
130     runningTCP = true;
131     if (pthread_create(&tidTCP, NULL, RunTCP, this))
132         {
133         runningTCP = false;
134         CloseTCP();
135         errorStr = "Cannot create TCP thread";
136         printfd(__FILE__, "Error: Cannot create TCP thread\n");
137         return -1;
138         }
139     }
140 return 0;
141 }
142
143 int NF_CAP::Stop()
144 {
145 runningTCP = runningUDP = false;
146 if (portU && !stoppedUDP)
147     {
148     CloseUDP();
149     for (int i = 0; i < 25 && !stoppedUDP; ++i)
150         {
151         struct timespec ts = {0, 200000000};
152         nanosleep(&ts, NULL);
153         }
154     if (stoppedUDP)
155         {
156         pthread_join(tidUDP, NULL);
157         }
158     else
159         {
160         if (pthread_kill(tidUDP, SIGUSR1))
161             {
162             errorStr = "Error sending signal to UDP thread";
163             printfd(__FILE__, "Error: Error sending signal to UDP thread\n");
164             return -1;
165             }
166         printfd(__FILE__, "UDP thread NOT stopped\n");
167         }
168     }
169 if (portT && !stoppedTCP)
170     {
171     CloseTCP();
172     for (int i = 0; i < 25 && !stoppedTCP; ++i)
173         {
174         struct timespec ts = {0, 200000000};
175         nanosleep(&ts, NULL);
176         }
177     if (stoppedTCP)
178         {
179         pthread_join(tidTCP, NULL);
180         }
181     else
182         {
183         if (pthread_kill(tidTCP, SIGUSR1))
184             {
185             errorStr = "Error sending signal to TCP thread";
186             printfd(__FILE__, "Error: Error sending signal to TCP thread\n");
187             return -1;
188             }
189         printfd(__FILE__, "TCP thread NOT stopped\n");
190         }
191     }
192 return 0;
193 }
194
195 bool NF_CAP::OpenUDP()
196 {
197 struct sockaddr_in sin;
198 sockUDP = socket(PF_INET, SOCK_DGRAM, 0);
199 if (sockUDP <= 0)
200     {
201     errorStr = "Error opening UDP socket";
202     printfd(__FILE__, "Error: Error opening UDP socket\n");
203     return true;
204     }
205 sin.sin_family = AF_INET;
206 sin.sin_port = htons(portU);
207 sin.sin_addr.s_addr = inet_addr("0.0.0.0");
208 if (bind(sockUDP, (struct sockaddr *)&sin, sizeof(sin)))
209     {
210     errorStr = "Error binding UDP socket";
211     printfd(__FILE__, "Error: Error binding UDP socket\n");
212     return true;
213     }
214 return false;
215 }
216
217 bool NF_CAP::OpenTCP()
218 {
219 struct sockaddr_in sin;
220 sockTCP = socket(PF_INET, SOCK_STREAM, 0);
221 if (sockTCP <= 0)
222     {
223     errorStr = "Error opening TCP socket";
224     printfd(__FILE__, "Error: Error opening TCP socket\n");
225     return true;
226     }
227 sin.sin_family = AF_INET;
228 sin.sin_port = htons(portT);
229 sin.sin_addr.s_addr = inet_addr("0.0.0.0");
230 if (bind(sockTCP, (struct sockaddr *)&sin, sizeof(sin)))
231     {
232     errorStr = "Error binding TCP socket";
233     printfd(__FILE__, "Error: Error binding TCP socket\n");
234     return true;
235     }
236 if (listen(sockTCP, 1))
237     {
238     errorStr = "Error listening on TCP socket";
239     printfd(__FILE__, "Error: Error listening TCP socket\n");
240     return true;
241     }
242 return false;
243 }
244
245 void * NF_CAP::RunUDP(void * c)
246 {
247 sigset_t signalSet;
248 sigfillset(&signalSet);
249 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
250
251 NF_CAP * cap = static_cast<NF_CAP *>(c);
252 uint8_t buf[BUF_SIZE];
253 int res;
254 struct sockaddr_in sin;
255 socklen_t slen;
256 cap->stoppedUDP = false;
257 while (cap->runningUDP)
258     {
259     if (!WaitPackets(cap->sockUDP))
260         {
261         continue;
262         }
263
264     // Data
265     slen = sizeof(sin);
266     res = recvfrom(cap->sockUDP, buf, BUF_SIZE, 0, reinterpret_cast<struct sockaddr *>(&sin), &slen);
267     if (!cap->runningUDP)
268         break;
269
270     if (res == 0) // EOF
271         {
272         continue;
273         }
274
275     if (res < 24)
276         {
277         if (errno != EINTR)
278             {
279             cap->errorStr = "Invalid data received";
280             printfd(__FILE__, "Error: Invalid data received through UDP\n");
281             }
282         continue;
283         }
284
285     cap->ParseBuffer(buf, res);
286     }
287 cap->stoppedUDP = true;
288 return NULL;
289 }
290
291 void * NF_CAP::RunTCP(void * c)
292 {
293 sigset_t signalSet;
294 sigfillset(&signalSet);
295 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
296
297 NF_CAP * cap = static_cast<NF_CAP *>(c);
298 uint8_t buf[BUF_SIZE];
299 int res;
300 int sd;
301 struct sockaddr_in sin;
302 socklen_t slen;
303 cap->stoppedTCP = false;
304 while (cap->runningTCP)
305     {
306     if (!WaitPackets(cap->sockTCP))
307         {
308         continue;
309         }
310
311     // Data
312     slen = sizeof(sin);
313     sd = accept(cap->sockTCP, reinterpret_cast<struct sockaddr *>(&sin), &slen);
314     if (!cap->runningTCP)
315         break;
316
317     if (sd <= 0)
318         {
319         if (errno != EINTR)
320             {
321             cap->errorStr = "Error accepting connection";
322             printfd(__FILE__, "Error: Error accepting connection\n");
323             }
324         continue;
325         }
326
327     if (!WaitPackets(sd))
328         {
329         close(sd);
330         continue;
331         }
332
333     res = recv(sd, buf, BUF_SIZE, MSG_WAITALL);
334     close(sd);
335
336     if (!cap->runningTCP)
337         break;
338
339     if (res == 0) // EOF
340         {
341         continue;
342         }
343
344     // Wrong logic!
345     // Need to check actual data length and wait all data to receive
346     if (res < 24)
347         {
348         if (errno != EINTR)
349             {
350             cap->errorStr = "Invalid data received";
351             printfd(__FILE__, "Error: Invalid data received through TCP\n");
352             }
353         continue;
354         }
355
356     cap->ParseBuffer(buf, res);
357     }
358 cap->stoppedTCP = true;
359 return NULL;
360 }
361
362 void NF_CAP::ParseBuffer(uint8_t * buf, int size)
363 {
364 RAW_PACKET ip;
365 NF_HEADER * hdr = reinterpret_cast<NF_HEADER *>(buf);
366 if (htons(hdr->version) != 5)
367     {
368     return;
369     }
370
371 int packets = htons(hdr->count);
372
373 if (packets < 0 || packets > 30)
374     {
375     return;
376     }
377
378 if (24 + 48 * packets != size)
379     {
380     // See 'wrong logic' upper
381     return;
382     }
383
384 for (int i = 0; i < packets; ++i)
385     {
386     NF_DATA * data = reinterpret_cast<NF_DATA *>(buf + 24 + i * 48);
387
388     ip.rawPacket.header.ipHeader.ip_v = 4;
389     ip.rawPacket.header.ipHeader.ip_hl = 5;
390     ip.rawPacket.header.ipHeader.ip_p = data->proto;
391     ip.dataLen = ntohl(data->octets);
392     ip.rawPacket.header.ipHeader.ip_src.s_addr = data->srcAddr;
393     ip.rawPacket.header.ipHeader.ip_dst.s_addr = data->dstAddr;
394     ip.rawPacket.header.sPort = data->srcPort;
395     ip.rawPacket.header.dPort = data->dstPort;
396
397     traffCnt->Process(ip);
398     }
399 }