summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/server.go
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2020-04-26 22:28:49 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2020-04-26 22:28:49 -0600
commit83c85c53f583906e438bb9eb30fc0ab57bf59108 (patch)
tree589313ec6bb0214b8cd50353aa2a6027376bae6b /modules/caddyhttp/server.go
parent768383a610d529e72ccf34b05822c60616cbcada (diff)
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.
Diffstat (limited to 'modules/caddyhttp/server.go')
-rw-r--r--modules/caddyhttp/server.go27
1 files changed, 25 insertions, 2 deletions
diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go
index 05b415c..29a1d2b 100644
--- a/modules/caddyhttp/server.go
+++ b/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