lib/netutil: warn when IPv6 listen address is used without -enableTCP6 (#10640)

### Describe Your Changes

Fixes #6858

### Checklist

The following checks are **mandatory**:

- [x] My change adheres to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/#pull-request-checklist).
- [x] My change adheres to [VictoriaMetrics development
goals](https://docs.victoriametrics.com/victoriametrics/goals/).

---------

Signed-off-by: andriibeee <154226341+andriibeee@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Max Kotliar <mkotlyar@victoriametrics.com>
This commit is contained in:
andriibeee
2026-03-18 21:01:55 +02:00
committed by GitHub
parent fb579cf592
commit e761f22049
4 changed files with 122 additions and 1 deletions

View File

@@ -30,6 +30,7 @@ See also [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-rel
* FEATURE: [dashboards/unused-metrics](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/dashboards/unused-metrics.json): add a new dashboard for exploring stored metrics based on [Caridnality Explorer](https://docs.victoriametrics.com/victoriametrics/#cardinality-explorer) and [ingested metrics usage API](https://docs.victoriametrics.com/victoriametrics/#track-ingested-metrics-usage). The dashboard requires [Infinity Grafana plugin](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) to be installed. See [#10617](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10617) for details.
* FEATURE: [vmalert](https://docs.victoriametrics.com/victoriametrics/vmalert/): add `search` parameter and pagination support in `/api/v1/rules` API. See [#10046](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10046).
* FEATURE: [vmui](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmui): add default pagination to improve the Alerting Rules page experience when vmalert loads thousands of rules. See [#10046](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10046).
* FEATURE: all VictoriaMetrics components: log a warning when an IPv6 listen address (e.g. `[::]:6969`) is specified but `-enableTCP6` is not set. Previously, the server silently listened on IPv4 only. See [#6858](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6858). Thanks to @andriibeee for the contribution.
* BUGFIX: `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): retry RPC by dialing a new connection instead of reusing a pooled one when the previous attempt fails with `io.EOF`, `broken pipe` or `reset by peer`. This reduces query failures caused by stale connections to restarted vmstorage nodes. See [#10314](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10314)
* BUGFIX: [vmui](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmui): fix autocomplete dropdown not closing on the Raw Query page. See [#10665](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/10665)

View File

@@ -26,6 +26,78 @@ func TestIsErrMissingPort(t *testing.T) {
f("http://vmstorage-0.svc.cluster.local.:8080", false)
}
func TestIsLonePort(t *testing.T) {
f := func(s string, expected bool) {
t.Helper()
if isLonePort(s) != expected {
t.Fatalf("unexpected result for %q; got %v; want %v", s, !expected, expected)
}
}
f(":0", true)
f(":1", true)
f(":80", true)
f(":443", true)
f(":666", true)
f(":6969", true)
f(":8080", true)
f(":65535", true)
f(":65536", false)
f(":99999", false)
f("80", false)
f("8080", false)
f("", false)
f(":", false)
f(":123456", false)
f(":abc", false)
f(":80a", false)
f(":12.3", false)
f(":-1", false)
f("127.0.0.1:80", false)
f("[::1]:80", false)
// IPv6 addresses
f("[::1]:80", false)
f("[::]:443", false)
f("[fe80::1]:8080", false)
f("[fe80::1]:8080", false)
f("[2001:db8::1]:9090", false)
f("2606:4700:4700::1111:80", false)
f("[fd00::1:2:3]:8428", false)
// domain names
f("localhost:80", false)
f("example.com:443", false)
f("victoriametrics.com", false)
f("zombo.com", false)
f("theonion.com", false)
f("vmstorage-0:8401", false)
f("vmstorage-0.svc.cluster.local.:8401", false)
f("pee-poo.internal:9090", false)
// full URL
f("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&family=Space+Grotesk:wght@400;600;700&display=swap", false)
// random strings
f("abc", false)
f("my dog got autism", false)
f("IDDQD", false)
f("Galactus", false)
f("hello:world", false)
f("12:34:56", false)
// normal TCPv4 addr
f("1.2.3.4:5", false)
f("0.0.0.0:80", false)
f("1.2.3.4:65535", false)
}
func TestNormalizeAddrSuccess(t *testing.T) {
f := func(addr string, defaultPort int, expected string) {
t.Helper()

View File

@@ -45,6 +45,36 @@ func TestIsTCPv4Addr(t *testing.T) {
// too big port
f("1.2.3.4:152344", false)
// IPv6 addresses
f("[::1]:80", false)
f("[::]:443", false)
f("[fe80::1]:8080", false)
f("[fe80::1]:8080", false)
f("[2001:db8::1]:9090", false)
f("2606:4700:4700::1111:80", false)
f("[fd00::1:2:3]:8428", false)
// domain names
f("localhost:80", false)
f("example.com:443", false)
f("victoriametrics.com", false)
f("zombo.com", false)
f("theonion.com", false)
f("vmstorage-0:8401", false)
f("vmstorage-0.svc.cluster.local.:8401", false)
f("pee-poo.internal:9090", false)
// full URL
f("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&family=Space+Grotesk:wght@400;600;700&display=swap", false)
// random strings
f("abc", false)
f("my dog got autism", false)
f("IDDQD", false)
f("Galactus", false)
f("hello:world", false)
f("12:34:56", false)
// normal TCPv4 addr
f("1.2.3.4:5", true)
f("0.0.0.0:80", true)

View File

@@ -6,6 +6,7 @@ import (
"flag"
"fmt"
"net"
"strconv"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
@@ -14,7 +15,20 @@ import (
var enableTCP6 = flag.Bool("enableTCP6", false, "Whether to enable IPv6 for listening and dialing. By default, only IPv4 TCP and UDP are used")
// NewTCPListener returns new TCP listener for the given addr and optional tlsConfig.
func isLonePort(s string) bool {
n := len(s)
if n < 2 || s[0] != ':' {
return false
}
port, err := strconv.Atoi(s[1:])
if err != nil {
return false
}
return port >= 0 && port <= 65535
}
// NewTCPListener returns a new TCP listener for the given addr and optional tlsConfig.
//
// name is used for metrics. Each listener in the program must have a distinct name.
//
@@ -22,6 +36,10 @@ var enableTCP6 = flag.Bool("enableTCP6", false, "Whether to enable IPv6 for list
// See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
func NewTCPListener(name, addr string, useProxyProtocol bool, tlsConfig *tls.Config) (*TCPListener, error) {
network := GetTCPNetwork()
if network == "tcp4" && !isLonePort(addr) && !isTCPv4Addr(addr) {
logger.Warnf("listening address %q looks like IPv6, but IPv6 is disabled; the server will listen on IPv4 only. "+
"Pass -enableTCP6 command-line flag to enable IPv6 support", addr)
}
ln, err := net.Listen(network, addr)
if err != nil {
return nil, err