change sniffer behaviour when stopping capture. workaround if pcap_findalldev fails

unstable
gaspmat@gmail.com 2012-03-02 10:48:17 +01:00 committed by James Lee
parent 46da36d3a0
commit 248a73a73c
3 changed files with 241 additions and 69 deletions

View File

@ -64,28 +64,46 @@ void __stdcall sniffer_receive(DWORD_PTR Param, DWORD_PTR ThParam, HANDLE hPacke
char *get_interface_name_by_index(unsigned int fidx) char *get_interface_name_by_index(unsigned int fidx)
{ {
unsigned idx = 1; unsigned int i, idx;
char errbuf[PCAP_ERRBUF_SIZE+4]; char errbuf[PCAP_ERRBUF_SIZE+4];
static char device_name[64]; // PKS, probably safe, due to snifferm mutex static char device_name[64]; // PKS, probably safe, due to snifferm mutex
int if_error;
struct ifaces_list *ifaces;
pcap_if_t *interfaces, *int_iter; pcap_if_t *interfaces, *int_iter;
interfaces = int_iter = NULL;
ifaces = NULL;
idx = 1;
memset(device_name, 0, sizeof(device_name)); memset(device_name, 0, sizeof(device_name));
interfaces = int_iter = NULL;
if(pcap_findalldevs(&interfaces, errbuf) == -1) { if(pcap_findalldevs(&interfaces, errbuf) == -1) {
dprintf("Hmm, out of memory? (errno = %d, but probably not useful)", errno); dprintf("pcap_findalldevs failed, trying netlink_get_interfaces, errbuf was : %s", errbuf);
if_error = netlink_get_interfaces(&ifaces);
if(if_error) {
dprintf("Error when retrieving interfaces info");
return NULL; return NULL;
} }
for (i = 0; i < ifaces->entries; i++) {
if(fidx == ifaces->ifaces[i].index) {
strncpy(device_name, ifaces->ifaces[i].name, sizeof(device_name)-1);
break;
}
}
}
else { //pcap_findalldevs suceeded
for(int_iter = interfaces; int_iter; int_iter = int_iter->next) { for(int_iter = interfaces; int_iter; int_iter = int_iter->next) {
if(fidx == idx++) { if(fidx == idx++) {
strncpy(device_name, int_iter->name, sizeof(device_name)-1); strncpy(device_name, int_iter->name, sizeof(device_name)-1);
break; break;
} }
} }
}
if(interfaces)
pcap_freealldevs(interfaces); pcap_freealldevs(interfaces);
if (ifaces)
free(ifaces);
return device_name[0] ? device_name : NULL; return device_name[0] ? device_name : NULL;
@ -137,8 +155,8 @@ struct sockaddr_in6 *peername6;
/* mutex */ /* mutex */
LOCK *snifferm; LOCK *snifferm;
#define SNIFFER_MAX_INTERFACES 128 #define SNIFFER_MAX_INTERFACES 128 // let's hope interface index don't go above this value
#define SNIFFER_MAX_QUEUE 210000 // ~300Mb @ 1514 bytes #define SNIFFER_MAX_QUEUE 200000 // ~290Mb @ 1514 bytes
CaptureJob open_captures[SNIFFER_MAX_INTERFACES]; CaptureJob open_captures[SNIFFER_MAX_INTERFACES];
@ -151,6 +169,7 @@ DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet);
HANDLE pktsdk_interface_by_index(unsigned int fidx); HANDLE pktsdk_interface_by_index(unsigned int fidx);
DWORD pktsdk_initialize(void); DWORD pktsdk_initialize(void);
DWORD request_sniffer_interfaces(Remote *remote, Packet *packet) DWORD request_sniffer_interfaces(Remote *remote, Packet *packet)
{ {
Packet *response = packet_create_response(packet); Packet *response = packet_create_response(packet);
@ -166,11 +185,11 @@ DWORD request_sniffer_interfaces(Remote *remote, Packet *packet)
6: Accessible? 6: Accessible?
7: DHCP? 7: DHCP?
*/ */
unsigned int idx = 1;
DWORD result = ERROR_SUCCESS; DWORD result = ERROR_SUCCESS;
#ifdef _WIN32 #ifdef _WIN32
HANDLE hCfg; HANDLE hCfg;
unsigned int idx = 1;
check_pssdk(); check_pssdk();
@ -233,6 +252,10 @@ DWORD request_sniffer_interfaces(Remote *remote, Packet *packet)
#else #else
char errbuf[PCAP_ERRBUF_SIZE+4]; char errbuf[PCAP_ERRBUF_SIZE+4];
int aidx = htonl(1); // :~( int aidx = htonl(1); // :~(
struct ifaces_list *ifaces;
uint32_t i;
int aidx_bigendian;
int mtu_bigendian;
int yes_int = htonl(1); int yes_int = htonl(1);
int no_int = 0; int no_int = 0;
@ -241,14 +264,12 @@ DWORD request_sniffer_interfaces(Remote *remote, Packet *packet)
pcap_if_t *interfaces, *int_iter; pcap_if_t *interfaces, *int_iter;
interfaces = int_iter = NULL; interfaces = int_iter = NULL;
ifaces = NULL;
do { do {
result = pcap_findalldevs(&interfaces, errbuf); result = pcap_findalldevs(&interfaces, errbuf);
if(result) {
dprintf("pcap_findalldevs() failed, errbuf is %s", errbuf);
break;
}
if(!result) { // pcap_findalldevs suceeded
for(int_iter = interfaces; int_iter; int_iter = int_iter->next) for(int_iter = interfaces; int_iter; int_iter = int_iter->next)
{ {
entries[0].header.type = TLV_TYPE_UINT; entries[0].header.type = TLV_TYPE_UINT;
@ -257,11 +278,11 @@ DWORD request_sniffer_interfaces(Remote *remote, Packet *packet)
entries[1].header.type = TLV_TYPE_STRING; entries[1].header.type = TLV_TYPE_STRING;
entries[1].header.length = strlen(int_iter->name)+1; entries[1].header.length = strlen(int_iter->name)+1;
entries[1].buffer = int_iter->name; entries[1].buffer = (PUCHAR)int_iter->name;
entries[2].header.type = TLV_TYPE_STRING; entries[2].header.type = TLV_TYPE_STRING;
entries[2].header.length = strlen(int_iter->name)+1; entries[2].header.length = strlen(int_iter->name)+1;
entries[2].buffer = int_iter->name; entries[2].buffer = (PUCHAR)int_iter->name;
entries[3].header.type = TLV_TYPE_UINT; entries[3].header.type = TLV_TYPE_UINT;
entries[3].header.length = sizeof(unsigned int); entries[3].header.length = sizeof(unsigned int);
@ -286,12 +307,63 @@ DWORD request_sniffer_interfaces(Remote *remote, Packet *packet)
packet_add_tlv_group(response, TLV_TYPE_SNIFFER_INTERFACES, entries, 8); packet_add_tlv_group(response, TLV_TYPE_SNIFFER_INTERFACES, entries, 8);
aidx = htonl(ntohl(aidx)+1); // :~( aidx = htonl(ntohl(aidx)+1); // :~(
} }
} else {
dprintf("pcap_findalldevs() failed, trying netlink_get_interfaces now, errbuf was %s", errbuf);
result = netlink_get_interfaces(&ifaces);
if(result) {
dprintf("Error when retrieving interfaces info");
break;
}
// netlink_get_interfaces suceeded
for (i = 0; i < ifaces->entries; i++)
{
aidx_bigendian = htonl(ifaces->ifaces[i].index);
entries[0].header.type = TLV_TYPE_UINT;
entries[0].header.length = sizeof(uint32_t);
entries[0].buffer = (PUCHAR)&aidx_bigendian;
entries[1].header.type = TLV_TYPE_STRING;
entries[1].header.length = strlen(ifaces->ifaces[i].name)+1;
entries[1].buffer = (PUCHAR)ifaces->ifaces[i].name;
entries[2].header.type = TLV_TYPE_STRING;
entries[2].header.length = strlen(ifaces->ifaces[i].name)+1;
entries[2].buffer = (PUCHAR)ifaces->ifaces[i].name;
entries[3].header.type = TLV_TYPE_UINT;
entries[3].header.length = sizeof(unsigned int);
entries[3].buffer = (PUCHAR)&no_int; // xxx, get encapsulation type?
mtu_bigendian = htonl(ifaces->ifaces[i].mtu);
entries[4].header.type = TLV_TYPE_UINT;
entries[4].header.length = sizeof(uint32_t);
entries[4].buffer = (PUCHAR)&mtu_bigendian;
entries[5].header.type = TLV_TYPE_BOOL;
entries[5].header.length = sizeof(BOOL);
entries[5].buffer = (PUCHAR)&no_int; // check encaps options / crap
entries[6].header.type = TLV_TYPE_BOOL;
entries[6].header.length = sizeof(BOOL);
entries[6].buffer = (PUCHAR)&yes_int; // sure, why not.
entries[7].header.type = TLV_TYPE_BOOL;
entries[7].header.length = sizeof(BOOL);
entries[7].buffer = (PUCHAR)&no_int; // hrm. not worth it.
packet_add_tlv_group(response, TLV_TYPE_SNIFFER_INTERFACES, entries, 8);
}
}
} while(0); } while(0);
if(ifaces)
free(ifaces);
if(interfaces) if(interfaces)
pcap_freealldevs(interfaces); pcap_freealldevs(interfaces);
#endif #endif
packet_transmit_response(result, remote, response); packet_transmit_response(result, remote, response);
@ -419,7 +491,7 @@ void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *byt
if(j->idx_pkts >= j->max_pkts) j->idx_pkts = 0; if(j->idx_pkts >= j->max_pkts) j->idx_pkts = 0;
if(j->pkts[j->idx_pkts]) free(j->pkts[j->idx_pkts]); if(j->pkts[j->idx_pkts]) free((void*)(j->pkts[j->idx_pkts]));
j->pkts[j->idx_pkts++] = pkt; j->pkts[j->idx_pkts++] = pkt;
@ -483,7 +555,7 @@ DWORD request_sniffer_capture_start(Remote *remote, Packet *packet) {
ifid = packet_get_tlv_value_uint(packet,TLV_TYPE_SNIFFER_INTERFACE_ID); ifid = packet_get_tlv_value_uint(packet,TLV_TYPE_SNIFFER_INTERFACE_ID);
maxp = packet_get_tlv_value_uint(packet,TLV_TYPE_SNIFFER_PACKET_COUNT); maxp = packet_get_tlv_value_uint(packet,TLV_TYPE_SNIFFER_PACKET_COUNT);
maxp = min(maxp, 200000); maxp = min(maxp, SNIFFER_MAX_QUEUE);
maxp = max(maxp, 1); maxp = max(maxp, 1);
result = ERROR_SUCCESS; result = ERROR_SUCCESS;
@ -526,7 +598,7 @@ DWORD request_sniffer_capture_start(Remote *remote, Packet *packet) {
break; break;
} }
#else #else
name = get_interface_name_by_index(ifid); name = get_interface_name_by_index(ifh);
if(! name) { if(! name) {
result = ERROR_INVALID_PARAMETER; result = ERROR_INVALID_PARAMETER;
@ -626,7 +698,7 @@ DWORD request_sniffer_capture_start(Remote *remote, Packet *packet) {
DWORD request_sniffer_capture_stop(Remote *remote, Packet *packet) { DWORD request_sniffer_capture_stop(Remote *remote, Packet *packet) {
Packet *response = packet_create_response(packet); Packet *response = packet_create_response(packet);
unsigned int ifid,i; unsigned int ifid;
CaptureJob *j; CaptureJob *j;
DWORD result; DWORD result;
@ -670,13 +742,8 @@ DWORD request_sniffer_capture_stop(Remote *remote, Packet *packet) {
thread_join(j->thread); // should take less than 1 second :p thread_join(j->thread); // should take less than 1 second :p
#endif #endif
for(i=0; i<j->max_pkts; i++) { packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts);
if(!j->pkts[i]) break; packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int) j->cur_bytes);
PktDestroy(j->pkts[i]);
j->pkts[i] = NULL;
}
free(j->pkts);
memset(j, 0, sizeof(CaptureJob));
lock_release(snifferm); lock_release(snifferm);
@ -687,7 +754,62 @@ DWORD request_sniffer_capture_stop(Remote *remote, Packet *packet) {
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
DWORD request_sniffer_capture_release(Remote *remote, Packet *packet) {
Packet *response = packet_create_response(packet);
unsigned int ifid,i;
CaptureJob *j;
DWORD result;
check_pssdk();
dprintf("sniffer>> release_capture()");
ifid = packet_get_tlv_value_uint(packet,TLV_TYPE_SNIFFER_INTERFACE_ID);
dprintf("sniffer>> release_capture(0x%.8x)", ifid);
result = ERROR_SUCCESS;
do {
// the interface is invalid
if(ifid == 0 || ifid >= SNIFFER_MAX_INTERFACES) {
result = ERROR_INVALID_PARAMETER;
break;
}
j = &open_captures[ifid];
// the interface is not being captured
#ifdef _WIN32
if(! j->adp || j->active == 1)
#else
if(! j->pcap || j->active == 1)
#endif
{
result = ERROR_INVALID_PARAMETER;
break;
}
lock_acquire(snifferm);
packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts);
packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int) j->cur_bytes);
dprintf("sniffer>> release_capture() interface %d released %d packets/%d bytes", j->intf, j->cur_pkts, j->cur_bytes);
for(i=0; i<j->max_pkts; i++) {
if(!j->pkts[i]) break;
PktDestroy(j->pkts[i]);
j->pkts[i] = NULL;
}
free(j->pkts);
memset(j, 0, sizeof(CaptureJob));
lock_release(snifferm);
} while(0);
packet_transmit_response(result, remote, response);
return ERROR_SUCCESS;
}
DWORD request_sniffer_capture_stats(Remote *remote, Packet *packet) { DWORD request_sniffer_capture_stats(Remote *remote, Packet *packet) {
Packet *response = packet_create_response(packet); Packet *response = packet_create_response(packet);
@ -722,9 +844,10 @@ DWORD request_sniffer_capture_stats(Remote *remote, Packet *packet) {
result = ERROR_INVALID_PARAMETER; result = ERROR_INVALID_PARAMETER;
break; break;
} }
lock_acquire(snifferm);
packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts); packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_PACKET_COUNT, j->cur_pkts);
packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int) j->cur_bytes); packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, (unsigned int) j->cur_bytes);
lock_release(snifferm);
} while(0); } while(0);
packet_transmit_response(result, remote, response); packet_transmit_response(result, remote, response);
@ -733,7 +856,7 @@ DWORD request_sniffer_capture_stats(Remote *remote, Packet *packet) {
DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) { DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) {
Packet *response = packet_create_response(packet); Packet *response = packet_create_response(packet);
unsigned int ifid; unsigned int ifid, i;
unsigned int bcnt; unsigned int bcnt;
CaptureJob *j; CaptureJob *j;
DWORD result; DWORD result;
@ -753,13 +876,13 @@ DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) {
// the interface is invalid // the interface is invalid
if(ifid == 0 || ifid >= SNIFFER_MAX_INTERFACES) { if(ifid == 0 || ifid >= SNIFFER_MAX_INTERFACES) {
packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0); packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0);
break; goto fail;
} }
j = &open_captures[ifid]; j = &open_captures[ifid];
if(! j->dbuf) { if(! j->dbuf) {
packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0); packet_add_tlv_uint(response, TLV_TYPE_SNIFFER_BYTE_COUNT, 0);
break; goto fail;
} }
if(j->didx + bcnt > j->dlen) { if(j->didx + bcnt > j->dlen) {
@ -777,8 +900,22 @@ DWORD request_sniffer_capture_dump_read(Remote *remote, Packet *packet) {
j->dbuf = NULL; j->dbuf = NULL;
j->didx = 0; j->didx = 0;
j->dlen = 0; j->dlen = 0;
// if dump occurs when interface is not active, i.e sniff has ended, release info
if (j->active == 0) {
dprintf("sniffer>> capture_dump_read, release CaptureJob");
lock_acquire(snifferm);
for(i=0; i<j->max_pkts; i++) {
if(!j->pkts[i]) break;
PktDestroy(j->pkts[i]);
j->pkts[i] = NULL;
}
free(j->pkts);
memset(j, 0, sizeof(CaptureJob));
lock_release(snifferm);
}
} }
fail:
packet_transmit_response(result, remote, response); packet_transmit_response(result, remote, response);
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
@ -791,7 +928,7 @@ DWORD request_sniffer_capture_dump(Remote *remote, Packet *packet) {
unsigned int *tmp; unsigned int *tmp;
CaptureJob *j; CaptureJob *j;
DWORD result,pcnt,bcnt,rcnt,i; DWORD result,pcnt,rcnt,i;
DWORD thi, tlo; DWORD thi, tlo;
check_pssdk(); check_pssdk();
@ -834,7 +971,6 @@ DWORD request_sniffer_capture_dump(Remote *remote, Packet *packet) {
// Add basic stats // Add basic stats
pcnt = 0; pcnt = 0;
bcnt = 0;
rcnt = 0; rcnt = 0;
mbuf = (1024*1024); mbuf = (1024*1024);
@ -916,6 +1052,11 @@ Command customCommands[] =
{ request_sniffer_capture_stats, { 0 }, 0 }, { request_sniffer_capture_stats, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER }, { EMPTY_DISPATCH_HANDLER },
}, },
// Release captured packets instead of downloading them
{ "sniffer_capture_release",
{ request_sniffer_capture_release, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
// Sniffing packet dump // Sniffing packet dump
{ "sniffer_capture_dump", { "sniffer_capture_dump",
{ request_sniffer_capture_dump, { 0 }, 0 }, { request_sniffer_capture_dump, { 0 }, 0 },

View File

@ -60,6 +60,10 @@ class Sniffer < Extension
request = Packet.create_request('sniffer_capture_stop') request = Packet.create_request('sniffer_capture_stop')
request.add_tlv(TLV_TYPE_SNIFFER_INTERFACE_ID, intf.to_i) request.add_tlv(TLV_TYPE_SNIFFER_INTERFACE_ID, intf.to_i)
response = client.send_request(request) response = client.send_request(request)
{
:packets => response.get_tlv_value(TLV_TYPE_SNIFFER_PACKET_COUNT),
:bytes => response.get_tlv_value(TLV_TYPE_SNIFFER_BYTE_COUNT),
}
end end
# Retrieve stats about a current capture # Retrieve stats about a current capture
@ -73,6 +77,17 @@ class Sniffer < Extension
} }
end end
# Release packets from a current capture
def capture_release(intf)
request = Packet.create_request('sniffer_capture_release')
request.add_tlv(TLV_TYPE_SNIFFER_INTERFACE_ID, intf.to_i)
response = client.send_request(request)
{
:packets => response.get_tlv_value(TLV_TYPE_SNIFFER_PACKET_COUNT),
:bytes => response.get_tlv_value(TLV_TYPE_SNIFFER_BYTE_COUNT),
}
end
# Buffer the current capture to a readable buffer # Buffer the current capture to a readable buffer
def capture_dump(intf) def capture_dump(intf)
request = Packet.create_request('sniffer_capture_dump') request = Packet.create_request('sniffer_capture_dump')

View File

@ -33,6 +33,7 @@ class Console::CommandDispatcher::Sniffer
"sniffer_stop" => "Stop packet capture on a specific interface", "sniffer_stop" => "Stop packet capture on a specific interface",
"sniffer_stats" => "View statistics of an active capture", "sniffer_stats" => "View statistics of an active capture",
"sniffer_dump" => "Retrieve captured packet data to PCAP file", "sniffer_dump" => "Retrieve captured packet data to PCAP file",
"sniffer_release" => "Free captured packets on a specific interface instead of downloading them",
} }
end end
@ -76,8 +77,10 @@ class Console::CommandDispatcher::Sniffer
return return
end end
client.sniffer.capture_stop(intf) res = client.sniffer.capture_stop(intf)
print_status("Capture stopped on interface #{intf}") print_status("Capture stopped on interface #{intf}")
print_status("There are #{res[:packets]} packets (#{res[:bytes]} bytes) remaining")
print_status("Download or release them using 'sniffer_dump' or 'sniffer_release'")
return true return true
end end
@ -97,6 +100,19 @@ class Console::CommandDispatcher::Sniffer
return true return true
end end
def cmd_sniffer_release(*args)
intf = args[0].to_i
if (intf == 0)
print_error("Usage: sniffer_stats [interface-id]")
return
end
res = client.sniffer.capture_release(intf)
print_status("Flushed #{res[:packets]} packets (#{res[:bytes]} bytes) from interface #{intf}")
return true
end
def cmd_sniffer_dump(*args) def cmd_sniffer_dump(*args)
intf = args[0].to_i intf = args[0].to_i
if (intf == 0 or not args[1]) if (intf == 0 or not args[1])