]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/capture/divert_freebsd/divert_cap.cpp
Complete replacement notifiers with subscriptions.
[stg.git] / projects / stargazer / plugins / capture / divert_freebsd / divert_cap.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 : Boris Mikhailenko <stg34@stg.dp.ua>
19 */
20
21 /*
22 $Revision: 1.13 $
23 $Date: 2010/09/10 06:43:03 $
24 */
25
26 #include "divert_cap.h"
27
28 #include "stg/traffcounter.h"
29 #include "stg/raw_ip_packet.h"
30 #include "stg/common.h"
31
32 #include <algorithm>
33 #include <vector>
34
35 #include <cstdio>
36 #include <cstring>
37 #include <cerrno>
38 #include <cstdlib>
39 #include <csignal>
40
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44
45 #include <sys/uio.h>
46 #include <sys/time.h>
47 #include <sys/ioctl.h>
48 #include <sys/poll.h>
49
50 #include <fcntl.h>
51 #include <unistd.h>
52
53 #define BUFF_LEN (16384) /* max mtu -> lo=16436  TODO why?*/
54
55 //-----------------------------------------------------------------------------
56 struct DIVERT_DATA {
57 int sock;
58 short int port;
59 char iface[10];
60 };
61 //-----------------------------------------------------------------------------
62 pollfd pollddiv;
63 DIVERT_DATA cddiv;  //capture data
64 //-----------------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
67
68 extern "C" STG::Plugin* GetPlugin()
69 {
70     static DIVERT_CAP plugin;
71     return &plugin;
72 }
73 //-----------------------------------------------------------------------------
74 //-----------------------------------------------------------------------------
75 //-----------------------------------------------------------------------------
76 std::string DIVERT_CAP::GetVersion() const
77 {
78 return "cap_divert v.1.0";
79 }
80 //-----------------------------------------------------------------------------
81 DIVERT_CAP::DIVERT_CAP()
82     : port(0),
83       disableForwarding(false),
84       nonstop(false),
85       isRunning(false),
86       traffCnt(NULL),
87       logger(STG::PluginLogger::get("cap_divert"))
88 {
89 }
90 //-----------------------------------------------------------------------------
91 int DIVERT_CAP::Start()
92 {
93 if (isRunning)
94     return 0;
95
96 if (DivertCapOpen() < 0)
97     {
98     errorStr = "Cannot open socket!";
99     printfd(__FILE__, "Cannot open socket\n");
100     return -1;
101     }
102
103 nonstop = true;
104
105 if (pthread_create(&thread, NULL, Run, this))
106     {
107     errorStr = "Cannot create thread.";
108     logger("Cannot create thread.");
109     printfd(__FILE__, "Cannot create thread\n");
110     return -1;
111     }
112
113 return 0;
114 }
115 //-----------------------------------------------------------------------------
116 int DIVERT_CAP::Stop()
117 {
118 if (!isRunning)
119     return 0;
120
121 DivertCapClose();
122
123 nonstop = false;
124
125 //5 seconds to thread stops itself
126 int i;
127 for (i = 0; i < 25; i++)
128     {
129     if (!isRunning)
130         break;
131
132     struct timespec ts = {0, 200000000};
133     nanosleep(&ts, NULL);
134     }
135
136 //after 5 seconds waiting thread still running. now killing it
137 if (isRunning)
138     {
139     if (pthread_kill(thread, SIGINT))
140         {
141         errorStr = "Cannot kill thread.";
142         logger("Cannot send signal to thread.");
143         printfd(__FILE__, "Cannot kill thread\n");
144         return -1;
145         }
146     }
147
148 return 0;
149 }
150 //-----------------------------------------------------------------------------
151 void * DIVERT_CAP::Run(void * d)
152 {
153 sigset_t signalSet;
154 sigfillset(&signalSet);
155 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
156
157 DIVERT_CAP * dc = static_cast<DIVERT_CAP *>(d);
158 dc->isRunning = true;
159
160 char buffer[STG::packetSize + 14];
161 while (dc->nonstop)
162     {
163     STG::RawPacket rp;
164     dc->DivertCapRead(buffer, sizeof(buffer), NULL);
165
166     if (buffer[12] != 0x8)
167         continue;
168
169     memcpy(&rp.rawPacket, &buffer[14], STG::packetSize);
170
171     dc->traffCnt->process(rp);
172     }
173
174 dc->isRunning = false;
175 return NULL;
176 }
177 //-----------------------------------------------------------------------------
178 int DIVERT_CAP::DivertCapOpen()
179 {
180 memset(&pollddiv, 0, sizeof(pollddiv));
181 memset(&cddiv, 0, sizeof(DIVERT_DATA));
182
183 strcpy(cddiv.iface, "foo");
184 cddiv.port = port;
185
186 DivertCapOpen(0);
187 pollddiv.events = POLLIN;
188 pollddiv.fd = cddiv.sock;
189
190 return 0;
191 }
192 //-----------------------------------------------------------------------------
193 int DIVERT_CAP::DivertCapOpen(int)
194 {
195 int ret;
196 cddiv.sock = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
197 if (cddiv.sock < 0)
198     {
199     errorStr = "Create divert socket error.";
200     logger("Cannot create a socket: %s", strerror(errno));
201     printfd(__FILE__, "Cannot create divert socket\n");
202     return -1;
203     }
204
205 struct sockaddr_in divAddr;
206
207 memset(&divAddr, 0, sizeof(divAddr));
208
209 divAddr.sin_family = AF_INET;
210 divAddr.sin_port = htons(cddiv.port);
211 divAddr.sin_addr.s_addr = INADDR_ANY;
212
213 ret = bind(cddiv.sock, (struct sockaddr *)&divAddr, sizeof(divAddr));
214
215 if (ret < 0)
216     {
217     errorStr = "Bind divert socket error.";
218     logger("Cannot bind the scoket: %s", strerror(errno));
219     printfd(__FILE__, "Cannot bind divert socket\n");
220     return -1;
221     }
222
223 return cddiv.sock;
224 }
225 //-----------------------------------------------------------------------------
226 int DIVERT_CAP::DivertCapRead(char * b, int blen, char ** iface)
227 {
228 poll(&pollddiv, 1, -1);
229
230 if (pollddiv.revents & POLLIN)
231     {
232     DivertCapRead(b, blen, iface, 0);
233     pollddiv.revents = 0;
234     return 0;
235     }
236
237 return 0;
238 }
239 //-----------------------------------------------------------------------------
240 int DIVERT_CAP::DivertCapRead(char * b, int blen, char ** iface, int)
241 {
242 static char buf[BUFF_LEN];
243 static struct sockaddr_in divertaddr;
244 static int bytes;
245 static socklen_t divertaddrSize = sizeof(divertaddr);
246
247 if ((bytes = recvfrom (cddiv.sock, buf, BUFF_LEN,
248                        0, (struct sockaddr*) &divertaddr, &divertaddrSize)) > 50)
249     {
250     memcpy(b + 14, buf, blen - 14);
251     b[12] = 0x8;
252
253     if (iface)
254         *iface = cddiv.iface;
255
256     if (!disableForwarding)
257         {
258         if (sendto(cddiv.sock, buf, bytes, 0, (struct sockaddr*)&divertaddr, divertaddrSize) < 0)
259             logger("sendto error: %s", strerror(errno));
260         }
261     }
262 else
263     {
264     if (bytes < 0)
265         logger("recvfrom error: %s", strerror(errno));
266     }
267
268 return 0;
269 }
270 //-----------------------------------------------------------------------------
271 int DIVERT_CAP::DivertCapClose()
272 {
273 close(cddiv.sock);
274 return 0;
275 }
276 //-----------------------------------------------------------------------------
277 int DIVERT_CAP::ParseSettings()
278 {
279 int p;
280 STG::ParamValue pv;
281 std::vector<STG::ParamValue>::const_iterator pvi;
282
283 pv.param = "Port";
284 pvi = std::find(settings.moduleParams.begin(), settings.moduleParams.end(), pv);
285 if (pvi == settings.moduleParams.end() || pvi->value.empty())
286     {
287     p = 15701;
288     }
289 else if (ParseIntInRange(pvi->value[0], 1, 65535, &p))
290     {
291     errorStr = "Cannot parse parameter \'Port\': " + errorStr;
292     printfd(__FILE__, "Cannot parse parameter 'Port'\n");
293     return -1;
294     }
295
296 port = p;
297
298 bool d = false;
299 pv.param = "DisableForwarding";
300 pvi = std::find(settings.moduleParams.begin(), settings.moduleParams.end(), pv);
301 if (pvi == settings.moduleParams.end() || pvi->value.empty())
302     {
303     disableForwarding = false;
304     }
305 else if (ParseYesNo(pvi->value[0], &d))
306     {
307     errorStr = "Cannot parse parameter \'DisableForwarding\': " + errorStr;
308     printfd(__FILE__, "Cannot parse parameter 'DisableForwarding'\n");
309     return -1;
310     }
311
312 disableForwarding = d;
313
314 return 0;
315 }
316 //-----------------------------------------------------------------------------