Skip to content
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

Provide local and remote socket addresses from a Connecting #508

Closed
Demi-Marie opened this issue Nov 20, 2019 · 21 comments
Closed

Provide local and remote socket addresses from a Connecting #508

Demi-Marie opened this issue Nov 20, 2019 · 21 comments
Labels
enhancement New feature or request

Comments

@Demi-Marie
Copy link
Contributor

libp2p needs to know the local and remote socket addresses for every incoming connection as soon as the connection is accepted. Is this a feature that you would be willing to include? If so, I will submit a PR.

@Ralith
Copy link
Collaborator

Ralith commented Nov 20, 2019

You can get the local address from Endpoint::local_addr, or just hold onto whatever you passed to EndpointBuilder::bind. We don't have plans to support multiple local addresses, so this should be sufficient, but let us know if it's not.

Exposing the remote address from Connecting makes perfect sense to me. I imagine many applications will want this even just for diagnostics. A PR would be very welcome!

@Ralith
Copy link
Collaborator

Ralith commented Nov 20, 2019

Alternatively, since this doesn't make a lot of sense for outgoing connections, perhaps <Incoming as Stream>::Item could be made into a struct containing Connecting and associated metadata, but my gut feeling is that's less ergonomic for dubious benefit.

@Demi-Marie
Copy link
Contributor Author

Libp2p needs to know the destination IP address of the UDP datagram that initiated the connection. This allows it to publish new addresses at which the local host can be reached. This address is generally different from what was passed to EndpointBuilder::bind if a wildcard address was used for the latter. On Linux, it can be obtained by setting the IPV6_RECVPKTINFO option for IPv6 sockets, or the IP_PKTINFO option for IPv4 sockets.

@Ralith
Copy link
Collaborator

Ralith commented Nov 20, 2019

Ah, good point, I forgot about wildcard IPs. Exposing that makes sense, though it'll require a certain amount of piping, and perhaps attention to win32/macos/BSD compatibility.

@Ralith Ralith added the enhancement New feature or request label Nov 20, 2019
@Demi-Marie
Copy link
Contributor Author

Windows is going to require us to handle sockets ourselves, just as we already do on *nix. I don’t have access to a Windows machine, so I am not particularly comfortable writing this code. I am, however, willing to write an implementation for Linux.

@Ralith
Copy link
Collaborator

Ralith commented Nov 20, 2019

If we're lucky it'll be exactly the same, but obscure cmsg stuff is pretty hit-or-miss portability wise. Linux would be a good start for us to build off of, at least!

@Demi-Marie
Copy link
Contributor Author

Demi-Marie commented Nov 22, 2019

Here is what I have found:

OS Linux FreeBSD OpenBSD NetBSD macOS illumos (and presumably Solaris, AIX, z/OS, etc) Windows
IPv4 destination address IP_PKTINFO IP_RECVDSTADDR IP_RECVDSTADDR all are supported IP_PKTINFO IP_RECVPKTINFO IP_PKTINFO
IPv4 ingress interface IP_PKTINFO IP_RECVIF IP_RECVIF all are supported IP_PKTINFO IP_RECVPKTINFO IP_PKTINFO
IPv6 destination address IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO
IPv6 ingress interface IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO IPV6_RECVPKTINFO

I don’t have access to Solaris, AIX, or any other big iron UNIX docs, so I assumed that they work the same as illumos, as they are all System V derivatives. ? means that I could not find the documentation ― it does not mean that it is not possible.

I believe that we should add this functionality to libstd, async-std, and Tokio, rather than trying to implement it ourselves.

The IPv6 API is standardized in RFC 3542, so it works on all OSs.

@Ralith
Copy link
Collaborator

Ralith commented Nov 22, 2019

Nice work! Do you expect to need interfaces too?

@Demi-Marie
Copy link
Contributor Author

Demi-Marie commented Nov 22, 2019

Probably not right away, although they would be nice to have. I think we should have a crate that abstracts these differences, and then port async-std and tokio to use it.

I can test on Linux and OpenBSD as I have both of those installed. I can probably FreeBSD, NetBSD, and illumos without too much trouble. I do not have access to any of the proprietary OSs, so those will need to be tested by someone else.

@Ralith
Copy link
Collaborator

Ralith commented Nov 22, 2019

Adding support for semi-portable cmsg stuff to foundational libraries is a very tricky engineering problem, particularly when trying to be zero-cost. We're already doing similar things by hand for ECN support and I think continuing in that vein is reasonable.

That said, if you have ideas for how to address this sort of thing more reusably, don't let me stand in your way! I know tokio, at minimum, is receptive to exposing cmsg-related capabilities if a good API can be found.

@Ralith
Copy link
Collaborator

Ralith commented Nov 22, 2019

Bear in mind also that we expect Quinn to continue to dig deeper into esoteric and bleeding-edge platform-specific APIs as part of ongoing performance work, e.g. #501, so any attempt to create a generic "advanced datagram socket" abstraction will have a moving target.

@Demi-Marie
Copy link
Contributor Author

Demi-Marie commented Nov 22, 2019

@Ralith I think io_uring on Linux will be the biggest performance win of them all, at least for APIs that don’t require special privilege. That very much should be incorporated into Tokio and async-std, as it also supports filesystem I/O.

Going faster than that generally requires bypassing the kernel, which requires special privileges. On most systems, such privileges are only available to root.

@Ralith
Copy link
Collaborator

Ralith commented Nov 22, 2019

While io_uring is pretty cool, and I'm strongly supportive of its adoption in general-purpose toolkits, it doesn't solve the problems addressed by segmentation offload.

@Demi-Marie
Copy link
Contributor Author

As far as control messages, I think libraries can provide a thin wrapper around the raw system calls with a reasonable amount of effort. Users would be expected to provide their own buffers.

@Ralith
Copy link
Collaborator

Ralith commented Aug 8, 2020

I think we need this to handle the case where a single socket accepts connections on multiple addresses on the same subnet. Currently, the source address of outgoing packets is not guaranteed to match what the peer expects in that situation. See https://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/ for related discussion.

@Demi-Marie
Copy link
Contributor Author

This is actually less of an issue for QUIC than it is for DNS, since QUIC supports roaming of clients natively. We do need to get this right for servers, though.

@Ralith
Copy link
Collaborator

Ralith commented Aug 8, 2020

Migration can be disabled for a given connection by the server, so even clients may need this.

@zz85
Copy link
Contributor

zz85 commented Dec 16, 2020

I was looking up whether quinn supports IP_PKTINFO and found this issue. @Demi-Marie, just wondering if you had the chance to work on this issue? It seems that one way IP_PKTINFO can be set on socket would be to extend the send_ext and recv_ext methods

@Ralith
Copy link
Collaborator

Ralith commented Dec 19, 2020

That would be the correct approach, yeah.

Matthias247 pushed a commit to Matthias247/quinn that referenced this issue Dec 21, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in quinn-rs#508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
Matthias247 pushed a commit to Matthias247/quinn that referenced this issue Dec 21, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in quinn-rs#508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
@Matthias247
Copy link
Contributor

I have implemented the Linux version of this in #943. It works fine. It might also work on other platforms - but I didn't get to verify this so far, so I haven't enabled the flag on other platforms.

I also have another change which will allow to reuse that particular incoming IP address for all outgoing transmissions on the same connection. But I will park that for another CR.

Matthias247 pushed a commit to Matthias247/quinn that referenced this issue Dec 21, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in quinn-rs#508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
Matthias247 pushed a commit to Matthias247/quinn that referenced this issue Dec 21, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in quinn-rs#508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
Matthias247 pushed a commit to Matthias247/quinn that referenced this issue Dec 21, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in quinn-rs#508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
Matthias247 pushed a commit to Matthias247/quinn that referenced this issue Dec 22, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in quinn-rs#508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
Matthias247 pushed a commit to Matthias247/quinn that referenced this issue Dec 22, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in quinn-rs#508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
Matthias247 pushed a commit to Matthias247/quinn that referenced this issue Dec 27, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in quinn-rs#508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
Matthias247 pushed a commit to Matthias247/quinn that referenced this issue Dec 28, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in quinn-rs#508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
djc pushed a commit that referenced this issue Dec 29, 2020
When a listener is bound to multiple network interfaces (e.g. `::0`),
it is not obvious which IP the peer used to send a packet. We however
might need this information to send packets back to the peer with the
same source address.

This problem is described in #508.

This change makes the destination IP address which was used to send
the initial packet available in the `Conneting` and `Connection` types.

The information is far available only on Linux due to missing test on
other platforms.
@Ralith
Copy link
Collaborator

Ralith commented Nov 5, 2021

Looks like this was fixed by #943.

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

No branches or pull requests

4 participants