* chore(deps): bump the go group across 7 directories with 5 updates Bumps the go group with 4 updates in the / directory: [github.com/coder/websocket](https://github.com/coder/websocket), [github.com/docker/docker](https://github.com/docker/docker), [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) and [mvdan.cc/gofumpt](https://github.com/mvdan/gofumpt). Bumps the go group with 2 updates in the /api directory: [github.com/coder/websocket](https://github.com/coder/websocket) and [github.com/hashicorp/boundary/sdk](https://github.com/hashicorp/boundary). Bumps the go group with 1 update in the /plugins/boundary/mains/aws directory: [github.com/hashicorp/boundary/sdk](https://github.com/hashicorp/boundary). Bumps the go group with 1 update in the /plugins/boundary/mains/azure directory: [github.com/hashicorp/boundary/sdk](https://github.com/hashicorp/boundary). Bumps the go group with 1 update in the /plugins/boundary/mains/gcp directory: [github.com/hashicorp/boundary/sdk](https://github.com/hashicorp/boundary). Bumps the go group with 1 update in the /plugins/boundary/mains/minio directory: [github.com/hashicorp/boundary/sdk](https://github.com/hashicorp/boundary). Bumps the go group with 1 update in the /sdk directory: [github.com/coder/websocket](https://github.com/coder/websocket). Updates `github.com/coder/websocket` from 1.8.13 to 1.8.14 - [Release notes](https://github.com/coder/websocket/releases) - [Commits](https://github.com/coder/websocket/compare/v1.8.13...v1.8.14) Updates `github.com/docker/docker` from 28.3.3+incompatible to 28.4.0+incompatible - [Release notes](https://github.com/docker/docker/releases) - [Commits](https://github.com/docker/docker/compare/v28.3.3...v28.4.0) Updates `github.com/prometheus/client_golang` from 1.23.0 to 1.23.2 - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.23.0...v1.23.2) Updates `mvdan.cc/gofumpt` from 0.8.0 to 0.9.0 - [Release notes](https://github.com/mvdan/gofumpt/releases) - [Changelog](https://github.com/mvdan/gofumpt/blob/master/CHANGELOG.md) - [Commits](https://github.com/mvdan/gofumpt/compare/v0.8.0...v0.9.0) Updates `github.com/coder/websocket` from 1.8.13 to 1.8.14 - [Release notes](https://github.com/coder/websocket/releases) - [Commits](https://github.com/coder/websocket/compare/v1.8.13...v1.8.14) Updates `github.com/hashicorp/boundary/sdk` from 0.0.54 to 0.0.55 - [Release notes](https://github.com/hashicorp/boundary/releases) - [Changelog](https://github.com/hashicorp/boundary/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/boundary/compare/api/v0.0.54...api/v0.0.55) Updates `github.com/hashicorp/boundary/sdk` from 0.0.54 to 0.0.55 - [Release notes](https://github.com/hashicorp/boundary/releases) - [Changelog](https://github.com/hashicorp/boundary/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/boundary/compare/api/v0.0.54...api/v0.0.55) Updates `github.com/hashicorp/boundary/sdk` from 0.0.54 to 0.0.55 - [Release notes](https://github.com/hashicorp/boundary/releases) - [Changelog](https://github.com/hashicorp/boundary/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/boundary/compare/api/v0.0.54...api/v0.0.55) Updates `github.com/hashicorp/boundary/sdk` from 0.0.54 to 0.0.55 - [Release notes](https://github.com/hashicorp/boundary/releases) - [Changelog](https://github.com/hashicorp/boundary/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/boundary/compare/api/v0.0.54...api/v0.0.55) Updates `github.com/hashicorp/boundary/sdk` from 0.0.54 to 0.0.55 - [Release notes](https://github.com/hashicorp/boundary/releases) - [Changelog](https://github.com/hashicorp/boundary/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/boundary/compare/api/v0.0.54...api/v0.0.55) Updates `github.com/coder/websocket` from 1.8.13 to 1.8.14 - [Release notes](https://github.com/coder/websocket/releases) - [Commits](https://github.com/coder/websocket/compare/v1.8.13...v1.8.14) --- updated-dependencies: - dependency-name: github.com/coder/websocket dependency-version: 1.8.14 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go - dependency-name: github.com/docker/docker dependency-version: 28.4.0+incompatible dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go - dependency-name: github.com/prometheus/client_golang dependency-version: 1.23.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go - dependency-name: mvdan.cc/gofumpt dependency-version: 0.9.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go - dependency-name: github.com/coder/websocket dependency-version: 1.8.14 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go - dependency-name: github.com/hashicorp/boundary/sdk dependency-version: 0.0.55 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go - dependency-name: github.com/hashicorp/boundary/sdk dependency-version: 0.0.55 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go - dependency-name: github.com/hashicorp/boundary/sdk dependency-version: 0.0.55 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go - dependency-name: github.com/hashicorp/boundary/sdk dependency-version: 0.0.55 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go - dependency-name: github.com/hashicorp/boundary/sdk dependency-version: 0.0.55 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go - dependency-name: github.com/coder/websocket dependency-version: 1.8.14 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go ... Signed-off-by: dependabot[bot] <support@github.com> * Format files with latest gofumpt --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
152 lines
6.6 KiB
Go
152 lines
6.6 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package util
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
|
)
|
|
|
|
const (
|
|
// MinAddressLength is the minimum length for an address.
|
|
MinAddressLength = 3
|
|
// MaxAddressLength is the maximum length for an address.
|
|
MaxAddressLength = 255
|
|
)
|
|
|
|
var (
|
|
// ErrMissingPort is returned from SplitHostPort when the underlying
|
|
// net.SplitHostPort call detects the input did not contain a port. This is
|
|
// the case for an input like "127.0.0.1" (but not "127.0.0.1:").
|
|
ErrMissingPort = errors.New("missing port in address")
|
|
// ErrTooManyColons is returned from SplitHostPort when the underlying
|
|
// net.SplitHostPort call detects the input has more colons than it is
|
|
// expected to have. This is the case for an input like
|
|
// "127.0.0.1:1010:1010".
|
|
ErrTooManyColons = errors.New("too many colons in address")
|
|
// ErrMissingRBracket is returned from SplitHostPort when the underlying
|
|
// net.SplitHostPort call detects an input that starts with '[' but has no
|
|
// corresponding ']' closing bracket. This is the case for an input like
|
|
// "[::1:9090".
|
|
ErrMissingRBracket = errors.New("missing ']' in address")
|
|
// ErrUnexpectedLBracket is returned from SplitHostPort when the underlying
|
|
// net.SplitHostPort call detects an input that has an unexpected '['
|
|
// character where it is not supposed to be. This is the case for an input
|
|
// like "127.0.[0.1:9090" or "[[127.0.0.1]:9090" (but not
|
|
// "[127.0.0.1]:9090").
|
|
ErrUnexpectedLBracket = errors.New("unexpected '[' in address")
|
|
// ErrUnexpectedRBracket is returned from SplitHostPort when the underlying
|
|
// net.SplitHostPort call detects an input that has an unexpected ']'
|
|
// character where it is not supposed to be. This is the case for an input
|
|
// like "127.0.]0.1:9090" or "127.0.0.1]:9090" (but not "[127.0.0.1]:9090").
|
|
ErrUnexpectedRBracket = errors.New("unexpected ']' in address")
|
|
|
|
// ErrInvalidAddressLength is returned when an address input is not within
|
|
// defined lengths (see MinAddressLength and MaxAddressLength).
|
|
ErrInvalidAddressLength = errors.New("invalid address length")
|
|
// ErrInvalidAddressContainsPort is returned when an address input contains
|
|
// a port.
|
|
ErrInvalidAddressContainsPort = errors.New("address contains a port")
|
|
)
|
|
|
|
// This regular expression is used to find all instances of square brackets within a string.
|
|
// This regular expression is used to remove the square brackets from an IPv6 address.
|
|
var squareBrackets = regexp.MustCompile("\\[|\\]")
|
|
|
|
// JoinHostPort combines host and port into a network address of the form "host:port".
|
|
// If host contains a colon, as found in literal IPv6 addresses, then JoinHostPort returns "[host]:port".
|
|
func JoinHostPort(host, port string) string {
|
|
host = squareBrackets.ReplaceAllString(host, "")
|
|
return net.JoinHostPort(host, port)
|
|
}
|
|
|
|
// SplitHostPort splits a network address of the form "host:port",
|
|
// "host%zone:port", "[host]:port" or "[host%zone]:port" into separate "host" or
|
|
// "host%zone" and "port". It differs from its standard library counterpart in
|
|
// the following ways:
|
|
// - If the input is an IP address (with no port), this function will return
|
|
// that IP as the `host`, empty `port`, and ErrMissingPort.
|
|
// - If the input is just a host (with no port), this function will return
|
|
// that host as the `host`, empty `port`, and ErrMissingPort.
|
|
//
|
|
// These changes enable inputs like "ip_address" or "host" and allows callers to
|
|
// detect whether any given `hostport` contains a port or is just a host/IP.
|
|
func SplitHostPort(hostport string) (host string, port string, err error) {
|
|
// In case `hostport` is just an ip, we can grab that early.
|
|
if ip := net.ParseIP(hostport); ip != nil {
|
|
// If ParseIP successfully parsed it, it means `hostport` does not have
|
|
// a port (or is a malformed IPv6 address like "::1:1234").
|
|
host = ip.String()
|
|
err = ErrMissingPort
|
|
return host, port, err
|
|
}
|
|
|
|
// At this time, we don't necessarily know that `hostport` is a string
|
|
// composed of a host and a port, however net.SplitHostPort will error if
|
|
// that is not the case.
|
|
host, port, err = net.SplitHostPort(hostport)
|
|
if err != nil {
|
|
addrErr := new(net.AddrError)
|
|
isAddrErr := errors.As(err, &addrErr)
|
|
if !isAddrErr {
|
|
return host, port, err
|
|
}
|
|
|
|
// Since net.SplitHostPort does not type the error reason, we'll handle
|
|
// that here to simplify logic in callers of this function. Note that
|
|
// while this list covers every error state in net.SplitHostPort up to
|
|
// Go 1.24.1, error reasons might expand over time.
|
|
// See: https://cs.opensource.google/go/go/+/refs/tags/go1.24.1:src/net/ipsock.go;l=165-218
|
|
const (
|
|
stdlibErrReasonMissingPort = "missing port in address"
|
|
stdlibErrReasonTooManyColons = "too many colons in address"
|
|
stdlibErrReasonMissingRBracket = "missing ']' in address"
|
|
stdlibErrReasonUnexpectedLBracket = "unexpected '[' in address"
|
|
stdlibErrReasonUnexpectedRBracket = "unexpected ']' in address"
|
|
)
|
|
switch {
|
|
case strings.Contains(addrErr.Err, stdlibErrReasonMissingPort):
|
|
// In case the `hostport` value is an IPv6 address, we must remove
|
|
// the brackets (if they exist) to retain the same behavior as
|
|
// net.SplitHostPort. This case wouldn't be caught by net.ParseIP
|
|
// because "[ipv6_address]" is not a valid input to that function.
|
|
host = squareBrackets.ReplaceAllString(hostport, "")
|
|
err = ErrMissingPort
|
|
case strings.Contains(addrErr.Err, stdlibErrReasonTooManyColons):
|
|
err = ErrTooManyColons
|
|
case strings.Contains(addrErr.Err, stdlibErrReasonMissingRBracket):
|
|
err = ErrMissingRBracket
|
|
case strings.Contains(addrErr.Err, stdlibErrReasonUnexpectedLBracket):
|
|
err = ErrUnexpectedLBracket
|
|
case strings.Contains(addrErr.Err, stdlibErrReasonUnexpectedRBracket):
|
|
err = ErrUnexpectedRBracket
|
|
}
|
|
}
|
|
|
|
return host, port, err
|
|
}
|
|
|
|
// ParseAddress trims and validates the input address string. It checks whether
|
|
// the address is within the allowed length and attempts to split it into a host and
|
|
// port. If the address contains a port, it returns an error. The function supports
|
|
// both valid IP addresses (IPv4 or IPv6) and DNS names. If the address is valid
|
|
// and does not include a port, it returns the host (either an IP or a DNS name).
|
|
func ParseAddress(ctx context.Context, address string) (string, error) {
|
|
const op = "util.ParseAddress"
|
|
address = strings.TrimSpace(address)
|
|
if len(address) < MinAddressLength || len(address) > MaxAddressLength {
|
|
return "", ErrInvalidAddressLength
|
|
}
|
|
_, port, _ := SplitHostPort(address)
|
|
if port != "" {
|
|
return "", ErrInvalidAddressContainsPort
|
|
}
|
|
return parseutil.NormalizeAddr(address)
|
|
}
|