Skip to content
Snippets Groups Projects
Commit 2d0a8bf2 authored by Michael Tüxen's avatar Michael Tüxen
Browse files

Don't rely on pcap_setdirection() for filtering.

MacOS does not support pcap_setdirection() for PCAP_D_OUT.
Instead use only a single pcap handle (as it was originally) and
add a capture filter to only filter the packets in the expected
direction.
Only packets sent by the machine under test needs to be captured.
parent 627d8682
No related branches found
No related tags found
No related merge requests found
...@@ -403,6 +403,10 @@ struct netdev *local_netdev_new(struct config *config) ...@@ -403,6 +403,10 @@ struct netdev *local_netdev_new(struct config *config)
route_traffic_to_device(config, netdev); route_traffic_to_device(config, netdev);
netdev->psock = packet_socket_new(netdev->name); netdev->psock = packet_socket_new(netdev->name);
/* Make sure we only see packets from the machine under test. */
packet_socket_set_filter(netdev->psock,
NULL,
&config->live_local_ip); /* client IP */
return (struct netdev *)netdev; return (struct netdev *)netdev;
} }
......
...@@ -47,9 +47,8 @@ ...@@ -47,9 +47,8 @@
struct packet_socket { struct packet_socket {
char *name; /* malloc-allocated copy of interface name */ char *name; /* malloc-allocated copy of interface name */
pcap_t *pcap_in; /* handle for sniffing incoming packets */ pcap_t *pcap; /* handle for sniffing packets sent by the SUT */
pcap_t *pcap_out; /* handle for sniffing outgoing packets */ /* also used for sending packets */
/* also used for sending packets */
char pcap_error[PCAP_ERRBUF_SIZE]; /* for libpcap errors */ char pcap_error[PCAP_ERRBUF_SIZE]; /* for libpcap errors */
int pcap_offset; /* offset of packet data in pcap buffer */ int pcap_offset; /* offset of packet data in pcap buffer */
int data_link; int data_link;
...@@ -64,58 +63,30 @@ static inline s64 bpf_timeval_to_usecs(const struct bpf_timeval *tv) ...@@ -64,58 +63,30 @@ static inline s64 bpf_timeval_to_usecs(const struct bpf_timeval *tv)
} }
#endif /* defined(__OpenBSD__) */ #endif /* defined(__OpenBSD__) */
/* Call pcap_perror() and then exit with a failure status code. */
extern void die_pcap_perror(pcap_t *pcap, char *message)
{
pcap_perror(pcap, message);
exit(EXIT_FAILURE);
}
static void packet_socket_setup(struct packet_socket *psock) static void packet_socket_setup(struct packet_socket *psock)
{ {
int result;
DEBUGP("calling pcap_create() with %s\n", psock->name); DEBUGP("calling pcap_create() with %s\n", psock->name);
psock->pcap_in = pcap_create(psock->name, psock->pcap_error); psock->pcap = pcap_create(psock->name, psock->pcap_error);
if (psock->pcap_in == NULL) if (psock->pcap == NULL)
die_pcap_perror(psock->pcap_in, "pcap_create"); die("%s: %s\n", "pcap_create", psock->pcap_error);
psock->pcap_out = pcap_create(psock->name, psock->pcap_error); /* The following two calls MUST be called before activating
if (psock->pcap_out == NULL) * the handle. Then they are not failing. */
die_pcap_perror(psock->pcap_out, "pcap_create"); result = pcap_set_snaplen(psock->pcap, PACKET_READ_BYTES);
if (result != 0)
if (pcap_set_snaplen(psock->pcap_in, PACKET_READ_BYTES) != 0) die("%s: %s\n", "pcap_set_snaplen", pcap_statustostr(result));
die_pcap_perror(psock->pcap_in, "pcap_set_snaplen"); result = pcap_set_immediate_mode(psock->pcap, 1);
if (pcap_set_snaplen(psock->pcap_out, PACKET_READ_BYTES) != 0) if (result != 0)
die_pcap_perror(psock->pcap_out, "pcap_set_snaplen"); die("%s: %s\n", "pcap_set_immediate_mode", pcap_statustostr(result));
result = pcap_activate(psock->pcap);
/* By default libpcap with BPF waits until a read buffer fills if (result != 0) {
* up before returning any packets. We use the immediate mode to if (result == PCAP_WARNING || result == PCAP_ERROR)
* force the BPF device to return the first packet die("%s: %s\n", "pcap_activate", pcap_geterr(psock->pcap));
* immediately. else
* Enable this mode before activating the pcap handle. die("%s: %s\n", "pcap_activate", pcap_statustostr(result));
*/ }
if (pcap_set_immediate_mode(psock->pcap_in, 1) != 0) psock->data_link = pcap_datalink(psock->pcap);
die_pcap_perror(psock->pcap_out, "pcap_set_immediate_mode");
if (pcap_set_immediate_mode(psock->pcap_out, 1) != 0)
die_pcap_perror(psock->pcap_out, "pcap_set_immediate_mode");
if (pcap_activate(psock->pcap_in) != 0)
die_pcap_perror(psock->pcap_in,
"pcap_activate "
"(OpenBSD: another process (tcpdump?) "
"using bpf0?)");
if (pcap_activate(psock->pcap_out) != 0)
die_pcap_perror(psock->pcap_out,
"pcap_activate "
"(OpenBSD: another process (tcpdump?) "
"using bpf0?)");
if (pcap_setdirection(psock->pcap_in, PCAP_D_IN) != 0)
die_pcap_perror(psock->pcap_in, "pcap_setdirection");
if (pcap_setdirection(psock->pcap_out, PCAP_D_OUT) != 0)
die_pcap_perror(psock->pcap_out, "pcap_setdirection");
/* Find data link type. */
psock->data_link = pcap_datalink(psock->pcap_in);
DEBUGP("data_link: %d\n", psock->data_link); DEBUGP("data_link: %d\n", psock->data_link);
/* Based on the data_link type, calculate the offset of the /* Based on the data_link type, calculate the offset of the
...@@ -147,28 +118,28 @@ void packet_socket_set_filter(struct packet_socket *psock, ...@@ -147,28 +118,28 @@ void packet_socket_set_filter(struct packet_socket *psock,
ip_to_string(client_live_ip, client_live_ip_string); ip_to_string(client_live_ip, client_live_ip_string);
asprintf(&filter_str, if (client_ether_addr != NULL)
"ether src %02x:%02x:%02x:%02x:%02x:%02x and %s src %s", asprintf(&filter_str,
client_ether[0], "ether src %02x:%02x:%02x:%02x:%02x:%02x and %s src %s",
client_ether[1], client_ether[0],
client_ether[2], client_ether[1],
client_ether[3], client_ether[2],
client_ether[4], client_ether[3],
client_ether[5], client_ether[4],
client_live_ip->address_family == AF_INET6 ? "ip6" : "ip", client_ether[5],
client_live_ip_string); client_live_ip->address_family == AF_INET6 ? "ip6" : "ip",
client_live_ip_string);
else
asprintf(&filter_str,
"%s src %s",
client_live_ip->address_family == AF_INET6 ? "ip6" : "ip",
client_live_ip_string);
DEBUGP("setting BPF filter: %s\n", filter_str); DEBUGP("setting BPF filter: %s\n", filter_str);
if (pcap_compile(psock->pcap_in, &bpf_code, filter_str, 1, 0) != 0) if (pcap_compile(psock->pcap, &bpf_code, filter_str, 1, 0) != 0)
die_pcap_perror(psock->pcap_in, "pcap_compile"); die("%s: %s\n", "pcap_compile", pcap_geterr(psock->pcap));
if (pcap_setfilter(psock->pcap_in, &bpf_code) != 0) if (pcap_setfilter(psock->pcap, &bpf_code) != 0)
die_pcap_perror(psock->pcap_in, "pcap_setfilter"); die("%s: %s\n", "pcap_setfilter", pcap_geterr(psock->pcap));
pcap_freecode(&bpf_code);
if (pcap_compile(psock->pcap_out, &bpf_code, filter_str, 1, 0) != 0)
die_pcap_perror(psock->pcap_out, "pcap_compile");
if (pcap_setfilter(psock->pcap_out, &bpf_code) != 0)
die_pcap_perror(psock->pcap_out, "pcap_setfilter");
pcap_freecode(&bpf_code); pcap_freecode(&bpf_code);
free(filter_str); free(filter_str);
} }
...@@ -189,8 +160,7 @@ void packet_socket_free(struct packet_socket *psock) ...@@ -189,8 +160,7 @@ void packet_socket_free(struct packet_socket *psock)
if (psock->name != NULL) if (psock->name != NULL)
free(psock->name); free(psock->name);
pcap_close(psock->pcap_in); pcap_close(psock->pcap);
pcap_close(psock->pcap_out);
memset(psock, 0, sizeof(*psock)); /* paranoia to catch bugs*/ memset(psock, 0, sizeof(*psock)); /* paranoia to catch bugs*/
free(psock); free(psock);
...@@ -204,7 +174,7 @@ int packet_socket_writev(struct packet_socket *psock, ...@@ -204,7 +174,7 @@ int packet_socket_writev(struct packet_socket *psock,
*/ */
u8 *buf = NULL, *p = NULL; u8 *buf = NULL, *p = NULL;
int len = 0, i = 0; int len = 0, i = 0, result;
/* Calculate how much space we need. */ /* Calculate how much space we need. */
for (i = 0; i < iovcnt; ++i) for (i = 0; i < iovcnt; ++i)
...@@ -221,8 +191,11 @@ int packet_socket_writev(struct packet_socket *psock, ...@@ -221,8 +191,11 @@ int packet_socket_writev(struct packet_socket *psock,
DEBUGP("calling pcap_inject with %d bytes\n", len); DEBUGP("calling pcap_inject with %d bytes\n", len);
if (pcap_inject(psock->pcap_out, buf, len) != len) result = pcap_inject(psock->pcap, buf, len);
die_pcap_perror(psock->pcap_out, "pcap_inject"); if (result == -1)
die("%s: %s\n", "pcap_inject", pcap_geterr(psock->pcap));
if (result !=len)
die("%s: wrote %d bytes instead of %d\n", "pcap_inject", result, len);
free(buf); free(buf);
return STATUS_OK; return STATUS_OK;
...@@ -235,18 +208,12 @@ int packet_socket_receive(struct packet_socket *psock, ...@@ -235,18 +208,12 @@ int packet_socket_receive(struct packet_socket *psock,
int status = 0; int status = 0;
struct pcap_pkthdr *pkt_header = NULL; struct pcap_pkthdr *pkt_header = NULL;
const u8 *pkt_data = NULL; const u8 *pkt_data = NULL;
pcap_t *pcap;
struct ether_header *ether; struct ether_header *ether;
u32 address_family; u32 address_family;
DEBUGP("calling pcap_next_ex() for direction %s\n", DEBUGP("calling pcap_next_ex() for direction %s\n",
direction == DIRECTION_INBOUND ? "inbound" : "outbound"); direction == DIRECTION_INBOUND ? "inbound" : "outbound");
if (direction == DIRECTION_INBOUND)
pcap = psock->pcap_in;
else
pcap = psock->pcap_out;
/* Something about the way we're doing BIOCIMMEDIATE /* Something about the way we're doing BIOCIMMEDIATE
* causes libpcap to return 0 if there's no packet * causes libpcap to return 0 if there's no packet
* yet, which forces us to spin in this loop until * yet, which forces us to spin in this loop until
...@@ -257,13 +224,13 @@ int packet_socket_receive(struct packet_socket *psock, ...@@ -257,13 +224,13 @@ int packet_socket_receive(struct packet_socket *psock,
* here. TODO(ncardwell): fix this. * here. TODO(ncardwell): fix this.
*/ */
while (1) { while (1) {
status = pcap_next_ex(pcap, &pkt_header, &pkt_data); status = pcap_next_ex(psock->pcap, &pkt_header, &pkt_data);
if (status == 1) if (status == 1)
break; /* got a packet */ break; /* got a packet */
else if (status == 0) else if (status == 0)
return STATUS_ERR; /* no packet yet */ return STATUS_ERR; /* no packet yet */
else if (status == -1) else if (status == -1)
die_pcap_perror(pcap, "pcap_next_ex"); die("%s: %s\n", "pcap_inject", pcap_geterr(psock->pcap));
else if (status == -2) else if (status == -2)
die("pcap_next_ex: EOF in save file?!\n"); die("pcap_next_ex: EOF in save file?!\n");
else else
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment