-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Use hints with getaddrinfo() in std::net::lookup_host() #34700
Conversation
When resolving a hostname, pass a hints struct where ai_socktype is set to SOCK_STREAM in order to eliminate repeated results for each protocol family.
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
Ah right, another thing, would it be possible to add a test for this as well? |
Use hints with getaddrinfo() in std::net::lookup_host() As noted in rust-lang#24250, `std::net::lookup_host()` repeats each IPv[46] address in the result set. The number of repetitions is OS-dependent; e.g., Linux and FreeBSD give three copies, OpenBSD gives two. Filtering the duplicates can be done by the user if `lookup_host()` is used explicitly, but not with functions like `TcpStream::connect()`. What happens with the latter is that any unsuccessful connection attempt will be repeated as many times as there are duplicates of the address. The program: ```rust use std::net::TcpStream; fn main() { let _stream = TcpStream::connect("localhost:4444").unwrap(); } ``` results in the following capture: [capture-before.txt](https://github.com/rust-lang/rust/files/352004/capture-before.txt) assuming that "localhost" resolves both to ::1 and 127.0.0.1, and that the listening program opens just an IPv4 socket (e.g., `nc -l 127.0.0.1 4444`.) The reason for this behavior is explained in [this comment](rust-lang#24250 (comment)): `getaddrinfo()` is not constrained. Various OSS projects (I checked out Postfix, OpenLDAP, Apache HTTPD and BIND) which use `getaddrinfo()` generally constrain the result set by using a non-NULL `hints` parameter and setting at least `ai_socktype` to `SOCK_STREAM`. `SOCK_DGRAM` would also work. Other parameters are unnecessary for pure name resolution. The patch in this PR initializes a `hints` struct and passes it to `getaddrinfo()`, which eliminates the duplicates. The same test program as above with this change produces: [capture-after.txt](https://github.com/rust-lang/rust/files/352042/capture-after.txt) All `libstd` tests pass with this patch.
Use hints with getaddrinfo() in std::net::lookup_host() As noted in rust-lang#24250, `std::net::lookup_host()` repeats each IPv[46] address in the result set. The number of repetitions is OS-dependent; e.g., Linux and FreeBSD give three copies, OpenBSD gives two. Filtering the duplicates can be done by the user if `lookup_host()` is used explicitly, but not with functions like `TcpStream::connect()`. What happens with the latter is that any unsuccessful connection attempt will be repeated as many times as there are duplicates of the address. The program: ```rust use std::net::TcpStream; fn main() { let _stream = TcpStream::connect("localhost:4444").unwrap(); } ``` results in the following capture: [capture-before.txt](https://github.com/rust-lang/rust/files/352004/capture-before.txt) assuming that "localhost" resolves both to ::1 and 127.0.0.1, and that the listening program opens just an IPv4 socket (e.g., `nc -l 127.0.0.1 4444`.) The reason for this behavior is explained in [this comment](rust-lang#24250 (comment)): `getaddrinfo()` is not constrained. Various OSS projects (I checked out Postfix, OpenLDAP, Apache HTTPD and BIND) which use `getaddrinfo()` generally constrain the result set by using a non-NULL `hints` parameter and setting at least `ai_socktype` to `SOCK_STREAM`. `SOCK_DGRAM` would also work. Other parameters are unnecessary for pure name resolution. The patch in this PR initializes a `hints` struct and passes it to `getaddrinfo()`, which eliminates the duplicates. The same test program as above with this change produces: [capture-after.txt](https://github.com/rust-lang/rust/files/352042/capture-after.txt) All `libstd` tests pass with this patch.
I've added a test for (lack of) duplicates. It tries to resolve "localhost", which should exist on any reasonable system. The complication of counting the number of instances of each returned addres type, then asserting that no type has more than one instance, instead of just checking that |
Use hints with getaddrinfo() in std::net::lookup_host() As noted in #24250, `std::net::lookup_host()` repeats each IPv[46] address in the result set. The number of repetitions is OS-dependent; e.g., Linux and FreeBSD give three copies, OpenBSD gives two. Filtering the duplicates can be done by the user if `lookup_host()` is used explicitly, but not with functions like `TcpStream::connect()`. What happens with the latter is that any unsuccessful connection attempt will be repeated as many times as there are duplicates of the address. The program: ```rust use std::net::TcpStream; fn main() { let _stream = TcpStream::connect("localhost:4444").unwrap(); } ``` results in the following capture: [capture-before.txt](https://github.com/rust-lang/rust/files/352004/capture-before.txt) assuming that "localhost" resolves both to ::1 and 127.0.0.1, and that the listening program opens just an IPv4 socket (e.g., `nc -l 127.0.0.1 4444`.) The reason for this behavior is explained in [this comment](#24250 (comment)): `getaddrinfo()` is not constrained. Various OSS projects (I checked out Postfix, OpenLDAP, Apache HTTPD and BIND) which use `getaddrinfo()` generally constrain the result set by using a non-NULL `hints` parameter and setting at least `ai_socktype` to `SOCK_STREAM`. `SOCK_DGRAM` would also work. Other parameters are unnecessary for pure name resolution. The patch in this PR initializes a `hints` struct and passes it to `getaddrinfo()`, which eliminates the duplicates. The same test program as above with this change produces: [capture-after.txt](https://github.com/rust-lang/rust/files/352042/capture-after.txt) All `libstd` tests pass with this patch.
#24250 can be closed now, I think? |
Indeed, thanks! |
As noted in #24250,
std::net::lookup_host()
repeats each IPv[46] address in the result set. The number of repetitions is OS-dependent; e.g., Linux and FreeBSD give three copies, OpenBSD gives two. Filtering the duplicates can be done by the user iflookup_host()
is used explicitly, but not with functions likeTcpStream::connect()
. What happens with the latter is that any unsuccessful connection attempt will be repeated as many times as there are duplicates of the address.The program:
results in the following capture:
capture-before.txt
assuming that "localhost" resolves both to ::1 and 127.0.0.1, and that the listening program opens just an IPv4 socket (e.g.,
nc -l 127.0.0.1 4444
.) The reason for this behavior is explained in this comment:getaddrinfo()
is not constrained.Various OSS projects (I checked out Postfix, OpenLDAP, Apache HTTPD and BIND) which use
getaddrinfo()
generally constrain the result set by using a non-NULLhints
parameter and setting at leastai_socktype
toSOCK_STREAM
.SOCK_DGRAM
would also work. Other parameters are unnecessary for pure name resolution.The patch in this PR initializes a
hints
struct and passes it togetaddrinfo()
, which eliminates the duplicates. The same test program as above with this change produces:capture-after.txt
All
libstd
tests pass with this patch.