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