From 8fbe5a08939b9078a82db6b2d6c67bd3c21e2529 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 26 Oct 2023 00:29:51 +0200 Subject: [PATCH] lib/promscrape: do not add a suggestion for enabling TCP6 in error message when the dial address is TCPv4 --- lib/promscrape/statconn.go | 43 +++++++++++++++++++++++++-- lib/promscrape/statconn_test.go | 51 +++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 lib/promscrape/statconn_test.go diff --git a/lib/promscrape/statconn.go b/lib/promscrape/statconn.go index 8757342ccd..7aaf285809 100644 --- a/lib/promscrape/statconn.go +++ b/lib/promscrape/statconn.go @@ -4,6 +4,8 @@ import ( "context" "fmt" "net" + "strconv" + "strings" "sync" "sync/atomic" "time" @@ -22,7 +24,7 @@ func statStdDial(ctx context.Context, _, addr string) (net.Conn, error) { dialsTotal.Inc() if err != nil { dialErrors.Inc() - if !netutil.TCP6Enabled() { + if !netutil.TCP6Enabled() && !isTCPv4Addr(addr) { err = fmt.Errorf("%w; try -enableTCP6 command-line flag if you scrape ipv6 addresses", err) } return nil, err @@ -60,7 +62,7 @@ func newStatDialFunc(proxyURL *proxy.URL, ac *promauth.Config) (fasthttp.DialFun dialsTotal.Inc() if err != nil { dialErrors.Inc() - if !netutil.TCP6Enabled() { + if !netutil.TCP6Enabled() && !isTCPv4Addr(addr) { err = fmt.Errorf("%w; try -enableTCP6 command-line flag if you scrape ipv6 addresses", err) } return nil, err @@ -121,3 +123,40 @@ var ( connBytesRead = metrics.NewCounter(`vm_promscrape_conn_bytes_read_total`) connBytesWritten = metrics.NewCounter(`vm_promscrape_conn_bytes_written_total`) ) + +func isTCPv4Addr(addr string) bool { + s := addr + for i := 0; i < 3; i++ { + n := strings.IndexByte(s, '.') + if n < 0 { + return false + } + if !isUint8NumString(s[:n]) { + return false + } + s = s[n+1:] + } + n := strings.IndexByte(s, ':') + if n < 0 { + return false + } + if !isUint8NumString(s[:n]) { + return false + } + s = s[n+1:] + + // Verify TCP port + n, err := strconv.Atoi(s) + if err != nil { + return false + } + return n >= 0 && n < (1<<16) +} + +func isUint8NumString(s string) bool { + n, err := strconv.Atoi(s) + if err != nil { + return false + } + return n >= 0 && n < (1<<8) +} diff --git a/lib/promscrape/statconn_test.go b/lib/promscrape/statconn_test.go new file mode 100644 index 0000000000..37a2ecf3c6 --- /dev/null +++ b/lib/promscrape/statconn_test.go @@ -0,0 +1,51 @@ +package promscrape + +import ( + "testing" +) + +func TestIsTCPv4Addr(t *testing.T) { + f := func(addr string, resultExpected bool) { + t.Helper() + result := isTCPv4Addr(addr) + if result != resultExpected { + t.Fatalf("unexpected result for isIPv4Addr(%q); got %v; want %v", addr, result, resultExpected) + } + } + + // empty addr + f("", false) + + // too small number of octets + f("foobar", false) + f("1", false) + f("1.2", false) + f("1.2.3", false) + f("1.2.3.", false) + + // non-numeric octets + f("foo.bar.baz.aaa", false) + + // non-numeric last value + f("1.2.3.foo", false) + + // negative value + f("1.2.3.-4", false) + + // missing port + f("1.2.3.4", false) + + // invalid port + f("1.2.3.4:foo", false) + + // too big octet + f("1.2.3.444:5", false) + + // too big port + f("1.2.3.4:152344", false) + + // normal TCPv4 addr + f("1.2.3.4:5", true) + f("0.0.0.0:80", true) + f("1.2.3.4:65535", true) +}