-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Transparently proxying UDP traffic with pf? #1543
Comments
I have never tested on FreeBSD, so this project supports FreeBSD is still "theoretically". I have tested In your last PR, you said on FreeBSD UDP's destination could be retrieved from The |
That wasn't me, so you must be thinking of someone else. While I know how to write rules for pf fairly well, I've never programmed anything to interface with it, so I'm unsure of how the API is supposed to be used. The good news is that you can access the man pages online. There's also a forum, mailing lists, and a Discord server, all of which feature some form of development/programming discussion. I'm interested in learning as well, but I'm still learning rust, so it may be some time until I am of use. |
Glad to know that you are familiar with FreeBSD and pf. Could you find any doc / references about how to get the "original destination address" of UDP packets? On Linux, it is quite straight forward: https://man7.org/linux/man-pages/man7/ip.7.html ( On macOS, I got it from another post: (?) Deleted. A famous tools mitmproxy only supports TCP on FreeBSD: https://docs.mitmproxy.org/stable/howto-transparent/ . So it is quite hard to find a reference about how FreeBSD handles UDP redirects and how to get the original destination address programmatically. |
And you could also try the |
@Orum Do you still interest in making this Project working on FreeBSD? What's the current status? |
I am still very interested in making it work. However, I think the best way to do so at this point is to just read through FreeBSD's source code. As such, I'm familiarizing myself with it, but it's going to take some time as I have other obligations and projects demanding my attention, so it's on the back burner for me right now. This is probably the best, or at least, surest way to figure out how to get the address (assuming it's even possible at present) from pf. Additionally, I'd need to learn much more about rust before I contribute anything other than information to this project, as my knowledge of it is spotty at best. But, if I do figure out the FreeBSD side of the picture, perhaps someone here can handle that side of things once they have the information. I'm also not only willing, but happy to test things to see if they work once they're implemented. |
semigodking/redsocks#200 |
FreeBSD and OpenBSD diverged in their rules syntax quite a few years back when the latter made some changes that broke older rule sets, IIRC. I've stuck with FreeBSD, which might have an equivalent of I also don't really want to switch to ipfw, or any other firewall, as I really value simplicity and clarity of pf's rules' syntax. So many other firewalls are hard to decipher, which is undesirable to say the least when it comes to security. In any case I will try and dedicate some time to reading through and understanding the pf/bpf code in the future, but that will be some time from now. |
@ge9 Have you tried shadowsocks-rust with ipfw? What problem did you see? |
I tested it and it worked, but there were a problem.
However, FreeBSD disables IPv4-mapped IPv6 address by default (according to scala-native/scala-native#3630). If I set sysctl net.inet6.ip6.v6only=0 , then it worked.Except for this, normal transparent proxy setting will work. FYI, My settings are following:
|
There is a This is always working for Linux, because dual-stack socket was enabled by default for most distribution of Linux. Is there a way to test if dual-stack is enabled on FreeBSD? By reading |
Could you please help to run the test program on FreeBSD and see if any of these syscalls returned errors? |
cc @madeye , FreeBSD doesn't support IPv4-mapped-IPv6 by default. So my previous (years ago) PR that uses IPv6 sockets for sending back UDP packets won't be able to run properly on FreeBSD. |
This is the result of the python test program.
If I set In the shadowsocks, this is the error.
This originates from
|
Please test if it is Ok without setting |
I just found a better solution. Working on it. |
- ref #1543 - Reference Implementation: golang src/net/ipsock_posix.go ipStckCapabilities
Tested on OpenWRT. Please help testing it if it is working correctly on FreeBSD. @ge9 |
Please run again with shadowsocks-rust/crates/shadowsocks/src/net/sys/mod.rs Lines 143 to 181 in cd25d25
Are they all |
here is the log. seems all true.
|
Well, so FreeBSD allows |
Call |
Hmm it seems still not working...
|
Replace it with the method just like the one on stackoverflow. Please try again. @ge9 |
I have one thing to add, actually I'm testing transparent proxy with only one machine, by making the machine send packet to itself through the loopback device. 10.0.2.25 is the source address to which the proxy will be applied. Then we can test proxy by some commands like
|
BTW, mark-based routing on FreeBSD is also supported, which should be something like Linux's shadowsocks-rust/crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs Lines 43 to 59 in a27410c
It should allow you to easily route the outbound requests sent from But I really don't know how to set it in
|
My VM has IP 192.168.11.191, and
I want to test UDP redirects locally on FreeBSD, On the other hand,
It doesn't work, which seems to create an infinite loop. |
Did you confirm an infinite loop actually happened? The config seems fine to me. |
Yes, it do exist. |
Ah, did you assigned an additional IP? I assigned both 10.0.2.15 and 10.0.2.25 on the external interface. 10.0.2.15 was assigned by default (by Virtualbox's DHCP) and 10.0.2.25 is manually assigned, thus can be used for proxying. |
Nope. 192.168.11.192 was assigned by DHCP. So I should add another IP to
|
Ok now, here is the problem. Currently
was successfully redirected to
Well, the destination address was How can you test for a response UDP packet sent from remote? |
Yes, that's the problem on pf, which I don't know how to solve. |
I just found that https://man.openbsd.org/pf.conf#divert-to How to configure a rule with |
No, it's OpenBSD behavior. FreeBSD's divert-to has similar syntax but completely different meaning, as documented in https://man.freebsd.org/cgi/man.cgi?pf.conf(5) . (Also, from my experience on running redsocks in OpenBSD, supporting OpenBSD+divert-to requires a little work on UDP/TCP socket options). |
Just tested on FreeBSD with If it is
No errors was shown. But the client couldn't receive the response. In the latter case, I think |
With the test just did in Python: import socket
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0)
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
s.connect(('::ffff:169.254.1.1', 53))
print(s.getsockname()) When Script will always success without any errors. The line of If When Behavior was exactly the same. So there is no way to detect with |
The behavior seems quite wrong. Maybe we should let FreeBSD developers know about it. |
They offer a convenient way to do that. In any case, perhaps this issue report on shadowsocks should be split into two separate issues, one for the original issue of using transparent proxying with pf, and a new one for the IPv4/v6 issue. |
True. But currently the topic about IPv4-mapped IPv6 support was already come to a conclusion. We should focus on how to support UDP with |
The IPv4/v6 issue seems to be fixed now? |
@ge9 Of course, please make a PR. |
Here is an issue listed all known ways to make transparent proxy: 2EXP/2exp.github.io#2 .
|
https://man.freebsd.org/cgi/man.cgi?query=pf&sektion=4&manpath=OpenBSD
In the document it said shadowsocks-rust/crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs Lines 296 to 338 in 8b32d85
But it doesn't work, right? @Orum
Implementation detail: https://reviews.freebsd.org/D9235 According to this implementation, |
It is |
…TADDR NOTE: They have the same value as IP_ORIGDSTADDR, IPV6_ORIGDSTADDR ref #1543
I didn't know FreeBSD's man page describes UDP transparent proxy treatments. That seems much like OpenBSD's behavior. I may try it. |
All the references are from FreeBSD's manpage. |
I tried using |
I think the next step is to findout where the value of |
IP_RECVORIGDSTADDR equals IP_ORIGDSTADDR, but IP_RECVDSTADDR is different. Indeed, messages received by recvmsg() are slightly different, but both include 127.0.0.1.` |
|
Why we cannot obtain the original destination address from |
This is a similar symptom to my earlier issue (#1473), but as the circumstances have drastically changed I thought I'd open a new issue. To summarize the changes, I am no longer running
sslocal
on the host (Linux/iptables) machine; it's instead being run on my FreeBSD router which uses pf.Obviously, this requires different firewall rules to work, but there is little if any documentation I could find for transparently proxying via pf within the shadowsocks-rust project. What I've done here is largely guesswork, but this is the rule I came up with to transparently proxy both TCP & UDP to
sslocal
(and then on tossserver
):rdr on $int_if inet proto { tcp, udp } to !<private> -> 127.0.0.1 port 1080
sslocal
is being run on the router via the following command:sslocal -b 127.0.0.1:1080 -U --protocol redir -s 192.168.x.y:8388 -m none --tcp-redir pf --udp-redir pf
...and finally,
ssserver
is run with-U -m none -b 192.168.x.y:8388
This "works" in the sense that both TCP & UDP traffic are being redirected to
sslocal
(unlike in #1473 where only TCP traffic was ever reachingsslocal
), which is then sending the traffic on tosserver
. However, once again, only TCP traffic is being fully proxied correctly.UDP traffic does arrive at
sslocal
without any doubt, as it shows up when runningsslocal
with-vvv
like so (timestamps removed for brevity, and the host system's address being substituted here with simply<host>
):This traffic is then forwarded on to
ssserver
, which I can verify by watching outgoing traffic on the router viatcpdump
. After they arrive atssserver
though, they fail to reach the internet, so clearly something isn't configured correctly.My best guess as to what is happening here, based on the logs, is that
sslocal
thinks the destination of the UDP packet is127.0.0.1
(i.e. the address thatsslocal
is running on and where incoming UDP traffic on the router is redirected to), and fails to retrieve the original destination address before pf'srdr
rule took effect. This wouldn't surprise me as myrdr
rule is complete guesswork, so I assume I'm missing something.If that is indeed the problem, what should the
rdr
rule look like to transparently proxy UDP traffic with pf? Or am I barking up the wrong tree, and is the problem due to something else entirely?The text was updated successfully, but these errors were encountered: