aboutsummaryrefslogtreecommitdiff
path: root/lib/netdev-linux.c
diff options
context:
space:
mode:
authorMurphy McCauley <murphy.mccauley@gmail.com>2013-06-13 14:41:21 -0700
committerBen Pfaff <blp@nicira.com>2013-06-13 14:43:29 -0700
commit32383c3bd064fb87ec2b366569ba1185698c2e6d (patch)
tree096612d99d7de97b5e0e6a0a784286691e37df0f /lib/netdev-linux.c
parentddd3c9755d5fb1606445a72fb5f25e615518a162 (diff)
lib/netdev-linux.c: Prevent receiving of sent packets
Commit 796223f5 (netdev: Add new "struct netdev_rx" for capturing packets from a netdev) refactored send and receive into separate netdevs. As a result, send and receive now use different socket descriptors (except for tap interfaces which are treated specially). An unintended side effect was that all sent packets are looped back and received, which had previously been avoided as the kernel specifically prevents this from happening on a single socket descriptor. To resolve the situation, a socket filter is added to the receive socket so that it only accepts inbound packets. Simon Horman co-discovered and initially reported this issue. Signed-off-by: Murphy McCauley <murphy.mccauley@gmail.com> Signed-off-by: Ben Pfaff <blp@nicira.com> Tested-by: Simon Horman <horms@verge.net.au> Reviewed-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'lib/netdev-linux.c')
-rw-r--r--lib/netdev-linux.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index d73115be..014c579d 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -22,6 +22,7 @@
#include <fcntl.h>
#include <arpa/inet.h>
#include <inttypes.h>
+#include <linux/filter.h>
#include <linux/gen_stats.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
@@ -744,6 +745,14 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
} else {
struct sockaddr_ll sll;
int ifindex;
+ /* Result of tcpdump -dd inbound */
+ static struct sock_filter filt[] = {
+ { 0x28, 0, 0, 0xfffff004 }, /* ldh [0] */
+ { 0x15, 0, 1, 0x00000004 }, /* jeq #4 jt 2 jf 3 */
+ { 0x6, 0, 0, 0x00000000 }, /* ret #0 */
+ { 0x6, 0, 0, 0x0000ffff } /* ret #65535 */
+ };
+ static struct sock_fprog fprog = { ARRAY_SIZE(filt), filt };
/* Create file descriptor. */
fd = socket(PF_PACKET, SOCK_RAW, 0);
@@ -776,6 +785,16 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
netdev_get_name(netdev_), strerror(error));
goto error;
}
+
+ /* Filter for only inbound packets. */
+ error = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog,
+ sizeof fprog);
+ if (error) {
+ error = errno;
+ VLOG_ERR("%s: failed attach filter (%s)",
+ netdev_get_name(netdev_), strerror(error));
+ goto error;
+ }
}
rx = xmalloc(sizeof *rx);
@@ -910,7 +929,8 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size)
/* Use the tap fd to send to this device. This is essential for
* tap devices, because packets sent to a tap device with an
* AF_PACKET socket will loop back to be *received* again on the
- * tap device. */
+ * tap device. This doesn't occur on other interface types
+ * because we attach a socket filter to the rx socket. */
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
retval = write(netdev->state.tap.fd, data, size);