1
/*** This Programs/Libraries are (C)opyright by Sebastian Krahmer.
2
*** You may use it under the terms of the GPL. You should have
3
*** already received the file COPYING that shows you your rights.
4
*** Please look at COPYING for further license-details.
6
*** THERE IS ABSOLUTELY NO WARRANTY. SO YOU USE IT AT YOUR OWN RISK.
7
*** IT WAS WRITTEN IN THE HOPE THAT IT WILL BE USEFULL. I AM NOT RESPONSIBLE
8
*** FOR ANY DAMAGE YOU MAYBE GET DUE TO USING MY PROGRAMS.
12
#include "usi++/usi-structs.h"
13
#include "usi++/datalink.h"
18
#include <sys/ioctl.h>
30
memset(d_filter_string, 0, sizeof(d_filter_string));
32
memset(&d_tv, 0, sizeof(d_tv));
34
memset(d_dev, 0, sizeof(d_dev));
40
/* This constructor should be used to
41
* initialize raw-d_datalink-objects, means not IP/TCP/ICMP etc.
42
* We need this b/c unlike in derived classes, d_datalink::init_device()
43
* cannot set a filter!
45
Pcap::Pcap(char *filterStr)
48
memset(d_filter_string, 0, sizeof(d_filter_string));
49
strncpy(d_filter_string, filterStr, sizeof(d_filter_string));
52
memset(d_dev, 0, sizeof(d_dev));
63
Pcap::Pcap(const Pcap &rhs)
67
d_datalink = rhs.d_datalink;
68
d_framelen = rhs.d_framelen;
69
d_filter = rhs.d_filter;
72
d_ether = rhs.d_ether;
73
strncpy(d_filter_string, rhs.d_filter_string, sizeof(d_filter_string));
74
strncpy(d_dev, rhs.d_dev, sizeof(d_dev));
75
d_has_promisc = rhs.d_has_promisc;
76
d_snaplen = rhs.d_snaplen;
80
init_device(d_dev, d_has_promisc, d_snaplen);
85
Pcap &Pcap::operator=(const Pcap &rhs)
89
d_datalink = rhs.d_datalink;
90
d_framelen = rhs.d_framelen;
91
d_filter = rhs.d_filter;
94
d_ether = rhs.d_ether;
95
strncpy(d_filter_string, rhs.d_filter_string, sizeof(d_filter_string));
96
strncpy(d_dev, rhs.d_dev, sizeof(d_dev));
97
d_has_promisc = rhs.d_has_promisc;
98
d_snaplen = rhs.d_snaplen;
105
init_device(d_dev, d_has_promisc, d_snaplen);
111
/* Return the actual d_datalink of the object.
113
int Pcap::get_datalink()
118
/* Return the actual framlen of the object.
119
* (d_framelen depends on d_datalink)
121
int Pcap::get_framelen()
127
/* Fill buffer with src-hardware-adress of actuall packet,
128
* use 'd_datalink' to determine what HW the device is.
129
* Now only ethernet s supportet, but it's extensinable.
131
char *Pcap::get_hwsrc(char *hwaddr, size_t len)
134
memset(hwaddr, 0, len);
136
switch (d_datalink) {
138
if (len < 2*ETH_ALEN)
140
s = d_ether.ether_shost;
141
sprintf(hwaddr, "%02x:%02x:%02x:%02x:%02x:%02x", (u_char)*s,
142
(u_char)*(s+1), (u_char)*(s+2), (u_char)*(s+3),
143
(u_char)*(s+4), (u_char)*(s+5));
151
/* Fill buffer with dst-hardware-adress of actuall packet,
152
* use 'd_datalink' to determine what HW the device is.
153
* Now only ethernet s supportet.
155
char *Pcap::get_hwdst(char *hwaddr, size_t len)
159
memset(hwaddr, 0, len);
160
switch (d_datalink) {
162
if (len < 2*ETH_ALEN)
164
s = d_ether.ether_dhost;
165
sprintf(hwaddr, "%02x:%02x:%02x:%02x:%02x:%02x", (u_char)*s,
166
(u_char)*(s+1), (u_char)*(s+2), (u_char)*(s+3),
167
(u_char)*(s+4), (u_char)*(s+5));
175
/* Get protocol-type of ethernet-frame
176
* Maybe moves to ethernet-class in future?
178
u_int16_t Pcap::get_etype()
180
return ntohs(d_ether.ether_type);
183
/* Initialize a device ("eth0" for example) for packet-
184
* capturing. It MUST be called before sniffpack() is launched.
185
* Set 'promisc' to 1 if you want the device running in promiscous mode.
186
* Fetch at most 'd_snaplen' bytes per call.
188
int Pcap::init_device(char *dev, int promisc, size_t d_snaplen)
190
char ebuf[PCAP_ERRBUF_SIZE];
191
memset(ebuf, 0, PCAP_ERRBUF_SIZE);
193
if ((d_pd = pcap_open_live(dev, d_snaplen, promisc, 500, ebuf)) == NULL) {
194
die(ebuf, STDERR, 1);
196
#ifdef HAVE_PCAP_SETNONBLOCK
197
// make sure pcap_next() does not block
198
if (pcap_setnonblock(d_pd, 1, ebuf) < 0) {
199
die(ebuf, STDERR, 1);
203
// Ehem, BSD workarounnd. BSD won't timeout on select()
204
// unless we force immediate return for read() (in pcap)
205
// for uncomplete packets (queue not full?)
208
if (ioctl(pcap_fileno(d_pd), BIOCIMMEDIATE, &v) < 0) {
209
snprintf(ebuf, sizeof(ebuf),
210
"Pcap::init_device::ioctl(..., BIOCIMMEDIATE, 1) %s",
212
die(ebuf, STDERR, 1);
215
if (pcap_lookupnet(dev, &d_localnet, &d_netmask, ebuf) < 0) {
216
snprintf(ebuf, sizeof(ebuf), "Pcap::init_device::pcap_lookupnet: %s\n",
218
die(ebuf, STDERR, 1);
222
/* The d_filter_string must be filled by derived classes, such
223
* as IP, where the virtual init_device() simply sets d_filter_string
224
* to "ip" and then calls Pcap::init_device().
226
if (pcap_compile(d_pd, &d_filter, d_filter_string, 1, d_netmask) < 0) {
227
snprintf(ebuf, sizeof(ebuf), "Pcap::init_device::pcap_compile: %s\n",
229
die(ebuf, STDERR, 1);
231
if (pcap_setfilter(d_pd, &d_filter) < 0) {
232
snprintf(ebuf, sizeof(ebuf), "Pcap::init_device::pcap_setfilter: %s\n",
234
die(ebuf, STDERR, 1);
236
if ((d_datalink = pcap_datalink(d_pd)) < 0) {
237
snprintf(ebuf, sizeof(ebuf), "Pcap::init_device::pcap_d_datalink: %s\n",
239
die(ebuf, STDERR, 1);
242
// turn d_datalink into d_framelen
243
switch (d_datalink) {
245
d_framelen = sizeof(d_ether);
248
d_framelen = 4; /* shouldn't be 4 */
274
printf("%d %d\n", d_datalink, DLT_RAW);
275
fprintf(stderr, "Datalink type: %i not supported. Report!\n", d_datalink);
276
die("Pcap::init_device: Unknown d_datalink.\n", STDERR, 1);
279
strncpy(d_dev, dev, sizeof(d_dev));
280
d_has_promisc = promisc;
281
d_snaplen = d_snaplen;
286
/* set a new filter for capturing
288
int Pcap::setfilter(char *s)
290
char ebuf[PCAP_ERRBUF_SIZE];
291
memset(ebuf, 0, PCAP_ERRBUF_SIZE);
294
die("Pcap::setfilter: Device not initialized.\n", STDERR, 1);
296
memset(d_filter_string, 0, sizeof(d_filter_string));
297
snprintf(d_filter_string, sizeof(d_filter_string), "%s", s);
299
if (pcap_compile(d_pd, &d_filter, d_filter_string, 1, d_netmask) < 0) {
300
snprintf(ebuf, sizeof(ebuf), "Pcap::setfilter::pcap_compile: %s\n", pcap_geterr(d_pd));
301
die(ebuf, STDERR, 1);
304
if (pcap_setfilter(d_pd, &d_filter) < 0) {
305
snprintf(ebuf, sizeof(ebuf), "Pcap::setfilter::pcap_setfilter: %s\n", pcap_geterr(d_pd));
306
die(ebuf, STDERR, 1);
311
int Pcap::sniffpack(void *s, size_t len)
318
die("Pcap::sniffpack: Device not initialized.\n", STDERR, 1);
320
/* XXX: with select() packets on loopback interface are lost
321
* so we leave it out for now
323
if (d_tv.tv_sec != 0 || d_tv.tv_usec != 0) { // TO was set
327
int fd = pcap_fileno(d_pd);
333
if ((sr=select(fd+1, &rset, NULL, NULL, &tmp)) < 0) {
338
} else if (sr == 0) { // timed out
346
/* XXX: there is a bug on linux when select() returns 1, but pcap_next()
348
if (start == 0) // first time sniffpack() is called
351
if (d_tv.tv_sec != 0 || d_tv.tv_usec != 0) { // timeout set
352
while ((tmp = (char*)pcap_next(d_pd, &d_phdr)) == NULL)
353
if ((time(NULL) - start) > d_tv.tv_sec) {
358
} else { // no timeout set, loop until we get some kind of packet
359
while ((tmp = (char*)pcap_next(d_pd, &d_phdr)) == NULL)
363
switch (d_datalink) {
365
memcpy(&d_ether, tmp, d_framelen);
385
die("Pcap::sniffpack: Unknown d_datalink.\n", STDERR, 1);
388
cerr<<"Pcap::d_phdr.len="<<d_phdr.len<<endl;
389
cerr<<"Pcap::d_framelen="<<d_framelen<<endl;
391
// d_framelen was already calculated by init_device
392
memcpy(s, (tmp + d_framelen),
393
d_phdr.len - d_framelen < len ? d_phdr.len - d_framelen : len);
394
return (d_phdr.len - d_framelen);
398
// give back layer2 frame
399
void *Pcap::get_frame(void *hwframe, size_t len)
402
// switch over the hardware-layer of the packet
403
switch (d_datalink) {
405
memcpy(hwframe, &d_ether, (len<sizeof(d_ether)?len:sizeof(d_ether)));
413
int Pcap::timeout(struct timeval tv)