Transport: Add transparent proxy support for OpenBSD (pf divert-to) - #6546
Open
adsdevdoo wants to merge 1 commit into
Open
Transport: Add transparent proxy support for OpenBSD (pf divert-to)#6546adsdevdoo wants to merge 1 commit into
adsdevdoo wants to merge 1 commit into
Conversation
Member
|
Rebase
|
adsdevdoo
force-pushed
the
openbsd-transparent-proxy
branch
from
July 27, 2026 14:29
ef21c99 to
9458117
Compare
Member
|
GetOriginalDestination 是 redirect 模式使用的 从 conn.LocalAddr() 拿地址是典型的 Tproxy 模式的特征 它就在下面 从conn.LocalAddr() 获取地址 你为什么要单独写一个 redirect 模式 用的 GetOriginalDestination 然后包装 conn.LocalAddr() ? |
Implement the OpenBSD side of transparent proxying for the tunnel (dokodemo-door) inbound with followRedirect enabled: - UDP: enable IP_RECVDSTADDR and IP_RECVDSTPORT on the listening socket and read the original destination from the control messages. OpenBSD has no single message carrying address and port together, so both are required. - UDP replies: implement FakeUDP with SO_BINDANY so replies leave with the original destination as their source address; pf routes them back to the client via divert-reply. TCP needs no code: pf divert-to leaves the packet untouched, so the local address of the accepted socket already is the original destination, which is what the existing TProxy branch reads. Such an inbound is configured with "tproxy": "tproxy" in its sockopt. IPv4 only for now; IPv6 returns a clear error from FakeUDP.
adsdevdoo
force-pushed
the
openbsd-transparent-proxy
branch
from
July 28, 2026 06:11
9458117 to
1e87ebc
Compare
Author
|
@Fangliding |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Right now Xray can't work as a transparent proxy on OpenBSD.
GetOriginalDestinationfor TCP is a stub that returns an empty destination, and the UDP hub never learns where a packet was originally headed, so atunnelinbound withfollowRedirect: truedies with "unable to get destination". The usual workaround,followRedirect: falseplus sniffing, only covers HTTP and TLS. SSH and anything else sniffing can't identify ends up going to 127.0.0.1 and silently fails.This PR fills in the missing pieces. The mechanisms differ from both Linux and FreeBSD, which I suspect is why nobody ported this before:
divert-todoes not rewrite the packet, sogetsockname(2)on the accepted socket still returns the original destination. This is documented in pf.conf(5) and it's how relayd does it, sotransport/internet/tcp/sockopt_openbsd.gojust readsconn.LocalAddr(). No natlook ioctl needed, unlike FreeBSD.applyInboundSocketOptionssetsIP_RECVDSTADDRandIP_RECVDSTPORTwhenReceiveOriginalDestAddressis requested, and the UDP hub parses both control messages. There is no single cmsg carrying address and port together like Linux'sIP_RECVORIGDSTADDR;IP_RECVDSTPORTis OpenBSD specific and both messages are required.FakeUDPfor OpenBSD binds a socket to that address withSO_BINDANY, and a pfdivert-replyrule gets the packet back to the client.Everything sits behind
openbsdbuild tags with matching exclusions in the*_other.gofiles, so no other platform is touched. There's a small unit test for the control message parsing.No config changes are needed, the existing tunnel inbound options simply start working:
{ "listen": "127.0.0.1", "port": 12345, "protocol": "tunnel", "settings": { "allowedNetwork": "tcp", "followRedirect": true } }, { "listen": "127.0.0.1", "port": 12346, "protocol": "tunnel", "settings": { "allowedNetwork": "udp", "followRedirect": true } }with pf rules along these lines:
Testing. This is running on two OpenBSD routers, 7.7 and 7.8, both amd64, each serving a small LAN. Verified there: plain web traffic, SSH out to external hosts and other protocols sniffing cannot classify, DNS, QUIC/HTTP3, and Telegram and WhatsApp voice calls.
go test ./transport/internet/udppasses on OpenBSD, andgofmtandgo vetare clean on the touched packages. I have not run it on 7.9 yet. I went through the 7.9 release notes and changelog and found nothing touching divert,SO_BINDANYor the recvdst options, so I expect it to work unchanged, and I'll report back once I've upgraded a box.Limitations, to be upfront about them:
FakeUDPreturns a clear error for IPv6 targets. Doing v6 properly meansIPV6_RECVPKTINFObased plumbing, and I didn't want to ship code I can't test.SO_BINDANYneeds root, but that's inherent to transparent proxying on OpenBSD, relayd has the same requirement.One more thing. #5824 moves OpenBSD out of regular releases for lack of manpower, and says the platform can rejoin the standard build process once it gets reasonably active support. I run Xray on OpenBSD daily and I'm willing to be that support: testing on real hardware, keeping the OpenBSD specific code building and working across releases, and picking up OpenBSD issues as they come in. Happy to adjust naming or structure if you'd rather have this organized differently.