-
Notifications
You must be signed in to change notification settings - Fork 99
Support direct allowed IP removal #156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
067de43
to
8d219c0
Compare
[1] adds the WGALLOWEDIP_F_REMOVE_ME flag to WireGuard's Netlink API which, in the same way that WGPEER_F_REMOVE_ME allows a user to remove a single peer from a WireGuard device's configuration, allows a user to remove an ip from a peer's set of allowed ips. This capability was subsequently ported to wireguard-go as well. Add support for this feature to wgctrl-go, allowing clients to incrementally remove allowed IPs on a peer like so: wgtypes.Config{ Peers: []wgtypes.PeerConfig{ { PublicKey: peerKey, AllowedIPs: []wgtypes.AllowedIPConfig{ { IPNet: ip, Remove: true, }, }, }, }, } [1]: https://lore.kernel.org/netdev/[email protected]/ Signed-off-by: Jordan Rife <[email protected]>
8d219c0
to
8e89697
Compare
Direct allowed IP removal is a new feature, so its availability is limited for now. Clients who want to take advantage of this capability would need to know ahead of time if WireGuard on their system supports it or probe to see if they're running on a system that supports it. To ease the transition, add the WithShim option for clients: c, err := wgctrl.New(wgctrl.WithShim) WithShim wraps internal clients with a shim client that probes to see if direct IP removal is supported on their system. If not, the shim client emulates the effect by assigning IPs to a dummy peer then removing that peer. At some point in the future, this option should no longer be necessary once the feature becomes commonplace. In my case, I plan to use WithShim to simplify Cilium's WireGuard orchestration logic. Signed-off-by: Jordan Rife <[email protected]>
5efcced
to
04b7167
Compare
FYI @zx2c4, I mentioned this work on the mailing lists, but it looks like most development for wgctrl-go happens on GitHub so tagging you here. |
Add testRemoveManyIPs to the integration tests to exercise the direct allowed IP removal capability and run the test suite on all platforms. $ WGCTRL_INTEGRATION=yesreallydoit go test . ┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┓ ┃ OPERATING SYSTEM ┃ DRIVER ┃ REMOVE IP SUPPORTED ┃ RESULT ┃ ┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━┩ │ FreeBSD 14.2 │ native │ no │ PASS │ ├──────────────────┼──────────────┼─────────────────────┼────────┤ │ OpenBSD 7.7 │ native │ no │ PASS* │ ├──────────────────┼──────────────┼─────────────────────┼────────┤ │ Windows 11 │ native │ no │ PASS** │ ├──────────────────┼──────────────┼─────────────────────┼────────┤ │ Linux │ native │ no │ PASS │ ├──────────────────┼──────────────┼─────────────────────┼────────┤ │ Linux │ wireguard-go │ no │ PASS │ ├──────────────────┼──────────────┼─────────────────────┼────────┤ │ Linux │ native │ yes │ PASS │ ├──────────────────┼──────────────┼─────────────────────┼────────┤ │ Linux │ wireguard-go │ yes │ PASS │ └──────────────────┴──────────────┴─────────────────────┴────────┘ I compiled Linux from the bpf-next/master tree which includes commit ba3d7b93dbe3 ("wireguard: allowedips: add WGALLOWEDIP_F_REMOVE_ME flag") and wireguard-go from the head of master which includes commit 256bcbd70d5b ("device: add support for removing allowedips individually") to test platforms with native support. On systems where direct IP removal is not supported, I also made sure that ConfigureDevice returns an error when Remove is used without the shim. * OpenBSD skips this test case, since the driver is read only. ** Two assertions fail in Windows due to missing protocol version, but testRemoveManyIPs passes. Signed-off-by: Jordan Rife <[email protected]>
04b7167
to
56a8249
Compare
cc @mdlayher could you take a look at this when you get a chance? Thanks! |
So the thing I don't like about this is that it's actually kind of well designed! Specifically, this In a year or two or three or four, most users won't really care about the lack of support on old kernels because new kernels will be more readily deployable. But right now, you do care, so you understandably want something now so that you can begin using this API. At the same time, "WithShim" is so generic and nice and neat. The API looks like a general purpose shim with a new general purpose options flag to enable it. But hopefully in five years that will be useless and we can remove the nice pretty API. Except nobody likes to remove nice pretty APIs. Because this is only going to be useful for a limited amount of time, and the actual thing that it does is a bit of a clever hack, what if we just treat the whole thing as a hack? For example, if this is to become always on (and why not?), then the flow looks like:
Where supportsAIPFlags() is something even dumber that runs uname(2) and caches the result in a boolean for subsequent usage. And then we decide based on the vulgar version number. Yes, this is terrible! This is objectively worse in almost every way than what you've proposed in your PR. Trying, failing, and retrying -- "probing" for features -- takes care of older userspace implementations, backported kernelspace implementations, and so forth. (It also makes things kinda messier in the future if we wind up with two things to probe for.) But userspace implementations can be upgraded easily, and kernel implementations will eventually be updated. So why not do the dumbest and least intrusive thing? Another solution would be to enable this with an option And then in a year or two when the kernel feature is widespread enough, we can just remove the built-in hack, and folks who hit this and complain can simply update their kernels at this point, but don't need to update their code. Does that make sense? |
As someone who is still supporting platforms stuck on RHEL 4.18 kernels, I really hope so haha. Old kernels stick around a while, especially for enterprisey stuff.
Unfortunately, you can't really trust the kernel version info to tell you what features are available. This probably works for most platforms, but there are exceptions like RHEL and its derivatives like Rocky where, for example, their "4.18" kernel is more like a 5.10 kernel as far as features go. This can be true of Ubuntu to a more limited extent as well, although they tend to track upstream kernels a little more closely, only backporting the odd bug fix here and there. This is an annoyance I've grappled with a lot, especially as it relates to Cilium. A more feature-specific probe is simple enough, as evidenced by the code here, so I'd advise sticking with that approach to avoid the inevitable headaches that come with comparing kernel version strings. This is the only part I have a strong feeling about.
I hear you on the API, and as far as that goes, I have no strong opinions one way or another. I'm fine enabling the behavior by default and dropping the How would you feel about this plan?:
It should be trivial to drop the shim layer later by deleting a file and a few functions later on without impacting users of the library. |
@zx2c4 Just checking back in! How do you feel about my counterproposal? |
@zx2c4 @mdlayher Any thoughts here? I'd love to close the loop on this, as it's coming up on a year since I embarked on the endeavor to support direct IP removal throughout the stack. The As an aside, I noticed this repo seems to be short on reviewers, so if you're looking for some extra help I'd be happy to chip in. |
AllowedIPConfig
I recently implemented support for the WGALLOWEDIP_F_REMOVE_ME flag to WireGuard Linux's Netlink API which, in the same way that
WGPEER_F_REMOVE_ME
allows a user to remove a single peer from a WireGuard device's configuration, allows a user to remove an ip from a peer's set of allowed ips. This capability was subsequently ported to wireguard-go as well.This PR adds support for this feature to wgctrl-go, allowing clients to incrementally remove allowed IPs on a peer like so:
WithShim
The second part of this PR adds a
WithShim
option for clients. Since direct allowed IP removal is a new feature, set to land in the next Linux release, its availability is limited for now. Clients who want to take advantage of the capability would need to know ahead of time if WireGuard on their system supports it or probe to see if they're running on a system that supports it. To ease the transition, add the WithShim option for clients:WithShim
wraps internal clients with a shim client that probes to see if direct IP removal is supported on their system. If not, the shim client emulates the effect by assigning IPs to a dummy peer then removing that peer. At some point in the future, this option should no longer be necessary once the feature becomes commonplace.In my case, I plan to use WithShim to simplify Cilium's WireGuard orchestration logic, since it needs to work across a range of Linux kernel versions.
Testing
I expanded the integration tests to exercise the direct allowed IP removal capability and ran them on all platforms.
$ WGCTRL_INTEGRATION=yesreallydoit go test .
I compiled Linux from the bpf-next/master tree which includes commit ba3d7b93dbe3 ("wireguard: allowedips: add WGALLOWEDIP_F_REMOVE_ME flag") and wireguard-go from the head of master which includes commit 256bcbd70d5b ("device: add support for removing allowedips individually") to test platforms with native support.
On systems where direct IP removal is not supported, I also made sure that ConfigureDevice returns an error when Remove is used without the shim.
1 OpenBSD skips this test case, since the driver is read only.
2 Two assertions fail in Windows due to missing protocol version, but testRemoveManyIPs passes.