-
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
add support for OpenBSD/pf #1567
Conversation
@@ -625,6 +625,8 @@ where | |||
if bypassed { "bypassed" } else { "proxied" }, | |||
err | |||
); | |||
#[cfg(target_os = "openbsd")] | |||
let _ = self.respond_writer.send_to(self.peer_addr, &Address::SocketAddress(SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::new(0,0,0,0)), 0)), data).await; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why OpenBSD needs this "faked" destination address? addr
is the actual address of client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think peer_addr
is client (local) address and addr
is remote address, which is not assigned to sslocal itself, resulting an error (Can't assign requested address, error 49).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not true. send_received_respond_packet
is for sending back packets received from remote server to local client. So:
peer_addr
is the receiver (client)'s addressaddr
is the sender (remote server)'s address
The code in respond_write.send_to
, which is redir/udprelay/mod.rs:UdpRedirInboundWriter::send_to
were doing:
- Create an UDP socket,
bind()
toaddr
- Call
sendto
topeer_addr
This is the way to make an UDP packet that source address is addr
and destination address is peer_addr
.
If socket's bind()
failed right here (EADDRNOTAVAIL
), SO_BINDANY
was not set or working as expected. Setting addr
to 0.0.0.0:0
is actually let system to allocate one for this socket, which is not the expected behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I mistakenly disable set_bindany() function. If I enabled it, the original send_to
worked correctly.
https://man.openbsd.org/getsockopt.2 says that we need divert-reply
along with SO_BINDANY, but in my environment, it seems working correctly without divert-reply
...🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SO_BINDANY
allows socket to bind()
an address that is not belongs to local environment. pf
should be one of the use cases.
@@ -15,7 +15,7 @@ cfg_if! { | |||
#[allow(dead_code, non_upper_case_globals, non_snake_case, non_camel_case_types)] | |||
#[allow(clippy::useless_transmute, clippy::too_many_arguments, clippy::unnecessary_cast)] | |||
mod pfvar; | |||
} else if #[cfg(target_os = "freebsd")] { | |||
} else if #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] { | |||
#[path = "pfvar_bindgen_freebsd.rs"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pfvar_bindgen_freebsd.rs
is generated on FreeBSD. I suggest you to generate one on OpenBSD with bindgen-cli.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah actually, for bindany, I just reversed the comment-out of the old existing code. Maybe that's not working correctly? I'll look into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WRONG COMMENT. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I'm not familiar with this tool, but how can I do this? Is there a commandline for generating this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is pfvar.h
in OpenBSD included in release? If no, you should first download it from its source.
Create a header file, that only has #include <pfvar.h>
.
$ cargo install bindgen-cli
$ bindgen <your_created_header_file> -o pfvar_bindgen_openbsd.rs
More reference: https://rust-lang.github.io/rust-bindgen/command-line-usage.html
What is that |
Ah sorry that's a stack trace... |
And I may be able to add IPv6 support soon. |
You should install an
Run
This project have set some unstable options, which requires nightly Rust. |
Sorry, I can't figure out how to solve this. Do you have any idea? I think I successfully created
but it seems not working... |
There are already some hard-coded constant values for FreeBSD, like shadowsocks-rust/crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/macos.rs Line 167 in 6d7bc35
Should we write pub mod pfvar; instead of mod pfvar and use the constants in udprelay/sys/unix/bsd.rs?
|
The first error indicates that OpenBSD doesn't have If so, IPv6 support on OpenBSD have to be disabled. Those hard-coded constant values exists because they are not defined in libc, so I copied them directly from source. I would suggest to add |
Sorry, I pasted only the part of errors, but similar error happens for libc::IP_RECVDSTPORT. |
It would be great to open an PR to Rust's libc crate and add all those contants. Before it got merge, it is Ok to just hard-coded. All these constants are added by users, so if nobody is actually using it / depend on it, it won't exist in libc. |
Also, I added support for IPv6, but strangely enough, transparent proxying only works every other time. (I don't know detailed conditions) |
crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs
Outdated
Show resolved
Hide resolved
crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs
Outdated
Show resolved
Hide resolved
crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs
Outdated
Show resolved
Hide resolved
crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs
Outdated
Show resolved
Hide resolved
crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/mod.rs
Outdated
Show resolved
Hide resolved
Consider update your branch with the latest master's commits. |
Now I'm working on completing this pull request. |
I would prefer the separation. openbsd and freebsd has too many differences. |
Is it okay if some part of code is shared (copy-pasted) between two xxxxbsd.rs files? (Maybe something is already shared between macos.rs and bsd.rs) |
Your choice. If those features are actually shared between all BSD systems, it could be shared. |
8da6202
to
15d2415
Compare
Now, I
I think I've done all the remaining works (except for the flag issue) |
Current changes look good to me. But the code are not properly formatted. Run |
I applied rustfmt, except for the pfvar file. Is this okay? |
It's Ok. But some of them are still not formatted. |
Oh, sorry, I forgot "git add"... |
Added support for OpenBSD/pf.
In OpenBSD's pf,
divert-to
is used for transparent proxying.As described in https://man.openbsd.org/pf.conf, TCP destination address can be obtained by getsockname() (like Linux+TPROXY or FreeBSD+ipfw), and UDP destination address can be obtained by special socket options like IP_RECVDSTADDR.
send_to
using "fake" source address fails, but using "0.0.0.0:0" instead works. Note that this is not related to IPv4-mapped IPv6 address issue (#1543), because OpenBSD doesn't support IPv4-mapped IPv6 address (https://man.openbsd.org/inet6) and shadowsocks can detect it.Currently IPv6 is not supported. Also,
--features "local-tun"
doesn't work.