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

What are the best socket option defaults? #72

Closed
njsmith opened this issue Mar 7, 2017 · 2 comments
Closed

What are the best socket option defaults? #72

njsmith opened this issue Mar 7, 2017 · 2 comments

Comments

@njsmith
Copy link
Member

@njsmith njsmith commented Mar 7, 2017

Our default socket configuration is a little different than the classic BSD defaults. Are we making the right choices?

  • SO_REUSEADDR on non-Windows, SO_EXCLUSIVEADDR on Windows: almost certainly correct for listening sockets. More dubious but mostly harmless for client sockets. (See also #39)

    On Windows the other option would be to leave both SO_REUSEADDR and SO_EXCLUSIVEADDR unset, which gives (a) the preferred TIME_WAIT semantics (same as setting SO_REUSEADDR on a Unix system), but also (b) weird socket hijacking issues. (This is what libuv does, e.g.) For now our reasoning is "when in doubt, err on the side of security", but really it would be better to make an actual decision :-). And it's not clear what the best trade-off here is. On recent versions of Windows (including I think all the versions Python officially supports), you can only hijack sockets belonging to the same user, which under the traditional Unix security model would be no big deal – if the process belongs to the same user you could also ptrace it or whatever, and we already have countermeasures against anyone setting SO_REUSEADDR by accident. So maybe the security issue is not worth worrying about in practice. But Windows is not Unix, and even on Unix the traditional security model is not what it used to be (e.g. you probably can't ptrace random other processes these days!), so ... I'm not confident I understand the risks.

    There's also the option of pushing this into the higher-level networking interface (#73), where it knows whether or not it's dealing with a listening socket.

  • IPV6_V6ONLY unset: The important thing is to have a consistent default, because this varies across environments in practice. And I guess unset is a little better than set because it simplifies ipv6 support in simple cases?

  • TCP_NODELAY set: I'm not sure if this is a good idea or not. asyncio sets it by default as well. My suspicion is that having TCP_NODELAY set is a good idea for most serious protocols (latency is important, Nagle sucks for that, most protocols aren't telnet, and hopefully most serious implementations are not hitting the OS with lots of tiny writes and relying on it to fix things up). But Nagle also serves as a safety belt for low-effort implementations, which are the ones that are least likely to override defaults...

  • TCP_NOTSENT_LOWAT set to 16 KiB: well, it's... not obviously wrong? Here we're breaking new ground, so we'll have to see how it goes in practice. This is quite a complicated issue; see #76.

@njsmith
Copy link
Member Author

@njsmith njsmith commented Aug 11, 2017

@oremanj
Copy link
Member

@oremanj oremanj commented Mar 12, 2019

I think this is done:

  • open_tcp_listeners sets SO_REUSEADDR and SO_EXCLUSIVEADDRUSE, and deals with IPv6 correctly
  • SocketStream sets TCP_NOTSENT_LOWAT and TCP_NODELAY
  • we have #928 to track whether SO_EXCLUSIVEADDRUSE is appropriate
  • maybe there's a remaining question of what to do about V6ONLY for client sockets, but I'm pretty sure open_tcp_stream winds up DTRT there by trying IPv4 and IPv6 connections separately
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants