Browse Source

caddyhttp: Fix listener overlap detection on Linux

Sigh, apparently Linux is incapable of distinguishing host interfaces
in socket addresses, even though it works fine on Mac. I suppose we just
have to assume that any listeners with the same port are the same
address, completely ignoring the host interface on Linux... oh well.
master
Matthew Holt 5 years ago
parent
commit
83c85c53f5
No known key found for this signature in database GPG Key ID: 2A349DD577D586A5
  1. 27
      modules/caddyhttp/server.go

27
modules/caddyhttp/server.go

@ -21,6 +21,7 @@ import (
"net"
"net/http"
"net/url"
"runtime"
"strings"
"time"
@ -307,8 +308,30 @@ func (s *Server) hasListenerAddress(fullAddr string) bool {
continue
}
// host must be the same and port must fall within port range
if (thisAddrs.Host == laddrs.Host) &&
// Apparently, Linux requires all bound ports to be distinct
// *regardless of host interface* even if the addresses are
// in fact different; binding "192.168.0.1:9000" and then
// ":9000" will fail for ":9000" because "address is already
// in use" even though it's not, and the same bindings work
// fine on macOS. I also found on Linux that listening on
// "[::]:9000" would fail with a similar error, except with
// the address "0.0.0.0:9000", as if deliberately ignoring
// that I specified the IPv6 interface explicitly. This seems
// to be a major bug in the Linux network stack and I don't
// know why it hasn't been fixed yet, so for now we have to
// special-case ourselves around Linux like a doting parent.
// The second issue seems very similar to a discussion here:
// https://github.com/nodejs/node/issues/9390
//
// This is very easy to reproduce by creating an HTTP server
// that listens to both addresses or just one with a host
// interface; or for a more confusing reproduction, try
// listening on "127.0.0.1:80" and ":443" and you'll see
// the error, if you take away the GOOS condition below.
//
// So, an address is equivalent if the port is in the port
// range, and if not on Linux, the host is the same... sigh.
if (runtime.GOOS == "linux" || thisAddrs.Host == laddrs.Host) &&
(laddrs.StartPort <= thisAddrs.EndPort) &&
(laddrs.StartPort >= thisAddrs.StartPort) {
return true

Loading…
Cancel
Save