Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dns: Support link local IPv6 addresses #7889

Merged
merged 3 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions balancer/pickfirst/pickfirstleaf/pickfirstleaf.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"errors"
"fmt"
"net"
"net/netip"
"sync"
"time"

Expand Down Expand Up @@ -417,11 +418,14 @@ func addressFamily(address string) ipAddrFamily {
if err != nil {
return ipAddrFamilyUnknown
}
ip := net.ParseIP(host)
ip, err := netip.ParseAddr(host)
if err != nil {
return ipAddrFamilyUnknown
}
switch {
case ip.To4() != nil:
case ip.Is4() || ip.Is4In6():
return ipAddrFamilyV4
case ip.To16() != nil:
case ip.Is6():
return ipAddrFamilyV6
default:
return ipAddrFamilyUnknown
Expand Down
12 changes: 6 additions & 6 deletions balancer/pickfirst/pickfirstleaf/pickfirstleaf_ext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ func (s) TestPickFirstLeaf_InterleavingIPV4Preffered(t *testing.T) {
{Addresses: []resolver.Address{{Addr: "[::FFFF:192.168.0.1]:2222"}}},
{Addresses: []resolver.Address{{Addr: "[0001:0001:0001:0001:0001:0001:0001:0001]:8080"}}},
{Addresses: []resolver.Address{{Addr: "[0002:0002:0002:0002:0002:0002:0002:0002]:8080"}}},
{Addresses: []resolver.Address{{Addr: "[0003:0003:0003:0003:0003:0003:0003:0003]:3333"}}},
{Addresses: []resolver.Address{{Addr: "[fe80::1%eth0]:3333"}}},
{Addresses: []resolver.Address{{Addr: "grpc.io:80"}}}, // not an IP.
},
},
Expand All @@ -1107,7 +1107,7 @@ func (s) TestPickFirstLeaf_InterleavingIPV4Preffered(t *testing.T) {
{Addr: "2.2.2.2:2"},
{Addr: "[0002:0002:0002:0002:0002:0002:0002:0002]:8080"},
{Addr: "3.3.3.3:3"},
{Addr: "[0003:0003:0003:0003:0003:0003:0003:0003]:3333"},
{Addr: "[fe80::1%eth0]:3333"},
{Addr: "[::FFFF:192.168.0.1]:2222"},
}

Expand Down Expand Up @@ -1135,7 +1135,7 @@ func (s) TestPickFirstLeaf_InterleavingIPv6Preffered(t *testing.T) {
{Addresses: []resolver.Address{{Addr: "3.3.3.3:3"}}},
{Addresses: []resolver.Address{{Addr: "[::FFFF:192.168.0.1]:2222"}}},
{Addresses: []resolver.Address{{Addr: "[0002:0002:0002:0002:0002:0002:0002:0002]:2222"}}},
{Addresses: []resolver.Address{{Addr: "[0003:0003:0003:0003:0003:0003:0003:0003]:3333"}}},
{Addresses: []resolver.Address{{Addr: "[fe80::1%eth0]:3333"}}},
{Addresses: []resolver.Address{{Addr: "grpc.io:80"}}}, // not an IP.
},
},
Expand All @@ -1150,7 +1150,7 @@ func (s) TestPickFirstLeaf_InterleavingIPv6Preffered(t *testing.T) {
{Addr: "grpc.io:80"},
{Addr: "[0002:0002:0002:0002:0002:0002:0002:0002]:2222"},
{Addr: "2.2.2.2:2"},
{Addr: "[0003:0003:0003:0003:0003:0003:0003:0003]:3333"},
{Addr: "[fe80::1%eth0]:3333"},
{Addr: "3.3.3.3:3"},
{Addr: "[::FFFF:192.168.0.1]:2222"},
}
Expand Down Expand Up @@ -1180,7 +1180,7 @@ func (s) TestPickFirstLeaf_InterleavingUnknownPreffered(t *testing.T) {
{Addresses: []resolver.Address{{Addr: "[::FFFF:192.168.0.1]:2222"}}},
{Addresses: []resolver.Address{{Addr: "[0001:0001:0001:0001:0001:0001:0001:0001]:8080"}}},
{Addresses: []resolver.Address{{Addr: "[0002:0002:0002:0002:0002:0002:0002:0002]:8080"}}},
{Addresses: []resolver.Address{{Addr: "[0003:0003:0003:0003:0003:0003:0003:0003]:3333"}}},
{Addresses: []resolver.Address{{Addr: "[fe80::1%eth0]:3333"}}},
{Addresses: []resolver.Address{{Addr: "example.com:80"}}}, // not an IP.
},
},
Expand All @@ -1197,7 +1197,7 @@ func (s) TestPickFirstLeaf_InterleavingUnknownPreffered(t *testing.T) {
{Addr: "2.2.2.2:2"},
{Addr: "[0002:0002:0002:0002:0002:0002:0002:0002]:8080"},
{Addr: "3.3.3.3:3"},
{Addr: "[0003:0003:0003:0003:0003:0003:0003:0003]:3333"},
{Addr: "[fe80::1%eth0]:3333"},
{Addr: "[::FFFF:192.168.0.1]:2222"},
}

Expand Down
11 changes: 6 additions & 5 deletions channelz/service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"context"
"fmt"
"net"
"net/netip"
"strconv"
"strings"
"testing"
Expand Down Expand Up @@ -605,8 +606,8 @@ func (s) TestGetSocket(t *testing.T) {
lastMessageReceivedTimestamp: time.Unix(3, 0),
localFlowControlWindow: 65536,
remoteFlowControlWindow: 1024,
localAddr: &net.TCPAddr{IP: net.ParseIP("1.0.0.1"), Port: 10001},
remoteAddr: &net.TCPAddr{IP: net.ParseIP("12.0.0.1"), Port: 10002},
localAddr: &net.TCPAddr{IP: netip.MustParseAddr("1.0.0.1").AsSlice(), Port: 10001},
remoteAddr: &net.TCPAddr{IP: netip.MustParseAddr("12.0.0.1").AsSlice(), Port: 10002},
remoteName: "remote.remote",
}), newSocket(czSocket{
streamsStarted: 10,
Expand Down Expand Up @@ -637,11 +638,11 @@ func (s) TestGetSocket(t *testing.T) {
lastMessageReceivedTimestamp: time.Unix(0, 0),
localFlowControlWindow: 65536,
remoteFlowControlWindow: 10240,
localAddr: &net.IPAddr{IP: net.ParseIP("1.0.0.1")},
remoteAddr: &net.IPAddr{IP: net.ParseIP("9.0.0.1")},
localAddr: &net.IPAddr{IP: netip.MustParseAddr("1.0.0.1").AsSlice()},
remoteAddr: &net.IPAddr{IP: netip.MustParseAddr("9.0.0.1").AsSlice()},
remoteName: "",
}), newSocket(czSocket{
localAddr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 10001},
localAddr: &net.TCPAddr{IP: netip.MustParseAddr("127.0.0.1").AsSlice(), Port: 10001},
}), newSocket(czSocket{
security: &credentials.TLSChannelzSecurityValue{
StandardName: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
Expand Down
15 changes: 11 additions & 4 deletions internal/credentials/xds/handshake_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package xds
import (
"crypto/x509"
"net"
"net/netip"
"net/url"
"regexp"
"testing"
Expand Down Expand Up @@ -142,8 +143,11 @@ func TestMatchingSANExists_FailureCases(t *testing.T) {
inputCert := &x509.Certificate{
DNSNames: []string{"foo.bar.example.com", "bar.baz.test.com", "*.example.com"},
EmailAddresses: []string{"foobar@example.com", "barbaz@test.com"},
IPAddresses: []net.IP{net.ParseIP("192.0.0.1"), net.ParseIP("2001:db8::68")},
URIs: []*url.URL{url1, url2},
IPAddresses: []net.IP{
netip.MustParseAddr("192.0.0.1").AsSlice(),
netip.MustParseAddr("2001:db8::68").AsSlice(),
},
URIs: []*url.URL{url1, url2},
}

tests := []struct {
Expand Down Expand Up @@ -214,8 +218,11 @@ func TestMatchingSANExists_Success(t *testing.T) {
inputCert := &x509.Certificate{
DNSNames: []string{"baz.test.com", "*.example.com"},
EmailAddresses: []string{"foobar@example.com", "barbaz@test.com"},
IPAddresses: []net.IP{net.ParseIP("192.0.0.1"), net.ParseIP("2001:db8::68")},
URIs: []*url.URL{url1, url2},
IPAddresses: []net.IP{
netip.MustParseAddr("192.0.0.1").AsSlice(),
netip.MustParseAddr("2001:db8::68").AsSlice(),
},
URIs: []*url.URL{url1, url2},
}

tests := []struct {
Expand Down
37 changes: 19 additions & 18 deletions internal/resolver/dns/dns_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"fmt"
rand "math/rand/v2"
"net"
"net/netip"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -122,7 +123,7 @@
}

// IP address.
if ipAddr, ok := formatIP(host); ok {
if ipAddr, err := formatIP(host); err == nil {
addr := []resolver.Address{{Addr: ipAddr + ":" + port}}
cc.UpdateState(resolver.State{Addresses: addr})
return deadResolver{}, nil
Expand Down Expand Up @@ -260,9 +261,9 @@
return nil, err
}
for _, a := range lbAddrs {
ip, ok := formatIP(a)
if !ok {
return nil, fmt.Errorf("dns: error parsing A record IP address %v", a)
ip, err := formatIP(a)
if err != nil {
return nil, fmt.Errorf("dns: error parsing A record IP address %v: %v", a, err)

Check warning on line 266 in internal/resolver/dns/dns_resolver.go

View check run for this annotation

Codecov / codecov/patch

internal/resolver/dns/dns_resolver.go#L266

Added line #L266 was not covered by tests
}
addr := ip + ":" + strconv.Itoa(int(s.Port))
newAddrs = append(newAddrs, resolver.Address{Addr: addr, ServerName: s.Target})
Expand Down Expand Up @@ -322,9 +323,9 @@
}
newAddrs := make([]resolver.Address, 0, len(addrs))
for _, a := range addrs {
ip, ok := formatIP(a)
if !ok {
return nil, fmt.Errorf("dns: error parsing A record IP address %v", a)
ip, err := formatIP(a)
if err != nil {
return nil, fmt.Errorf("dns: error parsing A record IP address %v: %v", a, err)

Check warning on line 328 in internal/resolver/dns/dns_resolver.go

View check run for this annotation

Codecov / codecov/patch

internal/resolver/dns/dns_resolver.go#L328

Added line #L328 was not covered by tests
}
addr := ip + ":" + d.port
newAddrs = append(newAddrs, resolver.Address{Addr: addr})
Expand All @@ -351,19 +352,19 @@
return &state, nil
}

// formatIP returns ok = false if addr is not a valid textual representation of
// an IP address. If addr is an IPv4 address, return the addr and ok = true.
// formatIP returns an error if addr is not a valid textual representation of
// an IP address. If addr is an IPv4 address, return the addr and error = nil.
// If addr is an IPv6 address, return the addr enclosed in square brackets and
// ok = true.
func formatIP(addr string) (addrIP string, ok bool) {
ip := net.ParseIP(addr)
if ip == nil {
return "", false
// error = nil.
func formatIP(addr string) (string, error) {
ip, err := netip.ParseAddr(addr)
if err != nil {
return "", err
}
if ip.To4() != nil {
return addr, true
if ip.Is4() {
return addr, nil
}
return "[" + addr + "]", true
return "[" + addr + "]", nil
}

// parseTarget takes the user input target string and default port, returns
Expand All @@ -379,7 +380,7 @@
if target == "" {
return "", "", internal.ErrMissingAddr
}
if ip := net.ParseIP(target); ip != nil {
if _, err := netip.ParseAddr(target); err == nil {
// target is an IPv4 or IPv6(without brackets) address
return target, defaultPort, nil
}
Expand Down
11 changes: 10 additions & 1 deletion internal/resolver/dns/dns_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,16 @@ func (s) TestIPResolver(t *testing.T) {
target: "[2001:db8::1]:http",
wantAddr: []resolver.Address{{Addr: "[2001:db8::1]:http"}},
},
// TODO(yuxuanli): zone support?
{
name: "ipv6 with zone and port",
target: "[fe80::1%25eth0]:1234",
wantAddr: []resolver.Address{{Addr: "[fe80::1%eth0]:1234"}},
},
{
name: "ipv6 with zone and default port",
target: "fe80::1%25eth0",
wantAddr: []resolver.Address{{Addr: "[fe80::1%eth0]:443"}},
},
}

for _, test := range tests {
Expand Down
9 changes: 5 additions & 4 deletions internal/testutils/fakegrpclb/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"fmt"
"io"
"net"
"net/netip"
"strconv"
"sync"
"time"
Expand Down Expand Up @@ -85,17 +86,17 @@
if err != nil {
return nil, fmt.Errorf("failed to parse list of backend address %q: %v", addr, err)
}
ip := net.ParseIP(ipStr)
if ip == nil {
return nil, fmt.Errorf("failed to parse ip: %q", ipStr)
ip, err := netip.ParseAddr(ipStr)
if err != nil {
return nil, fmt.Errorf("failed to parse ip %q: %v", ipStr, err)

Check warning on line 91 in internal/testutils/fakegrpclb/server.go

View check run for this annotation

Codecov / codecov/patch

internal/testutils/fakegrpclb/server.go#L91

Added line #L91 was not covered by tests
}
port, err := strconv.Atoi(portStr)
if err != nil {
return nil, fmt.Errorf("failed to convert port %q to int", portStr)
}
logger.Infof("Adding backend ip: %q, port: %d to server list", ip.String(), port)
servers = append(servers, &lbpb.Server{
IpAddress: ip,
IpAddress: ip.AsSlice(),
Port: int32(port),
})
}
Expand Down
7 changes: 5 additions & 2 deletions internal/xds/rbac/matchers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"errors"
"fmt"
"net"
"net/netip"
"regexp"

v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
Expand Down Expand Up @@ -344,7 +345,8 @@ func newRemoteIPMatcher(cidrRange *v3corepb.CidrRange) (*remoteIPMatcher, error)
}

func (sim *remoteIPMatcher) match(data *rpcData) bool {
return sim.ipNet.Contains(net.IP(net.ParseIP(data.peerInfo.Addr.String())))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what this old redundant net.IP cast was about, but now it's actually necessary. :)

ip, _ := netip.ParseAddr(data.peerInfo.Addr.String())
return sim.ipNet.Contains(net.IP(ip.AsSlice()))
}

type localIPMatcher struct {
Expand All @@ -361,7 +363,8 @@ func newLocalIPMatcher(cidrRange *v3corepb.CidrRange) (*localIPMatcher, error) {
}

func (dim *localIPMatcher) match(data *rpcData) bool {
return dim.ipNet.Contains(net.IP(net.ParseIP(data.localAddr.String())))
ip, _ := netip.ParseAddr(data.localAddr.String())
return dim.ipNet.Contains(net.IP(ip.AsSlice()))
}

// portMatcher matches on whether the destination port of the RPC matches the
Expand Down
4 changes: 4 additions & 0 deletions scripts/vet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ git grep '"github.com/envoyproxy/go-control-plane/envoy' -- '*.go' ':(exclude)*.
git grep -e 'context.Background()' --or -e 'context.TODO()' -- "*_test.go" | grep -v "benchmark/primitives/context_test.go" | grep -v "credential
s/google" | grep -v "internal/transport/" | grep -v "xds/internal/" | grep -v "security/advancedtls" | grep -v 'context.WithTimeout(' | not grep -v 'context.WithCancel('

# Disallow usage of net.ParseIP in favour of netip.ParseAddr as the former
# can't parse link local IPv6 addresses.
not git grep 'net.ParseIP' -- '*.go'

misspell -error .

# - gofmt, goimports, go vet, go mod tidy.
Expand Down
3 changes: 2 additions & 1 deletion security/advancedtls/crl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"fmt"
"math/big"
"net"
"net/netip"
"os"
"path"
"strings"
Expand Down Expand Up @@ -463,7 +464,7 @@ func setupTLSConn(t *testing.T) (net.Listener, *x509.Certificate, *ecdsa.Private
Subject: pkix.Name{CommonName: "test-cert"},
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
IPAddresses: []net.IP{net.ParseIP("::1")},
IPAddresses: []net.IP{netip.MustParseAddr("::1").AsSlice()},
CRLDistributionPoints: []string{"http://static.corp.google.com/crl/campus-sln/borg"},
}

Expand Down
5 changes: 3 additions & 2 deletions test/local_creds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"context"
"fmt"
"net"
"net/netip"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -181,11 +182,11 @@ func testLocalCredsE2EFail(dopts []grpc.DialOption) error {

var fakeClientAddr, fakeServerAddr net.Addr
fakeClientAddr = &net.IPAddr{
IP: net.ParseIP("10.8.9.10"),
IP: netip.MustParseAddr("10.8.9.10").AsSlice(),
Zone: "",
}
fakeServerAddr = &net.IPAddr{
IP: net.ParseIP("10.8.9.11"),
IP: netip.MustParseAddr("10.8.9.11").AsSlice(),
Zone: "",
}

Expand Down
7 changes: 4 additions & 3 deletions xds/internal/xdsclient/xdsresource/filter_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"errors"
"fmt"
"net"
"net/netip"
"strings"
"testing"

Expand Down Expand Up @@ -2438,7 +2439,7 @@ func (s) TestLookup_Successes(t *testing.T) {
lis: lisWithoutDefaultChain,
params: FilterChainLookupParams{
IsUnspecifiedListener: true,
DestAddr: net.ParseIP("2001:68::db8"),
DestAddr: netip.MustParseAddr("2001:68::db8").AsSlice(),
SourceAddr: net.IPv4(10, 1, 1, 1),
SourcePort: 1,
},
Expand Down Expand Up @@ -2468,8 +2469,8 @@ func (s) TestLookup_Successes(t *testing.T) {
lis: lisWithoutDefaultChain,
params: FilterChainLookupParams{
IsUnspecifiedListener: true,
DestAddr: net.ParseIP("2001:68::1"),
SourceAddr: net.ParseIP("2001:68::2"),
DestAddr: netip.MustParseAddr("2001:68::1").AsSlice(),
SourceAddr: netip.MustParseAddr("2001:68::2").AsSlice(),
SourcePort: 1,
},
wantFC: &FilterChain{
Expand Down
Loading