Skip to content

support setting IP_TRANSPARENT on sockets #227

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

Merged
merged 8 commits into from
Apr 30, 2021

Conversation

pepinns
Copy link
Contributor

@pepinns pepinns commented Apr 29, 2021

This allows you to set IP_TRANSPARENT on sockets for linux.

To setup for a local proxy you can use the following:
ref: https://powerdns.org/tproxydoc/tproxy.md.html

    export OUTBOUND_PORT=3100
    export PROXY_PORT=3000
    # move anything marked with a 1 --> table #100
    sudo ip rule add fwmark 1 lookup 100
    # table 100, treat all addrs as local loopback
    sudo ip route add local 0.0.0.0/0 dev lo table 100

    # all inbound traffic on $OUTBOUND_PORT should forward to localhost $PROXY_PORT transparently
    sudo iptables -t mangle -I POSTROUTING -p tcp --dport $OUTBOUND_PORT -j TPROXY --tproxy-mark 0x1/0x1 --on-port=$PROXY_PORT --on-ip=127.0.0.1

    # all output traffic for $OUTBOUND_PORT will get marked and sent to table #100 (loopback)
    sudo iptables -t mangle -A OUTPUT -p tcp -m tcp --dport $OUTBOUND_PORT -j MARK --set-mark 1

Once done, then newly accept()'ed sockets will have the local_addr() set to the originally requested address and not the currently bound listening address.

Copy link
Collaborator

@Thomasdezeeuw Thomasdezeeuw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm Ok with this change, but it needs to be behind the all feature (as it's not available on all OSs) and it needs to be moved and updated with some style changes. I've left some comments, but it shouldn't be too much work.

Copy link
Collaborator

@Thomasdezeeuw Thomasdezeeuw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There a typo in the docs: IP_TRANSPARENTF, otherwise LGTM.

src/socket.rs Outdated
#[cfg(all(feature = "all", target_os = "linux"))]
pub fn ip_transparent(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.inner, sys::IPPROTO_IP, libc::IP_TRANSPARENT)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the CI: can't use self.inner anymore, you need to use self.as_raw().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgive me, happy to change it, but this confuses me and I'd like to understand what's going on.

I don't see as_raw in the source code for this project, is that from somewhere else? What does it do and why would my method need to be different than the others in the file? They appear to be using the same function(s).

Changing self.inner --> self.as_raw() still compiles, but I don't really understand why.
It looks like self.inner is a Socket which is actually a c_int which is a i32.
It also only seems to compile when used in this method, but put into other methods causes a no method named `as_raw` found for reference `&socket::Socket` in the current scope error.

Is there some implementation of as_raw for Socket or c_int somewhere?
my rust-analyzer is choking on this file so thats not really helping me either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it have to do with the feature directive somehow?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is due to #222 which I merged yesterday, e.g. see

socket2/src/socket.rs

Lines 694 to 697 in eaa5f8f

unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_BROADCAST)
.map(|broadcast| broadcast != 0)
}

It's the same as the old .inner, but we now use a TcpStream to take advantage of the niche representation of that type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, rebased the branch against master and things look OK now.

@Thomasdezeeuw Thomasdezeeuw merged commit 3025b85 into rust-lang:master Apr 30, 2021
@Thomasdezeeuw
Copy link
Collaborator

Thanks @pepinns!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants