Neat! How does yours work? The Go version of this is easy to write, because wireguard-go has helpers to drive Netstack, which is also written in Go. But yours is in Rust. (I could have dug in, but I'm being lazy).
This is good stuff. There should be, ideally, one really good tool for doing plugboard-y stunnel-y type stuff with user-mode WireGuard, where you don't need root to set up the tunnels, and this could be that.
What do you mean by that? Mullvad doesn't have a generally accessible socks proxy like PIA does, that works with or without having the VPN on. The proxy is a localhost one for the most part so you can prevent an app from going online without having your vpn client on first.
> If you configure your browser, for example, to use the SOCKS5 proxy, it will direct all of your internet access via the proxy which is only accessible through Mullvad. So if you haven't turned on the app, your browser will prevent all internet access and therefore won't leak any information.
The OP post also needs the "VPN active" (ie: an active connection to the VPN server). Having the VPN active does not mean it's routing all your traffic through it, what traffic is routed through it is controlled by your wireguard config/routing table. Having
AllowedIPs = 10.64.0.1/32
in your wireguard config will only forward traffic bound to 10.64.0.1 (the IP Mullvad uses for their SOCKS5 proxies on wireguard connections) to the VPN server, which more or less achieves the same result as the OP post. You can access the SOCKS proxy without having your whole internet routed through the VPN.
An active connection but not an active system-wide network interface. The point of these tools is that the wireguard client is encapsulated together with the proxy in a simple user-mode process, with no integration into the host network stack.
I love wireguard but my one gripe with it is that its not a true data link layer. You have to give it routing information through an out of band mechanism “AllowedIPs.” One downside is that you can’t have two peers that act as general routers on the same wireguard network. With Ethernet, you can have multiple nodes in the same subnet acting as generic routers, it’s just a matter of sending IP packets to that host.
I hope someday wireguard addresses this issue and makes itself fully transparent as a data link layer.
> You have to give it routing information through an out of band mechanism “AllowedIPs.” One downside is that you can’t have two peers that act as general routers on the same wireguard network
This is a common misconception, due to that this is the way wg-quick works (unfortunately IMO; presumably to make it easier, and I guess wg-quick was never meant for people with advanced needs). On a lower level, AllowedIPs is really just "allowed IPs", and does no routing. You can have multiple active peers with overlapping AllowedIPs.
If you set up the tunnel through other means, you can make your own routes.
For example in systemd-networkd, see `RouteTable` under the `[WireguardPeer]` section of systemd.netdev(5).
(This was unfortunately broken for a brief while in systemd in Jan, but should now be fixed again: https://github.com/systemd/systemd/pull/22136. If it's not clear from the link, old and current behavior are that no routes are added unless RouteTable is explicitly set)
You should also be able to set it up manually and then add routes, policies and rules manually however you would otherwise.
(You're of course right on the protocol layer, but that is not the cause of the problem you want to solve)
Are you sure what you described works? Last I tried it didn't work, and this is explicitly stated on wireguard.com:
> In other words, when sending packets, the list of allowed IPs behaves as a sort of routing table, and when receiving packets, the list of allowed IPs behaves as a sort of access control list.
> This is what we call a Cryptokey Routing Table: the simple association of public keys and allowed IPs.
Which is, I believe, also why zx2c4 called to revert the whole systemd-networkd feature.
I would really want it to work as it would simplify my network configuration by a bit. Please share a working example if you are able to make it work, thanks!
Last I tried that I used iproute 2 to manually setup interfaces, use wg setconf to load WireGuard configurations. So I don't think it's my tool to blame.
> Are you sure what you described works? Last I tried it didn't work, and this is explicitly stated on wireguard.com:
If we're talking simply about decoupling routing from AllowedIPs, yes, using that right now and set it up several times. For redundant routers, see below.
> > In other words, when sending packets, the list of allowed IPs behaves as a sort of routing table
This does seem in conflict with my understanding... Depending on exactly what devil-details go into that "sort of", of course. Not deep enough into it to tell you, though.
> Which is, I believe, also why zx2c4 called to revert the whole systemd-networkd feature.
Rather the opposite AIUI; To allow for setting routes explicitly (which introducing the wg-quick behavior broke[0]).
What started making it click for me was this ArchWiki section[1]. The discussion under this GH issue may also provide some pointers[2]. Also [3]. IIRC I did get multiple outbound redundant routers with failover in the end. There may be WG-specific gremlins I glanced over but ascribed it to not fully grokking the Linux IP stack and issues with *tables in general at the time - the goal I had is hairy enough without Wireguard in the mix. Please report back here on your progress if you have the time :)
EDIT: Went back to take a look and I never did get proper HA routing sorted - ended up "solving" it with a script regularly checking reachability and bringing routes up/down accordingly. No need to bring the actual WG interfaces or IP assignments up/down for that, though.
> Cryptokey Routing, which works by associating public keys with a list of tunnel IP addresses that are allowed inside the tunnel.
> In the server configuration, when the network interface wants to send a packet to a peer (a client), it looks at that packet's destination IP and compares it to each peer's list of allowed IPs to see which peer to send it to.
> the list of allowed IPs behaves as a sort of routing table
> This is what we call a Cryptokey Routing Table
You can just set your peers on separate wg interfaces. At least on Linux and BSD, you have tables to control routing before packets reach the interface.
So you can have two wg interfaces, each with a single but distinct peer both with CIDR 0.0.0.0/0 (or what have you), and use ip-route/nftables as usual to pick the appropriate outgoing interface.
It makes sense if you think of each wg interface as a NIC connected to an L3 switch, and each peer to a host connected to another port on the same switch. AllowedIPs would correspond to the table+ACL in the switch.
But yeah, me saying it "does no routing" was not really correct. But that routing happens after that of the (rest of the) Linux kernel, not overlapping with, replacing, or conflicting with.
While this understanding does come from a decent amount of experience, in case I'm wildly misrepresenting things, do set it straight.
Not at all. See the links in the thread. You can try it yourself to verify if you do not believe me (and again, wg-quick does extra things here which are not inherent to Wireguard). And also again, you can specify as many wireguard interfaces as you want - no need to cram all peers into one interface.
i just wish i could control the routing via routing tables instead, making dynamic routing decisions possible without specialized software that is able to manipulate it.
just so you know, your assumption i am not using the right tools feels almost insulting to me considering i made no claim about any tooling used. i am using systemd-networkd to setup networking anywhere, i never touch wg-quick because it is no fit for my use cases. i have multiple routing tables and do policy routing and i would really like to have the "via" in the routing tables to have a meaning to wireguards crypto routing thing. i.e. i want to be able to set "AllowedIPs" based upon the routing table very similar to reverse path filtering. i know i can setup multiple interfaces with multiple keys to exchange and multiple ports to set and to make sure every client that needs to is kept in sync.... but it would be much nicer if i could handle it like an ip-ip tunnel and make routing decisions with software build for this purpose.
Wireguard is not a link layer (layer 2) tunnel; it is a network (layer 3) tunnel. It operates at the IP layer. You cannot use Wireguard with any non-IP layer3.
AllowedIPs can be disabled if you want; just set it to 0.0.0.0/0. AllowedIPs is needed because netfilter can't "see" which public key an inbound packet is coming from, so by the time a packet gets to netfilter it's too late to accept/reject based on which peer sent it to us.
> Only one peer is allowed to use 0.0.0.0/0 for AllowedIPs
This is simply incorrect. You can have two peers with the same AllowedIP; you just have to put them on separate interfaces (wg0 and wg1 for example). This is for exactly the same reason that a routing table can only have one default entry. If you want two default entries, make two routing tables.
> Yes but UI wise it presents itself as one
No, it doesn't present itself as one.
> since it’s acts as an interface
So does /dev/net/tun, which is definitely not a layer 2 interface either.
> you just have to put them on separate interfaces
I don’t have to do this with normal data link layers. That’s the point of the complaint. Wireguard is not a true data link layer. Manually configuring multiple interfaces for something I can do with just one interface with a normal data link layer at runtime is an extra inconvenience.
> This is for exactly the same reason that a routing table can only have one default entry. If you want two default entries, make two routing tables.
Using nftables I can specify different routers to use based on arbitrarily complex packet rules. Using just one interface. I can’t do this with wireguard, it will only allow me to to route arbitrary packets to a single peer on an interface. This is an inconvenience.
This is less important although useful in some cases. The more important thing is outbound - since Wireguard is layer 3, in the routing table you can't specify a peer to send the packet to like you can with ethernet, and it has to choose one using AllowedIPs.
This SFP has an embedded ARM processor running Linux. It’s pretty meta, but one could imagine a wireguard control network for these. The article even describes using wireguard-go on the embedded side.
This is cool! I was looking for something to integrate into an automated downloading setup. I had already setup a docker container that connected to wireguard and then the other containers would connect to the internet through that one, but doing it with socks is a lot easier and more of an out-of-the-box config. Decreasing complexity. Very nice!
A Docker solution[1] for the same thing using the official client. Performance can’t be compared with native kernel mode of course, but same technique can be used for other global proxy like OpenVPN.[2]
It would be really cool if you could use something like this in-process to open a "socket" that just happens to route over wireguard or another VPN.
E.g. you could easily have a bittorrent client use a certain VPN without routing all your traffic over it, or you could have a tab container in firefox use one connection, and another container another connection.
I used to run OpenVPN in a Docker container together with a SOCKS proxy for this exact use case (using a commercial VPN provider that doesn't offer SOCKS with different endpoints on a per-site/per-tab basis, without wanting to change my default route or non-browser traffic), but this is much more efficient (and safer).
I made it because my friends and I use wireguard to have a private network, and they don't feel comfortable running a ssh server on their machines. It can also be used with a vpn provider like Mullvad without setting up a new nic or requiring special privs.
I want to point out a caveat to others: Proxifier != VPN
wireproxy's wg only forwards TCP and UDP. I am not sure how ICMP is handled. Other transports, though rarely used, won't be tunneled (and may leak, if not dropped).
Most importantly missing: DNS, which usually is handled over UDP (changing slowly now with DNS-over-HTTPS and some TCP resolvers). Without handling DNS requests via your proxy, you're still leaking information about yourself to the resolver you're using.
To clarify, UDP is not currently supported, but I intend to support it in the future. Incoming ICMP should be completely dropped, and outgoing ICMP is not supported.
One simple reason is that the serverside might not want to expose a shell to its clients, and instead just provide network connectivity; you can configure something like that with SSH, but it's a pain, and WireGuard is approximately as simple to set up as SSH, which is the primary reason it's so popular.
Is it a pain? As far as I know, all that's needed is to insert restrict,command="/sbin/nologin",port-forwarding before the user's key in authorized_keys. You can add more security by using a separate user, but individual Unix users for each client are not^W^Wshould not be necessary for security.
userspace means that the code runs in userspace so, it doesn't require admin privileges. So, it is great if you are not the root. Exposing socks5 is great, so that another userspace process can use it. So, let's say you would like to run a torrent client in a restrictive environment, you can setup this and then through sock5 interface, you might be able to bypass firewall around it.
i have yet to encounter a case where a udp-tunnel has a practical advantage over tcp; on the other hand, corporate/hotel/coffeeshop firewalls that block anything not tcp/443 are super commom.
Though admittedly, mine doesn't have SOCKS support, and the code is not as lean as yours!