]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp
Replace deprecated usleep with POSIX-compliant nanosleep
[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 NF_CAP * cap = static_cast<NF_CAP *>(c);
248 uint8_t buf[BUF_SIZE];
249 int res;
250 struct sockaddr_in sin;
251 socklen_t slen;
252 cap->stoppedUDP = false;
253 while (cap->runningUDP)
254     {
255     if (!WaitPackets(cap->sockUDP))
256         {
257         continue;
258         }
259
260     // Data
261     slen = sizeof(sin);
262     res = recvfrom(cap->sockUDP, buf, BUF_SIZE, 0, reinterpret_cast<struct sockaddr *>(&sin), &slen);
263     if (!cap->runningUDP)
264         break;
265
266     if (res == 0) // EOF
267         {
268         continue;
269         }
270
271     if (res < 24)
272         {
273         if (errno != EINTR)
274             {
275             cap->errorStr = "Invalid data received";
276             printfd(__FILE__, "Error: Invalid data received through UDP\n");
277             }
278         continue;
279         }
280
281     cap->ParseBuffer(buf, res);
282     }
283 cap->stoppedUDP = true;
284 return NULL;
285 }
286
287 void * NF_CAP::RunTCP(void * c)
288 {
289 NF_CAP * cap = static_cast<NF_CAP *>(c);
290 uint8_t buf[BUF_SIZE];
291 int res;
292 int sd;
293 struct sockaddr_in sin;
294 socklen_t slen;
295 cap->stoppedTCP = false;
296 while (cap->runningTCP)
297     {
298     if (!WaitPackets(cap->sockTCP))
299         {
300         continue;
301         }
302
303     // Data
304     slen = sizeof(sin);
305     sd = accept(cap->sockTCP, reinterpret_cast<struct sockaddr *>(&sin), &slen);
306     if (!cap->runningTCP)
307         break;
308
309     if (sd <= 0)
310         {
311         if (errno != EINTR)
312             {
313             cap->errorStr = "Error accepting connection";
314             printfd(__FILE__, "Error: Error accepting connection\n");
315             }
316         continue;
317         }
318
319     if (!WaitPackets(sd))
320         {
321         close(sd);
322         continue;
323         }
324
325     res = recv(sd, buf, BUF_SIZE, MSG_WAITALL);
326     close(sd);
327
328     if (!cap->runningTCP)
329         break;
330
331     if (res == 0) // EOF
332         {
333         continue;
334         }
335
336     // Wrong logic!
337     // Need to check actual data length and wait all data to receive
338     if (res < 24)
339         {
340         if (errno != EINTR)
341             {
342             cap->errorStr = "Invalid data received";
343             printfd(__FILE__, "Error: Invalid data received through TCP\n");
344             }
345         continue;
346         }
347
348     cap->ParseBuffer(buf, res);
349     }
350 cap->stoppedTCP = true;
351 return NULL;
352 }
353
354 void NF_CAP::ParseBuffer(uint8_t * buf, int size)
355 {
356 RAW_PACKET ip;
357 NF_HEADER * hdr = reinterpret_cast<NF_HEADER *>(buf);
358 if (htons(hdr->version) != 5)
359     {
360     return;
361     }
362
363 int packets = htons(hdr->count);
364
365 if (packets < 0 || packets > 30)
366     {
367     return;
368     }
369
370 if (24 + 48 * packets != size)
371     {
372     // See 'wrong logic' upper
373     return;
374     }
375
376 for (int i = 0; i < packets; ++i)
377     {
378     NF_DATA * data = reinterpret_cast<NF_DATA *>(buf + 24 + i * 48);
379
380     ip.rawPacket.header.ipHeader.ip_v = 4;
381     ip.rawPacket.header.ipHeader.ip_hl = 5;
382     ip.rawPacket.header.ipHeader.ip_p = data->proto;
383     ip.dataLen = ntohl(data->octets);
384     ip.rawPacket.header.ipHeader.ip_src.s_addr = data->srcAddr;
385     ip.rawPacket.header.ipHeader.ip_dst.s_addr = data->dstAddr;
386     ip.rawPacket.header.sPort = data->srcPort;
387     ip.rawPacket.header.dPort = data->dstPort;
388
389     traffCnt->Process(ip);
390     }
391 }