-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathjcapture.c
238 lines (212 loc) · 6.61 KB
/
jcapture.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
* jnettop, network online traffic visualiser
* Copyright (C) 2002-2005 Jakub Skopal
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Header$
*
*/
#include "jbase.h"
#include "jcapture.h"
/*
* This stuff was copied out of Ethereal package by Gerald Combs <[email protected]>
* The point is, that we can use select() on platforms, where packet socket is
* select()able. This prevents the capturer from taking all the processor time
* doing g_tread_yeald() all the time.
* Currently, this should happen only on BSD systems
*/
#if !defined(BSD)
# define USE_SELECT
#endif
const jbase_device *jcapture_ActiveDevice;
const char *jcapture_ActiveBpfFilterText;
GQueue *jcapture_PacketQueue;
GMutex *jcapture_PacketQueueMutex;
GCond *jcapture_PacketQueueCond;
volatile gboolean jcapture_IsRunning;
struct bpf_program activeBpfFilterProgram;
gboolean onoffPromisc;
GThread *snifferThread;
GTrashStack *freePacketStack = NULL;
int freePacketStackSize = 0;
GMutex *freePacketStackMutex;
gboolean isEnding;
gboolean jcapture_Setup() {
jcapture_ActiveDevice = NULL;
jcapture_PacketQueue = g_queue_new();
jcapture_PacketQueueCond = g_cond_new();
jcapture_PacketQueueMutex = g_mutex_new();
freePacketStackMutex = g_mutex_new();
return TRUE;
}
void jcapture_SetPromisc(gboolean value) {
onoffPromisc = value;
}
gboolean jcapture_SetDevice(const jbase_device *device) {
if (jcapture_IsRunning) {
debug(LOG_ERR, "Attempt to set jcapture device while jcapture is running");
return FALSE;
}
jcapture_ActiveDevice = device;
return TRUE;
}
gboolean jcapture_SetBpfFilterText(const char *filterText) {
if (jcapture_IsRunning) {
debug(LOG_ERR, "Attempt to set jcapture filter while jcapture is running");
return FALSE;
}
jcapture_ActiveBpfFilterText = filterText;
return TRUE;
}
jbase_packet *jbase_packet_Alloc() {
jbase_packet *ptr;
g_mutex_lock(freePacketStackMutex);
ptr = (jbase_packet *)g_trash_stack_pop(&freePacketStack);
if (ptr) {
freePacketStackSize --;
}
g_mutex_unlock(freePacketStackMutex);
if (!ptr) {
ptr = g_new(jbase_packet, 1);
}
return ptr;
}
void jcapture_packet_Free(jbase_packet *packet) {
g_mutex_lock(freePacketStackMutex);
if (freePacketStackSize < FREEPACKETSTACK_PEEK) {
g_trash_stack_push(&freePacketStack, packet);
freePacketStackSize ++;
packet = NULL;
}
g_mutex_unlock(freePacketStackMutex);
if (packet)
g_free(packet);
}
gboolean packetReceived;
int deviceDataLink;
static void dispatch_callback(const u_char *udata, const struct pcap_pkthdr *hdr, const guchar *pcappacket) {
jbase_packet * packet;
packet = jbase_packet_Alloc();
packet->device = jcapture_ActiveDevice;
packet->dataLink = deviceDataLink;
memcpy(&(packet->header), hdr, sizeof(struct pcap_pkthdr));
if (packet->header.caplen > BUFSIZ)
packet->header.caplen = BUFSIZ;
memcpy(packet->data, pcappacket, packet->header.caplen);
g_mutex_lock(jcapture_PacketQueueMutex);
g_queue_push_head(jcapture_PacketQueue, packet);
g_mutex_unlock(jcapture_PacketQueueMutex);
g_cond_signal(jcapture_PacketQueueCond);
}
static gpointer snifferThreadFunc(gpointer data) {
pcap_t *handle = NULL;
const jbase_device *device = NULL;
gchar pcap_errbuf[PCAP_ERRBUF_SIZE];
gboolean isFilterUsed = FALSE;
threadCount ++;
while (!isEnding) {
if (device != jcapture_ActiveDevice) {
if (isFilterUsed) {
JBASE_PCAP_FREECODE(handle, &activeBpfFilterProgram);
}
if (device) {
pcap_close(handle);
}
device = jcapture_ActiveDevice;
if (!device) {
g_cond_signal(jcapture_PacketQueueCond);
threadCount --;
jcapture_IsRunning = TRUE;
return NULL;
}
handle = pcap_open_live((char*)device->name, BUFSIZ, onoffPromisc, 10, pcap_errbuf);
if (handle == NULL) {
char BUF[PCAP_ERRBUF_SIZE + 128];
snprintf(BUF, PCAP_ERRBUF_SIZE + 128, "Not sniffing. Error while initializing %s: %s", device->name, pcap_errbuf);
jbase_cb_DrawStatus(BUF);
break;
}
#if HAVE_PCAP_SETNONBLOCK
pcap_setnonblock(handle, 1, NULL);
#endif
if (jcapture_ActiveBpfFilterText) {
isFilterUsed = FALSE;
debug(LOG_DEBUG, "Filter: %s\n", jcapture_ActiveBpfFilterText);
if (pcap_compile(handle, &activeBpfFilterProgram, (char *)jcapture_ActiveBpfFilterText, 0, 0xFFFFFFFF) == -1) {
char BUF[PCAP_ERRBUF_SIZE + 128];
snprintf(BUF, PCAP_ERRBUF_SIZE + 128, "Filter not applied. Error while compiling: %s", pcap_geterr(handle));
jbase_cb_DrawStatus(BUF);
} else {
if (pcap_setfilter(handle, &activeBpfFilterProgram) == -1) {
char BUF[PCAP_ERRBUF_SIZE + 128];
snprintf(BUF, PCAP_ERRBUF_SIZE + 128, "Filter not applied. setfilter(): %s", pcap_geterr(handle));
jbase_cb_DrawStatus(BUF);
}
isFilterUsed = TRUE;
}
}
deviceDataLink = pcap_datalink(handle);
}
#ifdef USE_SELECT
{
int pcap_fd = pcap_fileno(handle);
int sel_ret;
struct timeval timeout;
fd_set set1;
FD_ZERO(&set1);
FD_SET(pcap_fd, &set1);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
sel_ret = select(pcap_fd+1, &set1, NULL, NULL, &timeout);
if (sel_ret > 0) {
pcap_dispatch(handle, 10, (pcap_handler)dispatch_callback, NULL);
}
}
#else
{
packetReceived = FALSE;
pcap_dispatch(handle, 10, (pcap_handler)dispatch_callback, NULL);
if (!packetReceived)
g_thread_yield();
}
#endif
}
threadCount --;
jcapture_IsRunning = FALSE;
return NULL;
}
gboolean jcapture_Start() {
isEnding = FALSE;
jcapture_IsRunning = TRUE;
snifferThread = g_thread_create((GThreadFunc)snifferThreadFunc, NULL, TRUE, NULL);
return TRUE;
}
gboolean jcapture_Kill() {
gpointer ptr;
if (!jcapture_IsRunning || isEnding) {
debug(LOG_DEBUG, "Attempt to kill jcapture which is not running.");
return FALSE;
}
isEnding = TRUE;
g_thread_join(snifferThread);
g_mutex_lock(jcapture_PacketQueueMutex);
while ((ptr = g_queue_pop_tail(jcapture_PacketQueue))) {
g_free(ptr);
}
g_mutex_unlock(jcapture_PacketQueueMutex);
g_cond_signal(jcapture_PacketQueueCond);
return TRUE;
}