diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b2a4f998c..cc23568bb 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -115,6 +115,17 @@ config WIREGUARD_DEBUG Say N here unless you know what you're doing. +config WIREGUARD_FLIP_MSB + bool "A fix for WireGuard traffic blocking" + depends on WIREGUARD + default n + help + This will try to circumvent handshake packet dropping firewalls + thereby allowing WireGuard peers to handshake + successfully. MSB's of packets (message_type field) will be or'd + with a constant defined by MESSAGE_FLIP_CONSTANT. It is + also backward-compatible. + config EQUALIZER tristate "EQL (serial line load balancing) support" help diff --git a/drivers/net/wireguard/cookie.c b/drivers/net/wireguard/cookie.c index 4956f0499..3f7382af3 100644 --- a/drivers/net/wireguard/cookie.c +++ b/drivers/net/wireguard/cookie.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. + * Copyright (C) 2022 Metin Evrim Ulu . All Rights Reserved. */ #include "cookie.h" @@ -9,6 +10,7 @@ #include "messages.h" #include "ratelimiter.h" #include "timers.h" +#include "queueing.h" #include #include @@ -185,7 +187,12 @@ void wg_cookie_message_create(struct message_handshake_cookie *dst, ((u8 *)skb->data + skb->len - sizeof(*macs)); u8 cookie[COOKIE_LEN]; - dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE); + if (PACKET_PEER(skb)->is_blocked) + dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE | + MESSAGE_FLIP_CONSTANT); + else + dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE); + dst->receiver_index = index; get_random_bytes_wait(dst->nonce, COOKIE_NONCE_LEN); diff --git a/drivers/net/wireguard/messages.h b/drivers/net/wireguard/messages.h index 208da7267..79ca0a823 100644 --- a/drivers/net/wireguard/messages.h +++ b/drivers/net/wireguard/messages.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. + * Copyright (C) 2022 Metin Evrim Ulu . All Rights Reserved. */ #ifndef _WG_MESSAGES_H @@ -58,9 +59,13 @@ enum message_type { MESSAGE_HANDSHAKE_INITIATION = 1, MESSAGE_HANDSHAKE_RESPONSE = 2, MESSAGE_HANDSHAKE_COOKIE = 3, - MESSAGE_DATA = 4 + MESSAGE_DATA = 4, + MESSAGE_FLIP8 = 8 }; +/* Constant used by WIREGUARD_FLIP_MSB */ +#define MESSAGE_FLIP_CONSTANT MESSAGE_FLIP8 + struct message_header { /* The actual layout of this that we want is: * u8 type diff --git a/drivers/net/wireguard/noise.c b/drivers/net/wireguard/noise.c index 720952b92..502a8f23c 100644 --- a/drivers/net/wireguard/noise.c +++ b/drivers/net/wireguard/noise.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. + * Copyright (C) 2022 Metin Evrim Ulu . All Rights Reserved. */ #include "noise.h" @@ -532,7 +533,12 @@ wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst, if (unlikely(!handshake->static_identity->has_identity)) goto out; - dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION); +#if IS_ENABLED(CONFIG_WIREGUARD_FLIP_MSB) + dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION | + MESSAGE_FLIP_CONSTANT); +#else + dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION); +#endif handshake_init(handshake->chaining_key, handshake->hash, handshake->remote_static); @@ -665,7 +671,8 @@ wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src, } bool wg_noise_handshake_create_response(struct message_handshake_response *dst, - struct noise_handshake *handshake) + struct noise_handshake *handshake, + bool is_blocked) { u8 key[NOISE_SYMMETRIC_KEY_LEN]; bool ret = false; @@ -681,7 +688,12 @@ bool wg_noise_handshake_create_response(struct message_handshake_response *dst, if (handshake->state != HANDSHAKE_CONSUMED_INITIATION) goto out; - dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE); + if (is_blocked) + dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE | + MESSAGE_FLIP_CONSTANT); + else + dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE); + dst->receiver_index = handshake->remote_index; /* e */ diff --git a/drivers/net/wireguard/noise.h b/drivers/net/wireguard/noise.h index c527253db..920f10553 100644 --- a/drivers/net/wireguard/noise.h +++ b/drivers/net/wireguard/noise.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. + * Copyright (C) 2022 Metin Evrim Ulu . All Rights Reserved. */ #ifndef _WG_NOISE_H #define _WG_NOISE_H @@ -124,7 +125,8 @@ wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src, struct wg_device *wg); bool wg_noise_handshake_create_response(struct message_handshake_response *dst, - struct noise_handshake *handshake); + struct noise_handshake *handshake, + bool is_blocked); struct wg_peer * wg_noise_handshake_consume_response(struct message_handshake_response *src, struct wg_device *wg); diff --git a/drivers/net/wireguard/peer.c b/drivers/net/wireguard/peer.c index 1acd00ab2..761433321 100644 --- a/drivers/net/wireguard/peer.c +++ b/drivers/net/wireguard/peer.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. + * Copyright (C) 2022 Metin Evrim Ulu . All Rights Reserved. */ #include "peer.h" @@ -61,6 +62,7 @@ struct wg_peer *wg_peer_create(struct wg_device *wg, INIT_LIST_HEAD(&peer->allowedips_list); wg_pubkey_hashtable_add(wg->peer_hashtable, peer); ++wg->num_peers; + peer->is_blocked = false; // unblocked by default pr_debug("%s: Peer %llu created\n", wg->dev->name, peer->internal_id); return peer; diff --git a/drivers/net/wireguard/peer.h b/drivers/net/wireguard/peer.h index 76e4d3128..f8a3d5fe3 100644 --- a/drivers/net/wireguard/peer.h +++ b/drivers/net/wireguard/peer.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. + * Copyright (C) 2022 Metin Evrim Ulu . All Rights Reserved. */ #ifndef _WG_PEER_H @@ -64,6 +65,7 @@ struct wg_peer { struct list_head allowedips_list; struct napi_struct napi; u64 internal_id; + bool is_blocked; }; struct wg_peer *wg_peer_create(struct wg_device *wg, diff --git a/drivers/net/wireguard/receive.c b/drivers/net/wireguard/receive.c index 7b8df406c..66c374e61 100644 --- a/drivers/net/wireguard/receive.c +++ b/drivers/net/wireguard/receive.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. + * Copyright (C) 2022 Metin Evrim Ulu . All Rights Reserved. */ #include "queueing.h" @@ -36,16 +37,24 @@ static size_t validate_header_len(struct sk_buff *skb) { if (unlikely(skb->len < sizeof(struct message_header))) return 0; - if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_DATA) && + if (((SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_DATA)) || + (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_DATA | + MESSAGE_FLIP_CONSTANT))) && skb->len >= MESSAGE_MINIMUM_LENGTH) return sizeof(struct message_data); - if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION) && + if (((SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION)) || + (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION | + MESSAGE_FLIP_CONSTANT))) && skb->len == sizeof(struct message_handshake_initiation)) return sizeof(struct message_handshake_initiation); - if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE) && + if (((SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE)) || + (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE | + MESSAGE_FLIP_CONSTANT))) && skb->len == sizeof(struct message_handshake_response)) return sizeof(struct message_handshake_response); - if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE) && + if (((SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE)) || + (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE | + MESSAGE_FLIP_CONSTANT))) && skb->len == sizeof(struct message_handshake_cookie)) return sizeof(struct message_handshake_cookie); return 0; @@ -108,7 +117,9 @@ static void wg_receive_handshake_packet(struct wg_device *wg, bool packet_needs_cookie; bool under_load; - if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE)) { + if ((SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE)) || + (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE | + MESSAGE_FLIP_CONSTANT))) { net_dbg_skb_ratelimited("%s: Receiving cookie response from %pISpfsc\n", wg->dev->name, skb); wg_cookie_message_consume( @@ -139,6 +150,7 @@ static void wg_receive_handshake_packet(struct wg_device *wg, } switch (SKB_TYPE_LE32(skb)) { + case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION | MESSAGE_FLIP_CONSTANT): case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION): { struct message_handshake_initiation *message = (struct message_handshake_initiation *)skb->data; @@ -158,9 +170,14 @@ static void wg_receive_handshake_packet(struct wg_device *wg, net_dbg_ratelimited("%s: Receiving handshake initiation from peer %llu (%pISpfsc)\n", wg->dev->name, peer->internal_id, &peer->endpoint.addr); + if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION | + MESSAGE_FLIP_CONSTANT)) { + peer->is_blocked = true; + } wg_packet_send_handshake_response(peer); break; } + case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE | MESSAGE_FLIP_CONSTANT): case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE): { struct message_handshake_response *message = (struct message_handshake_response *)skb->data; @@ -551,8 +568,11 @@ void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb) if (unlikely(prepare_skb_header(skb, wg) < 0)) goto err; switch (SKB_TYPE_LE32(skb)) { + case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION | MESSAGE_FLIP_CONSTANT): case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION): case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE): + case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE | MESSAGE_FLIP_CONSTANT): + case cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE | MESSAGE_FLIP_CONSTANT): case cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE): { int cpu, ret = -EBUSY; @@ -578,6 +598,7 @@ void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb) &per_cpu_ptr(wg->handshake_queue.worker, cpu)->work); break; } + case cpu_to_le32(MESSAGE_DATA | MESSAGE_FLIP_CONSTANT): case cpu_to_le32(MESSAGE_DATA): PACKET_CB(skb)->ds = ip_tunnel_get_dsfield(ip_hdr(skb), skb); wg_packet_consume_data(wg, skb); diff --git a/drivers/net/wireguard/send.c b/drivers/net/wireguard/send.c index 5368f7c35..d61168f10 100644 --- a/drivers/net/wireguard/send.c +++ b/drivers/net/wireguard/send.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. + * Copyright (C) 2022 Metin Evrim Ulu . All Rights Reserved. */ #include "queueing.h" @@ -91,7 +92,7 @@ void wg_packet_send_handshake_response(struct wg_peer *peer) peer->device->dev->name, peer->internal_id, &peer->endpoint.addr); - if (wg_noise_handshake_create_response(&packet, &peer->handshake)) { + if (wg_noise_handshake_create_response(&packet, &peer->handshake, peer->is_blocked)) { wg_cookie_add_mac_to_packet(&packet, sizeof(packet), peer); if (wg_noise_handshake_begin_session(&peer->handshake, &peer->keypairs)) { @@ -166,6 +167,9 @@ static bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair) struct message_data *header; struct sk_buff *trailer; int num_frags; +#if !IS_ENABLED(CONFIG_WIREGUARD_FLIP_MSB) + struct wg_peer *peer = keypair->entry.peer; +#endif /* Force hash calculation before encryption so that flow analysis is * consistent over the inner packet. @@ -203,7 +207,16 @@ static bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair) */ skb_set_inner_network_header(skb, 0); header = (struct message_data *)skb_push(skb, sizeof(*header)); - header->header.type = cpu_to_le32(MESSAGE_DATA); + +#if IS_ENABLED(CONFIG_WIREGUARD_FLIP_MSB) + header->header.type = cpu_to_le32(MESSAGE_DATA | MESSAGE_FLIP_CONSTANT); +#else + if (peer && peer->is_blocked) + header->header.type = cpu_to_le32(MESSAGE_DATA | MESSAGE_FLIP_CONSTANT); + else + header->header.type = cpu_to_le32(MESSAGE_DATA); +#endif + header->key_idx = keypair->remote_index; header->counter = cpu_to_le64(PACKET_CB(skb)->nonce); pskb_put(skb, trailer, trailer_len);