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

Use hints with getaddrinfo() in std::net::lookup_host() #34700

Merged
merged 2 commits into from
Jul 9, 2016

Conversation

inejge
Copy link
Contributor

@inejge inejge commented Jul 7, 2016

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:

use std::net::TcpStream;

fn main() {
    let _stream = TcpStream::connect("localhost:4444").unwrap();
}

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

All libstd tests pass with this patch.

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.
@rust-highfive
Copy link
Collaborator

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.

@inejge inejge changed the title Use hints with getaddrinfo() in std::net::lokup_host() Use hints with getaddrinfo() in std::net::lookup_host() Jul 7, 2016
@alexcrichton
Copy link
Member

@bors: r+ 0314d17

Thanks!

cc @rust-lang/libs, seems fine to me but worth ensuring others see as well

@alexcrichton
Copy link
Member

Ah right, another thing, would it be possible to add a test for this as well?

Manishearth added a commit to Manishearth/rust that referenced this pull request Jul 8, 2016
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.
bors added a commit that referenced this pull request Jul 8, 2016
Rollup of 9 pull requests

- Successful merges: #34097, #34456, #34610, #34612, #34659, #34688, #34691, #34699, #34700
- Failed merges:
Manishearth added a commit to Manishearth/rust that referenced this pull request Jul 8, 2016
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.
@inejge
Copy link
Contributor Author

inejge commented Jul 8, 2016

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 lookup_host() returned exactly two addresses, exists because of the behavior of getaddrinfo() on OpenBSD, which, in my testing, returns just the IPv4 addresses if ai_family is unspecified.

bors added a commit that referenced this pull request Jul 8, 2016
Rollup of 9 pull requests

- Successful merges: #34097, #34456, #34610, #34612, #34659, #34688, #34691, #34699, #34700
- Failed merges:
@alexcrichton
Copy link
Member

@bors: r+ 66bf109

@bors
Copy link
Contributor

bors commented Jul 9, 2016

⌛ Testing commit 66bf109 with merge fdca8c2...

bors added a commit that referenced this pull request Jul 9, 2016
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.
@bors bors merged commit 66bf109 into rust-lang:master Jul 9, 2016
@inejge inejge deleted the ai-hints branch July 9, 2016 09:11
@inejge
Copy link
Contributor Author

inejge commented Jul 15, 2016

#24250 can be closed now, I think?

@alexcrichton
Copy link
Member

Indeed, thanks!

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.

4 participants