shadowsocks-rust
shadowsocks-rust copied to clipboard
add support for OpenBSD/pf
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 (https://github.com/shadowsocks/shadowsocks-rust/issues/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.
What is that ktrace.out file?
Ah sorry that's a stack trace... I'll review and resend this PR sorry
And I may be able to add IPv6 support soon.
You should install an rustfmt, with:
rustup component add rustfmt
rustup component add rustfmt --toolchain nightly
Run rustfmt with:
cargo +nightly fmt
This project have set some unstable options, which requires nightly Rust.
error[E0425]: cannot find value `IPV6_RECVDSTPORT` in crate `libc`
--> crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs:272:37
|
272 | libc::IPPROTO_IPV6 => libc::IPV6_RECVDSTPORT,
| ^^^^^^^^^^^^^^^^ not found in `libc`
|
note: constant `crate::local::redir::sys::unix::pfvar::IPV6_RECVDSTPORT` exists but is inaccessible
--> crates/shadowsocks-service/src/local/redir/sys/unix/pfvar_bindgen_openbsd.rs:589:1
|
589 | pub const IPV6_RECVDSTPORT: u32 = 64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible
Sorry, I can't figure out how to solve this. Do you have any idea?
I think I successfully created pfvar_bindgen_openbsd and specified it in mod.rs
cfg_if! {
if #[cfg(any(target_os = "macos",
target_os = "ios"))] {
#[path = "pfvar_bindgen_macos.rs"]
#[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")] {
#[path = "pfvar_bindgen_freebsd.rs"]
#[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 = "openbsd")] {
#[path = "pfvar_bindgen_openbsd.rs"]
#[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;
}
}
but it seems not working...
There are already some hard-coded constant values for FreeBSD, like https://github.com/shadowsocks/shadowsocks-rust/blob/6d7bc358c11701c7114d877cb0ab2c9e33146db9/crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/macos.rs#L167. So, maybe pfvar_bindgen_freebsd.rs is not actually used either.
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 libc::IPV6_RECVDSTPORT in libc. Is that true? OpenBSD doesn't have IPV6_RECVDSTPORT?
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 IP_DONTFRAG for FreeBSD, OpenBSD independently instead of using the generated pfvar.rs, because they have no relation.
Sorry, I pasted only the part of errors, but similar error happens for libc::IP_RECVDSTPORT.
These constants do exist in OpenBSD's C library, in netinet/in.h, and so included in generated pfvar_xxx.rs, but they seem not defined in Rust's libc.
The situation is exactly the same for IP_DONTFRAG. It's defined in FreeBSD's netinet/in.h and included in pfvar_xxx.rs, but not defined in Rust's libc.
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) I think this is OpenBSD's issue, because shadowsocks with -vvvv doesn't detect any packet.
Consider update your branch with the latest master's commits.
Now I'm working on completing this pull request. Should I separate bsd.rs into openbsd.rs and freebsd.rs as you suggested?
Now I'm working on completing this pull request. Should I separate bsd.rs into openbsd.rs and freebsd.rs as you suggested?
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)
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.
Now, I
- separated bsd.rs into freebsd.rs and openbsd.rs
- defined IP_RECVDSTPORT and IPV6_RECVDSTPORT in the global scope of openbsd.rs (as a temporary fix until these two are supported by
libc) - added a boolean flag to confirm receiving both the address and port. But this still assumes we receive both the address and port only once respectively (in any order). If this is unacceptable, I'll fix it.
- removed
tun2support
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 cargo fmt in the root directory and push it again.
I applied rustfmt, except for the pfvar file. Is this okay?
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"...
I pushed it again. Maybe is it fixed now?