]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/capture/pcap/pcap_cap.cpp
Initial adding of PCap capturer.
[stg.git] / projects / stargazer / plugins / capture / pcap / pcap_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 : Maxim Mamontov <faust@stargazer.dp.ua>
19 */
20
21 #include "pcap_cap.h"
22
23 #include "stg/traffcounter.h"
24 #include "stg/plugin_creator.h"
25 #include "stg/common.h"
26 #include "stg/raw_ip_packet.h"
27
28 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
31 namespace
32 {
33 PLUGIN_CREATOR<PCAP_CAP> pcc;
34
35 const size_t SNAP_LEN 1518;
36 }
37
38 extern "C" PLUGIN * GetPlugin();
39 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
41 //-----------------------------------------------------------------------------
42 PLUGIN * GetPlugin()
43 {
44 return pcc.GetPlugin();
45 }
46 //-----------------------------------------------------------------------------
47 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
49 std::string PCAP_CAP::GetVersion() const
50 {
51 return "pcap_cap v.1.0";
52 }
53 //-----------------------------------------------------------------------------
54 PCAP_CAP::PCAP_CAP()
55     : errorStr(),
56       thread(),
57       nonstop(false),
58       isRunning(false),
59       handle(NULL),
60       traffCnt(NULL),
61       logger(GetPluginLogger(GetStgLogger(), "cap_pcap"))
62 {
63 }
64 //-----------------------------------------------------------------------------
65 int PCAP_CAP::Start()
66 {
67 if (isRunning)
68     return 0;
69
70 DEV_MAP::const_iterator it(devices.begin());
71 while (it != devices.end())
72     {
73     bpf_u_int32 mask;
74     bpf_u_int32 net;
75     char errbuf[PCAP_ERRBUF_SIZE];
76
77     /* get network number and mask associated with capture device */
78     if (pcap_lookupnet(it->device.c_str(), &net, &mask, errbuf) == -1)
79         {
80         errorStr = "Couldn't get netmask for device " + it->device + ": " + errbuf;
81         logger(errorStr);
82         printfd(__FILE__, "%s\n", errorStr.c_str());
83         return -1;
84         }
85
86     /* open capture device */
87     it->handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
88     if (it->handle == NULL)
89         {
90         errorStr = "Couldn't open device " + it->device + ": " + errbuf;
91         logger(errorStr);
92         printfd(__FILE__, "%s\n", errorStr.c_str());
93         return -1;
94         }
95
96     if (pcap_setnonblock(it->handle, true, errbuf) == -1)
97         {
98         errorStr = "Couldn't put device " + it->device + " into non-blocking mode: " + errbuf;
99         logger(errorStr);
100         printfd(__FILE__, "%s\n", errorStr.c_str());
101         return -1;
102         }
103
104     /* make sure we're capturing on an Ethernet device [2] */
105     if (pcap_datalink(it->handle) != DLT_EN10MB)
106         {
107         errorStr = it->device + " is not an Ethernet";
108         logger(errorStr);
109         printfd(__FILE__, "%s\n", errorStr.c_str());
110         return -1;
111         }
112
113     /* compile the filter expression */
114     if (pcap_compile(it->handle, &it->filter, it->filterExpression.c_str(), 0, net) == -1)
115         {
116         errorStr = "Couldn't parse filter " + it->filterExpression + ": " + pcap_geterr(it->handle);
117         logger(errorStr);
118         printfd(__FILE__, "%s\n", errorStr.c_str());
119         return -1;
120         }
121
122     /* apply the compiled filter */
123     if (pcap_setfilter(it->handle, &it->filter) == -1)
124         {
125         errorStr = "Couldn't install filter " + it->filterExpression + ": " + pcap_geterr(it->handle);
126         logger(errorStr);
127         printfd(__FILE__, "%s\n", errorStr.c_str());
128         return -1;
129         }
130
131     it->fd = pcap_get_selectable_fd(it->handle);
132     if (it->fd == -1)
133         {
134         {
135         errorStr = "Couldn't get a file descriptor for " + it->device + ": " + pcap_geterr(it->handle);
136         logger(errorStr);
137         printfd(__FILE__, "%s\n", errorStr.c_str());
138         return -1;
139         }
140         }
141     }
142
143 nonstop = true;
144
145 if (pthread_create(&thread, NULL, Run, this))
146     {
147     errorStr = "Cannot create thread.";
148     logger("Cannot create thread.");
149     printfd(__FILE__, "Cannot create thread\n");
150     return -1;
151     }
152
153 return 0;
154 }
155 //-----------------------------------------------------------------------------
156 int PCAP_CAP::Stop()
157 {
158 if (!isRunning)
159     return 0;
160
161 nonstop = false;
162
163 //5 seconds to thread stops itself
164 for (int i = 0; i < 25 && isRunning; i++)
165     {
166     struct timespec ts = {0, 200000000};
167     nanosleep(&ts, NULL);
168     }
169 //after 5 seconds waiting thread still running. now killing it
170 if (isRunning)
171     {
172     if (pthread_kill(thread, SIGUSR1))
173         {
174         errorStr = "Cannot kill thread.";
175         logger("Cannot send signal to thread.");
176         return -1;
177         }
178     for (int i = 0; i < 25 && isRunning; ++i)
179         {
180         struct timespec ts = {0, 200000000};
181         nanosleep(&ts, NULL);
182         }
183     if (isRunning)
184         {
185         errorStr = "PCAP_CAP not stopped.";
186         logger("Cannot stop thread.");
187         printfd(__FILE__, "Cannot stop thread\n");
188         return -1;
189         }
190     else
191         {
192         pthread_join(thread, NULL);
193         }
194     }
195
196 return 0;
197 }
198 //-----------------------------------------------------------------------------
199 void * PCAP_CAP::Run(void * d)
200 {
201 sigset_t signalSet;
202 sigfillset(&signalSet);
203 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
204
205 PCAP_CAP * dc = static_cast<PCAP_CAP *>(d);
206 dc->isRunning = true;
207
208 struct ETH_IP
209 {
210 uint16_t    ethHdr[8];
211 RAW_PACKET  rp;
212 char        padding[4];
213 char        padding1[8];
214 };
215
216 char ethip[sizeof(ETH_IP)];
217
218 memset(&ethip, 0, sizeof(ETH_IP));
219
220 ETH_IP * ethIP = static_cast<ETH_IP *>(static_cast<void *>(&ethip));
221 ethIP->rp.dataLen = -1;
222
223 char * iface = NULL;
224
225 while (dc->nonstop)
226     {
227
228     if (ethIP->ethHdr[7] != 0x8)
229         continue;
230
231     dc->traffCnt->Process(ethIP->rp);
232     }
233
234 dc->isRunning = false;
235 return NULL;
236 }