VictoriaMetrics/lib/netutil/netutil.go
LHHDZ 3a45bbb4e0
app/vmauth: fix discovering backend IPs when url_prefix contains hostname with srv+ prefix (#6401)
This change fixes the following panic:
```
2024-06-04T11:16:52.899Z        warn    app/vmauth/auth_config.go:353   cannot discover backend SRV records for http://srv+localhost:8080: lookup localhost on 10.100.10.4:53: server misbehaving; use it literally
panic: runtime error: integer divide by zero

goroutine 9 [running]:
github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver.handlerWrapper.func1()
        /Users/lhhdz/wd/projects/go/VictoriaMetrics/lib/httpserver/httpserver.go:291 +0x58
panic({0x103115100?, 0x10338d700?})
        /Users/lhhdz/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.3.darwin-arm64/src/runtime/panic.go:770 +0x124
main.getLeastLoadedBackendURL({0x0?, 0x22?, 0x1400014757b?}, 0x1400013c120?)
        /Users/lhhdz/wd/projects/go/VictoriaMetrics/app/vmauth/auth_config.go:473 +0x210
main.(*URLPrefix).getBackendURL(0x140000aa080)
        /Users/lhhdz/wd/projects/go/VictoriaMetrics/app/vmauth/auth_config.go:312 +0xb8
```

---------

Co-authored-by: Haley Wang <haley@victoriametrics.com>
2024-06-12 12:30:44 +02:00

68 lines
1.9 KiB
Go

package netutil
import (
"context"
"fmt"
"math/rand"
"net"
"strings"
"time"
)
type resolver interface {
LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error)
LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)
LookupMX(ctx context.Context, name string) ([]*net.MX, error)
}
// Resolver is default DNS resolver.
var Resolver resolver
func init() {
Resolver = &net.Resolver{
PreferGo: true,
StrictErrors: true,
}
}
// IsTrivialNetworkError returns true if the err can be ignored during logging.
func IsTrivialNetworkError(err error) bool {
// Suppress trivial network errors, which could occur at remote side.
s := err.Error()
if strings.Contains(s, "broken pipe") || strings.Contains(s, "reset by peer") {
return true
}
return false
}
// DialMaybeSRV dials the given addr.
//
// The addr may be either the usual TCP address or srv+host form, where host is SRV addr.
// If the addr has srv+host form, then the host is resolved with SRV into randomly chosen TCP address for the connection.
func DialMaybeSRV(ctx context.Context, network, addr string) (net.Conn, error) {
if strings.HasPrefix(addr, "srv+") {
addr = strings.TrimPrefix(addr, "srv+")
if n := strings.IndexByte(addr, ':'); n >= 0 {
// Drop port, since it should be automatically resolved via DNS SRV lookup below.
addr = addr[:n]
}
_, addrs, err := Resolver.LookupSRV(ctx, "", "", addr)
if err != nil {
return nil, fmt.Errorf("cannot resolve SRV addr %s: %w", addr, err)
}
if len(addrs) == 0 {
return nil, fmt.Errorf("missing SRV records for %s", addr)
}
n := rand.Intn(len(addrs))
addr = fmt.Sprintf("%s:%d", addrs[n].Target, addrs[n].Port)
}
return Dialer.DialContext(ctx, network, addr)
}
// Dialer is default network dialer.
var Dialer = &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: TCP6Enabled(),
}