shadowsocks-rust icon indicating copy to clipboard operation
shadowsocks-rust copied to clipboard

add support for OpenBSD/pf

Open ge9 opened this issue 1 year ago • 11 comments
trafficstars

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.

ge9 avatar Jun 24 '24 17:06 ge9

What is that ktrace.out file?

zonyitoo avatar Jun 24 '24 17:06 zonyitoo

Ah sorry that's a stack trace... I'll review and resend this PR sorry

ge9 avatar Jun 24 '24 17:06 ge9

And I may be able to add IPv6 support soon.

ge9 avatar Jun 24 '24 17:06 ge9

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.

zonyitoo avatar Jun 25 '24 06:06 zonyitoo

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...

ge9 avatar Jun 25 '24 06:06 ge9

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?

ge9 avatar Jun 25 '24 06:06 ge9

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.

zonyitoo avatar Jun 25 '24 08:06 zonyitoo

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.

ge9 avatar Jun 25 '24 08:06 ge9

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.

zonyitoo avatar Jun 25 '24 09:06 zonyitoo

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.

ge9 avatar Jun 25 '24 10:06 ge9

Consider update your branch with the latest master's commits.

zonyitoo avatar Jun 26 '24 02:06 zonyitoo

Now I'm working on completing this pull request. Should I separate bsd.rs into openbsd.rs and freebsd.rs as you suggested?

ge9 avatar Sep 15 '24 08:09 ge9

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.

zonyitoo avatar Sep 15 '24 15:09 zonyitoo

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)

ge9 avatar Sep 15 '24 16:09 ge9

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.

zonyitoo avatar Sep 16 '24 17:09 zonyitoo

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 tun2 support

I think I've done all the remaining works (except for the flag issue)

ge9 avatar Sep 18 '24 10:09 ge9

Current changes look good to me. But the code are not properly formatted. Run cargo fmt in the root directory and push it again.

zonyitoo avatar Sep 18 '24 15:09 zonyitoo

I applied rustfmt, except for the pfvar file. Is this okay?

ge9 avatar Sep 18 '24 16:09 ge9

I applied rustfmt, except for the pfvar file. Is this okay?

It's Ok. But some of them are still not formatted.

zonyitoo avatar Sep 19 '24 07:09 zonyitoo

Oh, sorry, I forgot "git add"...
I pushed it again. Maybe is it fixed now?

ge9 avatar Sep 19 '24 08:09 ge9