From 93bc1b72e3cd566e6447ad7a1f832474aad5dfcc Mon Sep 17 00:00:00 2001 From: Mohammed Al Sahaf Date: Tue, 12 Nov 2019 01:33:38 +0300 Subject: core: Use port ranges to avoid OOM with bad inputs (#2859) * fix OOM issue caught by fuzzing * use ParsedAddress as the struct name for the result of ParseNetworkAddress * simplify code using the ParsedAddress type * minor cleanups --- modules/caddyhttp/caddyhttp.go | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'modules/caddyhttp/caddyhttp.go') diff --git a/modules/caddyhttp/caddyhttp.go b/modules/caddyhttp/caddyhttp.go index 99a64c3..36d8154 100644 --- a/modules/caddyhttp/caddyhttp.go +++ b/modules/caddyhttp/caddyhttp.go @@ -135,15 +135,18 @@ func (app *App) Validate() error { lnAddrs := make(map[string]string) for srvName, srv := range app.Servers { for _, addr := range srv.Listen { - netw, expanded, err := caddy.ParseNetworkAddress(addr) + listenAddr, err := caddy.ParseNetworkAddress(addr) if err != nil { return fmt.Errorf("invalid listener address '%s': %v", addr, err) } - for _, a := range expanded { - if sn, ok := lnAddrs[netw+a]; ok { - return fmt.Errorf("server %s: listener address repeated: %s (already claimed by server '%s')", srvName, a, sn) + // check that every address in the port range is unique to this server; + // we do not use <= here because PortRangeSize() adds 1 to EndPort for us + for i := uint(0); i < listenAddr.PortRangeSize(); i++ { + addr := caddy.JoinNetworkAddress(listenAddr.Network, listenAddr.Host, strconv.Itoa(int(listenAddr.StartPort+i))) + if sn, ok := lnAddrs[addr]; ok { + return fmt.Errorf("server %s: listener address repeated: %s (already claimed by server '%s')", srvName, addr, sn) } - lnAddrs[netw+a] = srvName + lnAddrs[addr] = srvName } } } @@ -176,14 +179,15 @@ func (app *App) Start() error { } for _, lnAddr := range srv.Listen { - network, addrs, err := caddy.ParseNetworkAddress(lnAddr) + listenAddr, err := caddy.ParseNetworkAddress(lnAddr) if err != nil { return fmt.Errorf("%s: parsing listen address '%s': %v", srvName, lnAddr, err) } - for _, addr := range addrs { - ln, err := caddy.Listen(network, addr) + for i := uint(0); i <= listenAddr.PortRangeSize(); i++ { + hostport := listenAddr.JoinHostPort(i) + ln, err := caddy.Listen(listenAddr.Network, hostport) if err != nil { - return fmt.Errorf("%s: listening on %s: %v", network, addr, err) + return fmt.Errorf("%s: listening on %s: %v", listenAddr.Network, hostport, err) } // enable HTTP/2 by default @@ -194,11 +198,10 @@ func (app *App) Start() error { } // enable TLS - _, port, _ := net.SplitHostPort(addr) - if len(srv.TLSConnPolicies) > 0 && port != strconv.Itoa(app.httpPort()) { + if len(srv.TLSConnPolicies) > 0 && int(i) != app.httpPort() { tlsCfg, err := srv.TLSConnPolicies.TLSConfig(app.ctx) if err != nil { - return fmt.Errorf("%s/%s: making TLS configuration: %v", network, addr, err) + return fmt.Errorf("%s/%s: making TLS configuration: %v", listenAddr.Network, hostport, err) } ln = tls.NewListener(ln, tlsCfg) @@ -206,15 +209,15 @@ func (app *App) Start() error { // TODO: HTTP/3 support is experimental for now if srv.ExperimentalHTTP3 { app.logger.Info("enabling experimental HTTP/3 listener", - zap.String("addr", addr), + zap.String("addr", hostport), ) - h3ln, err := caddy.ListenPacket("udp", addr) + h3ln, err := caddy.ListenPacket("udp", hostport) if err != nil { return fmt.Errorf("getting HTTP/3 UDP listener: %v", err) } h3srv := &http3.Server{ Server: &http.Server{ - Addr: addr, + Addr: hostport, Handler: srv, TLSConfig: tlsCfg, }, -- cgit v1.2.3