wireguard: problem sending via libpcap's packet socket

Message ID 20200626201330.325840-1-ndev@hwipl.net
State New
Headers show
Series
  • wireguard: problem sending via libpcap's packet socket
Related show

Commit Message

Hans Wippel June 26, 2020, 8:13 p.m.
Hi,

while toying around with sending packets with libpcap, I noticed that it
did not work with a wireguard interface in contrast to my regular
ethernet interface.

It seems like libpcap does not set a protocol on the packet socket and
the following checks

  "skb->protocol == real_protocol",
  "skb->protocol == htons(ETH_P_IP)" and
  "skb->protocol == htons(ETH_P_IPV6)"

in the functions

  wg_check_packet_protocol(),
  wg_xmit() and
  wg_allowedips_lookup_dst()

fail because skb->protocol is 0.

Is this intended behaviour? Should these checks be changed in the kernel
or should this rather be reported to libpcap? Just in case, you can find
changes that made it work for me below (probably not the best solution).

Again, if this is not the right place to ask, just let me know and I am
sorry for the noise.
  Hans

Signed-off-by: Hans Wippel <ndev@hwipl.net>
---
 drivers/net/wireguard/allowedips.c | 5 +++--
 drivers/net/wireguard/device.c     | 4 ++--
 drivers/net/wireguard/queueing.h   | 3 ++-
 3 files changed, 7 insertions(+), 5 deletions(-)

Patch

diff --git a/drivers/net/wireguard/allowedips.c b/drivers/net/wireguard/allowedips.c
index 3725e9cd85f4..08e16907fde5 100644
--- a/drivers/net/wireguard/allowedips.c
+++ b/drivers/net/wireguard/allowedips.c
@@ -5,6 +5,7 @@ 
 
 #include "allowedips.h"
 #include "peer.h"
+#include "queueing.h"
 
 static void swap_endian(u8 *dst, const u8 *src, u8 bits)
 {
@@ -356,9 +357,9 @@  int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr)
 struct wg_peer *wg_allowedips_lookup_dst(struct allowedips *table,
 					 struct sk_buff *skb)
 {
-	if (skb->protocol == htons(ETH_P_IP))
+	if (wg_examine_packet_protocol(skb) == htons(ETH_P_IP))
 		return lookup(table->root4, 32, &ip_hdr(skb)->daddr);
-	else if (skb->protocol == htons(ETH_P_IPV6))
+	else if (wg_examine_packet_protocol(skb) == htons(ETH_P_IPV6))
 		return lookup(table->root6, 128, &ipv6_hdr(skb)->daddr);
 	return NULL;
 }
diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c
index a8f151b1b5fa..baed429b2ed1 100644
--- a/drivers/net/wireguard/device.c
+++ b/drivers/net/wireguard/device.c
@@ -132,10 +132,10 @@  static netdev_tx_t wg_xmit(struct sk_buff *skb, struct net_device *dev)
 	peer = wg_allowedips_lookup_dst(&wg->peer_allowedips, skb);
 	if (unlikely(!peer)) {
 		ret = -ENOKEY;
-		if (skb->protocol == htons(ETH_P_IP))
+		if (wg_examine_packet_protocol(skb) == htons(ETH_P_IP))
 			net_dbg_ratelimited("%s: No peer has allowed IPs matching %pI4\n",
 					    dev->name, &ip_hdr(skb)->daddr);
-		else if (skb->protocol == htons(ETH_P_IPV6))
+		else if (wg_examine_packet_protocol(skb) == htons(ETH_P_IPV6))
 			net_dbg_ratelimited("%s: No peer has allowed IPs matching %pI6\n",
 					    dev->name, &ipv6_hdr(skb)->daddr);
 		goto err;
diff --git a/drivers/net/wireguard/queueing.h b/drivers/net/wireguard/queueing.h
index c58df439dbbe..36badcf8a11d 100644
--- a/drivers/net/wireguard/queueing.h
+++ b/drivers/net/wireguard/queueing.h
@@ -84,7 +84,8 @@  static inline __be16 wg_examine_packet_protocol(struct sk_buff *skb)
 static inline bool wg_check_packet_protocol(struct sk_buff *skb)
 {
 	__be16 real_protocol = wg_examine_packet_protocol(skb);
-	return real_protocol && skb->protocol == real_protocol;
+	return real_protocol == htons(ETH_P_IP) ||
+		real_protocol == htons(ETH_P_IPV6);
 }
 
 static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating)