]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/capture/nfqueue/nfqueue.cpp
Implemented NFQ capturing.
[stg.git] / projects / stargazer / plugins / capture / nfqueue / nfqueue.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 "nfqueue.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 extern "C" {
29
30 #include <linux/netfilter.h>  /* Defines verdicts (NF_ACCEPT, etc) */
31 #include <libnetfilter_queue/libnetfilter_queue.h>
32
33 }
34
35 #include <arpa/inet.h> // ntohl
36 #include <signal.h>
37
38 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
41 namespace
42 {
43
44 PLUGIN_CREATOR<NFQ_CAP> ncc;
45
46 int callback(struct nfq_q_handle * /*queueHandle*/, struct nfgenmsg * /*msg*/,
47              struct nfq_data * nfqData, void *data)
48 {
49 int id = 0;
50
51 struct nfqnl_msg_packet_hdr * packetHeader = nfq_get_msg_packet_hdr(nfqData);
52 if (packetHeader == NULL)
53     return 0;
54
55 id = ntohl(packetHeader->packet_id);
56
57 unsigned char * payload = NULL;
58
59 if (nfq_get_payload(nfqData) < 0)
60     return id;
61
62 RAW_PACKET packet;
63
64 memcpy(&packet.rawPacket, payload, sizeof(ip.rawPacket));
65
66 NFQ_CAP * cap = static_cast<NFQ_CAP *>(data);
67
68 cap->Process(packet);
69
70 return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
71 }
72
73 }
74
75 extern "C" PLUGIN * GetPlugin();
76 //-----------------------------------------------------------------------------
77 //-----------------------------------------------------------------------------
78 //-----------------------------------------------------------------------------
79 PLUGIN * GetPlugin()
80 {
81 return ncc.GetPlugin();
82 }
83 //-----------------------------------------------------------------------------
84 //-----------------------------------------------------------------------------
85 //-----------------------------------------------------------------------------
86 std::string NFQ_CAP::GetVersion() const
87 {
88 return "cap_nfqueue v.1.0";
89 }
90 //-----------------------------------------------------------------------------
91 NFQ_CAP::NFQ_CAP()
92     : errorStr(),
93       thread(),
94       nonstop(false),
95       isRunning(false),
96       traffCnt(NULL),
97       logger(GetPluginLogger(GetStgLogger(), "cap_nfqueue"))
98 {
99 }
100 //-----------------------------------------------------------------------------
101 int NFQ_CAP::ParseSettings()
102 {
103 return 0;
104 }
105 //-----------------------------------------------------------------------------
106 int NFQ_CAP::Start()
107 {
108 if (isRunning)
109     return 0;
110
111 nfqHandle = nfq_open();
112 if (nfqHandle == NULL)
113     {
114     errorStr = "Failed to initialize netfilter queue.";
115     logger(errorStr);
116     return -1;
117     }
118
119 if (nfq_unbind_pf(nfqHandle, AF_INET) < 0)
120     {
121     errorStr = "Failed to unbind netfilter queue from IP handling.";
122     logger(errorStr);
123     return -1;
124     }
125
126 if (nfq_bind_pf(nfqHandle, AF_INET) < 0)
127     {
128     errorStr = "Failed to bind netfilter queue to IP handling.";
129     logger(errorStr);
130     return -1;
131     }
132
133 queueHandle = nfq_create_queue(nfqHandle, queueNumber, &Callback, this);
134 if (queueHandle == NULL)
135     {
136     errorStr = "Failed to create queue " + x2str(queueNumber) + ".";
137     logger(errorStr);
138     return -1;
139     }
140
141 if (nfq_set_mode(queueHandle, NFQNL_COPY_PACKET, 0xffFF) < 0)
142     {
143     errorStr = "Failed to set queue " + x2str(queueNumber) + " mode.";
144     logger(errorStr);
145     return -1;
146     }
147
148 nonstop = true;
149
150 if (pthread_create(&thread, NULL, Run, this))
151     {
152     errorStr = "Cannot create thread.";
153     logger("Cannot create thread.");
154     printfd(__FILE__, "Cannot create thread\n");
155     return -1;
156     }
157
158 return 0;
159 }
160 //-----------------------------------------------------------------------------
161 int NFQ_CAP::Stop()
162 {
163 if (!isRunning)
164     return 0;
165
166 nonstop = false;
167
168 //5 seconds to thread stops itself
169 for (int i = 0; i < 25 && isRunning; i++)
170     {
171     struct timespec ts = {0, 200000000};
172     nanosleep(&ts, NULL);
173     }
174 //after 5 seconds waiting thread still running. now killing it
175 if (isRunning)
176     {
177     if (pthread_kill(thread, SIGUSR1))
178         {
179         errorStr = "Cannot kill thread.";
180         logger("Cannot send signal to thread.");
181         return -1;
182         }
183     for (int i = 0; i < 25 && isRunning; ++i)
184         {
185         struct timespec ts = {0, 200000000};
186         nanosleep(&ts, NULL);
187         }
188     if (isRunning)
189         {
190         errorStr = "NFQ_CAP not stopped.";
191         logger("Cannot stop thread.");
192         printfd(__FILE__, "Cannot stop thread\n");
193         return -1;
194         }
195     }
196
197 pthread_join(thread, NULL);
198
199 nfq_destroy_queue(queueHandle);
200 nfq_close(nfqHandle);
201
202 return 0;
203 }
204 //-----------------------------------------------------------------------------
205 void * NFQ_CAP::Run(void * d)
206 {
207 sigset_t signalSet;
208 sigfillset(&signalSet);
209 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
210
211 NFQ_CAP * dc = static_cast<NFQ_CAP *>(d);
212 dc->isRunning = true;
213
214 int fd = nfq_fd(nfqHandle);
215 char buf[4096];
216
217 while (dc->nonstop)
218     {
219         if (!WaitPackets(fd))
220             continue;
221
222         int rv = read(fd, buf, sizeof(buf), 0);
223         if (rv < 0)
224             {
225             errorStr = "Read error: " + strerror(errno);
226             logger(errorStr);
227             break;
228             }
229         nfq_handle_packet(nfqHandle, buf, rv);
230     }
231
232 dc->isRunning = false;
233 return NULL;
234 }