Replace most uses of net.IP with netip.Addr (#8205)
Retain `net.IP` only where we directly work with `x509.Certificate` and friends. Fixes #5925 Depends on #8196
This commit is contained in:
parent
9b9ed86c10
commit
ac68828f43
15
bdns/dns.go
15
bdns/dns.go
|
@ -36,7 +36,7 @@ type ResolverAddrs []string
|
|||
// Client queries for DNS records
|
||||
type Client interface {
|
||||
LookupTXT(context.Context, string) (txts []string, resolver ResolverAddrs, err error)
|
||||
LookupHost(context.Context, string) ([]net.IP, ResolverAddrs, error)
|
||||
LookupHost(context.Context, string) ([]netip.Addr, ResolverAddrs, error)
|
||||
LookupCAA(context.Context, string) ([]*dns.CAA, string, ResolverAddrs, error)
|
||||
}
|
||||
|
||||
|
@ -381,10 +381,7 @@ func (dnsClient *impl) lookupIP(ctx context.Context, hostname string, ipType uin
|
|||
// chase CNAME/DNAME aliases and return relevant records. It will retry
|
||||
// requests in the case of temporary network errors. It returns an error if
|
||||
// both the A and AAAA lookups fail or are empty, but succeeds otherwise.
|
||||
//
|
||||
// TODO(#5925): Changing from net.IP to netip.Addr could start from here
|
||||
// outwards.
|
||||
func (dnsClient *impl) LookupHost(ctx context.Context, hostname string) ([]net.IP, ResolverAddrs, error) {
|
||||
func (dnsClient *impl) LookupHost(ctx context.Context, hostname string) ([]netip.Addr, ResolverAddrs, error) {
|
||||
var recordsA, recordsAAAA []dns.RR
|
||||
var errA, errAAAA error
|
||||
var resolverA, resolverAAAA string
|
||||
|
@ -407,7 +404,7 @@ func (dnsClient *impl) LookupHost(ctx context.Context, hostname string) ([]net.I
|
|||
return a == ""
|
||||
})
|
||||
|
||||
var addrsA []net.IP
|
||||
var addrsA []netip.Addr
|
||||
if errA == nil {
|
||||
for _, answer := range recordsA {
|
||||
if answer.Header().Rrtype == dns.TypeA {
|
||||
|
@ -415,7 +412,7 @@ func (dnsClient *impl) LookupHost(ctx context.Context, hostname string) ([]net.I
|
|||
if ok && a.A.To4() != nil {
|
||||
netIP, ok := netip.AddrFromSlice(a.A)
|
||||
if ok && (policy.IsReservedIP(netIP) == nil || dnsClient.allowRestrictedAddresses) {
|
||||
addrsA = append(addrsA, a.A)
|
||||
addrsA = append(addrsA, netIP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -425,7 +422,7 @@ func (dnsClient *impl) LookupHost(ctx context.Context, hostname string) ([]net.I
|
|||
}
|
||||
}
|
||||
|
||||
var addrsAAAA []net.IP
|
||||
var addrsAAAA []netip.Addr
|
||||
if errAAAA == nil {
|
||||
for _, answer := range recordsAAAA {
|
||||
if answer.Header().Rrtype == dns.TypeAAAA {
|
||||
|
@ -433,7 +430,7 @@ func (dnsClient *impl) LookupHost(ctx context.Context, hostname string) ([]net.I
|
|||
if ok && aaaa.AAAA.To16() != nil {
|
||||
netIP, ok := netip.AddrFromSlice(aaaa.AAAA)
|
||||
if ok && (policy.IsReservedIP(netIP) == nil || dnsClient.allowRestrictedAddresses) {
|
||||
addrsAAAA = append(addrsAAAA, aaaa.AAAA)
|
||||
addrsAAAA = append(addrsAAAA, netIP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
|
@ -373,10 +374,10 @@ func TestDNSLookupHost(t *testing.T) {
|
|||
t.Logf("dualstack.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertNotError(t, err, "Not an error to exist")
|
||||
test.Assert(t, len(ip) == 2, "Should have 2 IPs")
|
||||
expected := net.ParseIP("127.0.0.1")
|
||||
test.Assert(t, ip[0].To4().Equal(expected), "wrong ipv4 address")
|
||||
expected = net.ParseIP("::1")
|
||||
test.Assert(t, ip[1].To16().Equal(expected), "wrong ipv6 address")
|
||||
expected := netip.MustParseAddr("127.0.0.1")
|
||||
test.Assert(t, ip[0] == expected, "wrong ipv4 address")
|
||||
expected = netip.MustParseAddr("::1")
|
||||
test.Assert(t, ip[1] == expected, "wrong ipv6 address")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
|
@ -385,8 +386,8 @@ func TestDNSLookupHost(t *testing.T) {
|
|||
t.Logf("v6error.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertNotError(t, err, "Not an error to exist")
|
||||
test.Assert(t, len(ip) == 1, "Should have 1 IP")
|
||||
expected = net.ParseIP("127.0.0.1")
|
||||
test.Assert(t, ip[0].To4().Equal(expected), "wrong ipv4 address")
|
||||
expected = netip.MustParseAddr("127.0.0.1")
|
||||
test.Assert(t, ip[0] == expected, "wrong ipv4 address")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
|
@ -395,8 +396,8 @@ func TestDNSLookupHost(t *testing.T) {
|
|||
t.Logf("v4error.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertNotError(t, err, "Not an error to exist")
|
||||
test.Assert(t, len(ip) == 1, "Should have 1 IP")
|
||||
expected = net.ParseIP("::1")
|
||||
test.Assert(t, ip[0].To16().Equal(expected), "wrong ipv6 address")
|
||||
expected = netip.MustParseAddr("::1")
|
||||
test.Assert(t, ip[0] == expected, "wrong ipv6 address")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
@ -67,13 +68,13 @@ func (t timeoutError) Timeout() bool {
|
|||
}
|
||||
|
||||
// LookupHost is a mock
|
||||
func (mock *MockClient) LookupHost(_ context.Context, hostname string) ([]net.IP, ResolverAddrs, error) {
|
||||
func (mock *MockClient) LookupHost(_ context.Context, hostname string) ([]netip.Addr, ResolverAddrs, error) {
|
||||
if hostname == "always.invalid" ||
|
||||
hostname == "invalid.invalid" {
|
||||
return []net.IP{}, ResolverAddrs{"MockClient"}, nil
|
||||
return []netip.Addr{}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
if hostname == "always.timeout" {
|
||||
return []net.IP{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, "always.timeout", makeTimeoutError(), -1, nil}
|
||||
return []netip.Addr{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, "always.timeout", makeTimeoutError(), -1, nil}
|
||||
}
|
||||
if hostname == "always.error" {
|
||||
err := &net.OpError{
|
||||
|
@ -86,7 +87,7 @@ func (mock *MockClient) LookupHost(_ context.Context, hostname string) ([]net.IP
|
|||
m.AuthenticatedData = true
|
||||
m.SetEdns0(4096, false)
|
||||
logDNSError(mock.Log, "mock.server", hostname, m, nil, err)
|
||||
return []net.IP{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, hostname, err, -1, nil}
|
||||
return []netip.Addr{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, hostname, err, -1, nil}
|
||||
}
|
||||
if hostname == "id.mismatch" {
|
||||
err := dns.ErrId
|
||||
|
@ -100,22 +101,21 @@ func (mock *MockClient) LookupHost(_ context.Context, hostname string) ([]net.IP
|
|||
record.A = net.ParseIP("127.0.0.1")
|
||||
r.Answer = append(r.Answer, record)
|
||||
logDNSError(mock.Log, "mock.server", hostname, m, r, err)
|
||||
return []net.IP{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, hostname, err, -1, nil}
|
||||
return []netip.Addr{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, hostname, err, -1, nil}
|
||||
}
|
||||
// dual-homed host with an IPv6 and an IPv4 address
|
||||
if hostname == "ipv4.and.ipv6.localhost" {
|
||||
return []net.IP{
|
||||
net.ParseIP("::1"),
|
||||
net.ParseIP("127.0.0.1"),
|
||||
return []netip.Addr{
|
||||
netip.MustParseAddr("::1"),
|
||||
netip.MustParseAddr("127.0.0.1"),
|
||||
}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
if hostname == "ipv6.localhost" {
|
||||
return []net.IP{
|
||||
net.ParseIP("::1"),
|
||||
return []netip.Addr{
|
||||
netip.MustParseAddr("::1"),
|
||||
}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
ip := net.ParseIP("127.0.0.1")
|
||||
return []net.IP{ip}, ResolverAddrs{"MockClient"}, nil
|
||||
return []netip.Addr{netip.MustParseAddr("127.0.0.1")}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
|
||||
// LookupCAA returns mock records for use in tests.
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"math/rand/v2"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -61,10 +62,9 @@ func validateServerAddress(address string) error {
|
|||
}
|
||||
|
||||
// Ensure the `host` portion of `address` is a valid FQDN or IP address.
|
||||
IPv6 := net.ParseIP(host).To16()
|
||||
IPv4 := net.ParseIP(host).To4()
|
||||
_, err = netip.ParseAddr(host)
|
||||
FQDN := dns.IsFqdn(dns.Fqdn(host))
|
||||
if IPv6 == nil && IPv4 == nil && !FQDN {
|
||||
if err != nil && !FQDN {
|
||||
return errors.New("host is not an FQDN or IP address")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"github.com/letsencrypt/boulder/cmd"
|
||||
|
@ -41,8 +42,8 @@ func derivePrefix(key []byte, grpcAddr string) (string, error) {
|
|||
return "", fmt.Errorf("nonce service gRPC address must include an IP address: got %q", grpcAddr)
|
||||
}
|
||||
if host != "" && port != "" {
|
||||
hostIP := net.ParseIP(host)
|
||||
if hostIP == nil {
|
||||
hostIP, err := netip.ParseAddr(host)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("gRPC address host part was not an IP address")
|
||||
}
|
||||
if hostIP.IsUnspecified() {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -124,10 +124,10 @@ type ValidationRecord struct {
|
|||
// Shared
|
||||
//
|
||||
// TODO(#7311): Replace DnsName with Identifier.
|
||||
DnsName string `json:"hostname,omitempty"`
|
||||
Port string `json:"port,omitempty"`
|
||||
AddressesResolved []net.IP `json:"addressesResolved,omitempty"`
|
||||
AddressUsed net.IP `json:"addressUsed,omitempty"`
|
||||
DnsName string `json:"hostname,omitempty"`
|
||||
Port string `json:"port,omitempty"`
|
||||
AddressesResolved []netip.Addr `json:"addressesResolved,omitempty"`
|
||||
AddressUsed netip.Addr `json:"addressUsed,omitempty"`
|
||||
|
||||
// AddressesTried contains a list of addresses tried before the `AddressUsed`.
|
||||
// Presently this will only ever be one IP from `AddressesResolved` since the
|
||||
|
@ -143,7 +143,7 @@ type ValidationRecord struct {
|
|||
// AddressesTried: [ ::1 ],
|
||||
// ...
|
||||
// }
|
||||
AddressesTried []net.IP `json:"addressesTried,omitempty"`
|
||||
AddressesTried []netip.Addr `json:"addressesTried,omitempty"`
|
||||
|
||||
// ResolverAddrs is the host:port of the DNS resolver(s) that fulfilled the
|
||||
// lookup for AddressUsed. During recursive A and AAAA lookups, a record may
|
||||
|
@ -210,7 +210,7 @@ func (ch Challenge) RecordsSane() bool {
|
|||
for _, rec := range ch.ValidationRecord {
|
||||
// TODO(#7140): Add a check for ResolverAddress == "" only after the
|
||||
// core.proto change has been deployed.
|
||||
if rec.URL == "" || rec.DnsName == "" || rec.Port == "" || rec.AddressUsed == nil ||
|
||||
if rec.URL == "" || rec.DnsName == "" || rec.Port == "" || (rec.AddressUsed == netip.Addr{}) ||
|
||||
len(rec.AddressesResolved) == 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ func (ch Challenge) RecordsSane() bool {
|
|||
// TODO(#7140): Add a check for ResolverAddress == "" only after the
|
||||
// core.proto change has been deployed.
|
||||
if ch.ValidationRecord[0].DnsName == "" || ch.ValidationRecord[0].Port == "" ||
|
||||
ch.ValidationRecord[0].AddressUsed == nil || len(ch.ValidationRecord[0].AddressesResolved) == 0 {
|
||||
(ch.ValidationRecord[0].AddressUsed == netip.Addr{}) || len(ch.ValidationRecord[0].AddressesResolved) == 0 {
|
||||
return false
|
||||
}
|
||||
case ChallengeTypeDNS01:
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"crypto/rsa"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -39,8 +39,8 @@ func TestRecordSanityCheckOnUnsupportedChallengeType(t *testing.T) {
|
|||
URL: "http://localhost/test",
|
||||
DnsName: "localhost",
|
||||
Port: "80",
|
||||
AddressesResolved: []net.IP{{127, 0, 0, 1}},
|
||||
AddressUsed: net.IP{127, 0, 0, 1},
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"eastUnboundAndDown"},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -183,14 +183,14 @@ type ValidationRecord struct {
|
|||
// TODO(#7311): Replace hostname with Identifier.
|
||||
Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"`
|
||||
Port string `protobuf:"bytes,2,opt,name=port,proto3" json:"port,omitempty"`
|
||||
AddressesResolved [][]byte `protobuf:"bytes,3,rep,name=addressesResolved,proto3" json:"addressesResolved,omitempty"` // net.IP.MarshalText()
|
||||
AddressUsed []byte `protobuf:"bytes,4,opt,name=addressUsed,proto3" json:"addressUsed,omitempty"` // net.IP.MarshalText()
|
||||
AddressesResolved [][]byte `protobuf:"bytes,3,rep,name=addressesResolved,proto3" json:"addressesResolved,omitempty"` // netip.Addr.MarshalText()
|
||||
AddressUsed []byte `protobuf:"bytes,4,opt,name=addressUsed,proto3" json:"addressUsed,omitempty"` // netip.Addr.MarshalText()
|
||||
Authorities []string `protobuf:"bytes,5,rep,name=authorities,proto3" json:"authorities,omitempty"`
|
||||
Url string `protobuf:"bytes,6,opt,name=url,proto3" json:"url,omitempty"`
|
||||
// A list of addresses tried before the address used (see
|
||||
// core/objects.go and the comment on the ValidationRecord structure
|
||||
// definition for more information.
|
||||
AddressesTried [][]byte `protobuf:"bytes,7,rep,name=addressesTried,proto3" json:"addressesTried,omitempty"` // net.IP.MarshalText()
|
||||
AddressesTried [][]byte `protobuf:"bytes,7,rep,name=addressesTried,proto3" json:"addressesTried,omitempty"` // netip.Addr.MarshalText()
|
||||
ResolverAddrs []string `protobuf:"bytes,8,rep,name=resolverAddrs,proto3" json:"resolverAddrs,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
|
|
@ -31,15 +31,15 @@ message ValidationRecord {
|
|||
// TODO(#7311): Replace hostname with Identifier.
|
||||
string hostname = 1;
|
||||
string port = 2;
|
||||
repeated bytes addressesResolved = 3; // net.IP.MarshalText()
|
||||
bytes addressUsed = 4; // net.IP.MarshalText()
|
||||
repeated bytes addressesResolved = 3; // netip.Addr.MarshalText()
|
||||
bytes addressUsed = 4; // netip.Addr.MarshalText()
|
||||
|
||||
repeated string authorities = 5;
|
||||
string url = 6;
|
||||
// A list of addresses tried before the address used (see
|
||||
// core/objects.go and the comment on the ValidationRecord structure
|
||||
// definition for more information.
|
||||
repeated bytes addressesTried = 7; // net.IP.MarshalText()
|
||||
repeated bytes addressesTried = 7; // netip.Addr.MarshalText()
|
||||
repeated string resolverAddrs = 8;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,17 +27,19 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/letsencrypt/boulder/bdns"
|
||||
"github.com/letsencrypt/boulder/grpc/internal/backoff"
|
||||
"github.com/letsencrypt/boulder/grpc/noncebalancer"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/serviceconfig"
|
||||
|
||||
"github.com/letsencrypt/boulder/bdns"
|
||||
"github.com/letsencrypt/boulder/grpc/internal/backoff"
|
||||
"github.com/letsencrypt/boulder/grpc/noncebalancer"
|
||||
)
|
||||
|
||||
var logger = grpclog.Component("srv")
|
||||
|
@ -292,11 +294,11 @@ func (d *dnsResolver) lookup() (*resolver.State, error) {
|
|||
// If addr is an IPv4 address, return the addr and ok = true.
|
||||
// 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 {
|
||||
ip, err := netip.ParseAddr(addr)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
if ip.To4() != nil {
|
||||
if ip.Is4() {
|
||||
return addr, true
|
||||
}
|
||||
return "[" + addr + "]", true
|
||||
|
|
|
@ -7,7 +7,7 @@ package grpc
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
|
@ -23,6 +23,7 @@ import (
|
|||
)
|
||||
|
||||
var ErrMissingParameters = CodedError(codes.FailedPrecondition, "required RPC parameter was missing")
|
||||
var ErrInvalidParameters = CodedError(codes.InvalidArgument, "RPC parameter was invalid")
|
||||
|
||||
// This file defines functions to translate between the protobuf types and the
|
||||
// code types.
|
||||
|
@ -130,10 +131,10 @@ func ValidationRecordToPB(record core.ValidationRecord) (*corepb.ValidationRecor
|
|||
addrsTried := make([][]byte, len(record.AddressesTried))
|
||||
var err error
|
||||
for i, v := range record.AddressesResolved {
|
||||
addrs[i] = []byte(v)
|
||||
addrs[i] = v.AsSlice()
|
||||
}
|
||||
for i, v := range record.AddressesTried {
|
||||
addrsTried[i] = []byte(v)
|
||||
addrsTried[i] = v.AsSlice()
|
||||
}
|
||||
addrUsed, err := record.AddressUsed.MarshalText()
|
||||
if err != nil {
|
||||
|
@ -154,15 +155,23 @@ func PBToValidationRecord(in *corepb.ValidationRecord) (record core.ValidationRe
|
|||
if in == nil {
|
||||
return core.ValidationRecord{}, ErrMissingParameters
|
||||
}
|
||||
addrs := make([]net.IP, len(in.AddressesResolved))
|
||||
addrs := make([]netip.Addr, len(in.AddressesResolved))
|
||||
for i, v := range in.AddressesResolved {
|
||||
addrs[i] = net.IP(v)
|
||||
netIP, ok := netip.AddrFromSlice(v)
|
||||
if !ok {
|
||||
return core.ValidationRecord{}, ErrInvalidParameters
|
||||
}
|
||||
addrs[i] = netIP
|
||||
}
|
||||
addrsTried := make([]net.IP, len(in.AddressesTried))
|
||||
addrsTried := make([]netip.Addr, len(in.AddressesTried))
|
||||
for i, v := range in.AddressesTried {
|
||||
addrsTried[i] = net.IP(v)
|
||||
netIP, ok := netip.AddrFromSlice(v)
|
||||
if !ok {
|
||||
return core.ValidationRecord{}, ErrInvalidParameters
|
||||
}
|
||||
addrsTried[i] = netIP
|
||||
}
|
||||
var addrUsed net.IP
|
||||
var addrUsed netip.Addr
|
||||
err = addrUsed.UnmarshalText(in.AddressUsed)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
|
@ -2,7 +2,7 @@ package grpc
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -69,15 +69,15 @@ func TestChallenge(t *testing.T) {
|
|||
test.AssertNotError(t, err, "PBToChallenge failed")
|
||||
test.AssertDeepEquals(t, recon, chall)
|
||||
|
||||
ip := net.ParseIP("1.1.1.1")
|
||||
ip := netip.MustParseAddr("1.1.1.1")
|
||||
chall.ValidationRecord = []core.ValidationRecord{
|
||||
{
|
||||
DnsName: "example.com",
|
||||
Port: "2020",
|
||||
AddressesResolved: []net.IP{ip},
|
||||
AddressesResolved: []netip.Addr{ip},
|
||||
AddressUsed: ip,
|
||||
URL: "https://example.com:2020",
|
||||
AddressesTried: []net.IP{ip},
|
||||
AddressesTried: []netip.Addr{ip},
|
||||
},
|
||||
}
|
||||
chall.Error = &probs.ProblemDetails{Type: probs.TLSProblem, Detail: "asd", HTTPStatus: 200}
|
||||
|
@ -111,14 +111,14 @@ func TestChallenge(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestValidationRecord(t *testing.T) {
|
||||
ip := net.ParseIP("1.1.1.1")
|
||||
ip := netip.MustParseAddr("1.1.1.1")
|
||||
vr := core.ValidationRecord{
|
||||
DnsName: "exampleA.com",
|
||||
Port: "80",
|
||||
AddressesResolved: []net.IP{ip},
|
||||
AddressesResolved: []netip.Addr{ip},
|
||||
AddressUsed: ip,
|
||||
URL: "http://exampleA.com",
|
||||
AddressesTried: []net.IP{ip},
|
||||
AddressesTried: []netip.Addr{ip},
|
||||
ResolverAddrs: []string{"resolver:5353"},
|
||||
}
|
||||
|
||||
|
@ -132,23 +132,23 @@ func TestValidationRecord(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestValidationResult(t *testing.T) {
|
||||
ip := net.ParseIP("1.1.1.1")
|
||||
ip := netip.MustParseAddr("1.1.1.1")
|
||||
vrA := core.ValidationRecord{
|
||||
DnsName: "exampleA.com",
|
||||
Port: "443",
|
||||
AddressesResolved: []net.IP{ip},
|
||||
AddressesResolved: []netip.Addr{ip},
|
||||
AddressUsed: ip,
|
||||
URL: "https://exampleA.com",
|
||||
AddressesTried: []net.IP{ip},
|
||||
AddressesTried: []netip.Addr{ip},
|
||||
ResolverAddrs: []string{"resolver:5353"},
|
||||
}
|
||||
vrB := core.ValidationRecord{
|
||||
DnsName: "exampleB.com",
|
||||
Port: "443",
|
||||
AddressesResolved: []net.IP{ip},
|
||||
AddressesResolved: []netip.Addr{ip},
|
||||
AddressUsed: ip,
|
||||
URL: "https://exampleB.com",
|
||||
AddressesTried: []net.IP{ip},
|
||||
AddressesTried: []netip.Addr{ip},
|
||||
ResolverAddrs: []string{"resolver:5353"},
|
||||
}
|
||||
result := []core.ValidationRecord{vrA, vrB}
|
||||
|
|
|
@ -3,6 +3,7 @@ package grpc
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/resolver"
|
||||
|
@ -91,7 +92,8 @@ func parseResolverIPAddress(addr string) (*resolver.Address, error) {
|
|||
// empty (e.g. :80), the local system is assumed.
|
||||
host = "127.0.0.1"
|
||||
}
|
||||
if net.ParseIP(host) == nil {
|
||||
_, err = netip.ParseAddr(host)
|
||||
if err != nil {
|
||||
// Host is a DNS name or an IPv6 address without brackets.
|
||||
return nil, fmt.Errorf("address %q is not an IP address", addr)
|
||||
}
|
||||
|
|
|
@ -3,13 +3,15 @@ package probers
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/letsencrypt/boulder/observer/probers"
|
||||
"github.com/letsencrypt/boulder/strictyaml"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/letsencrypt/boulder/observer/probers"
|
||||
"github.com/letsencrypt/boulder/strictyaml"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -58,13 +60,12 @@ func (c DNSConf) validateServer() error {
|
|||
return fmt.Errorf(
|
||||
"invalid `server`, %q, port number must be one in [1-65535]", c.Server)
|
||||
}
|
||||
// Ensure `server` is a valid FQDN or IPv4 / IPv6 address.
|
||||
IPv6 := net.ParseIP(host).To16()
|
||||
IPv4 := net.ParseIP(host).To4()
|
||||
// Ensure `server` is a valid FQDN or IP address.
|
||||
_, err = netip.ParseAddr(host)
|
||||
FQDN := dns.IsFqdn(dns.Fqdn(host))
|
||||
if IPv6 == nil && IPv4 == nil && !FQDN {
|
||||
if err != nil && !FQDN {
|
||||
return fmt.Errorf(
|
||||
"invalid `server`, %q, is not an FQDN or IPv4 / IPv6 address", c.Server)
|
||||
"invalid `server`, %q, is not an FQDN or IP address", c.Server)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
14
policy/pa.go
14
policy/pa.go
|
@ -5,7 +5,6 @@ import (
|
|||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/mail"
|
||||
"net/netip"
|
||||
"os"
|
||||
|
@ -228,7 +227,8 @@ func validNonWildcardDomain(domain string) error {
|
|||
return errNameTooLong
|
||||
}
|
||||
|
||||
if ip := net.ParseIP(domain); ip != nil {
|
||||
_, err := netip.ParseAddr(domain)
|
||||
if err == nil {
|
||||
return errIPAddressInDNS
|
||||
}
|
||||
|
||||
|
@ -343,11 +343,11 @@ func validIP(ip string) error {
|
|||
return errEmptyIdentifier
|
||||
}
|
||||
|
||||
// Check the output of net.IP.String(), to ensure the input complied with
|
||||
// RFC 8738, Sec. 3. ("The identifier value MUST contain the textual form of
|
||||
// the address as defined in RFC 1123, Sec. 2.1 for IPv4 and in RFC 5952,
|
||||
// Sec. 4 for IPv6.") ParseIP() will accept a non-compliant but otherwise
|
||||
// valid string; String() will output a compliant string.
|
||||
// Check the output of netip.Addr.String(), to ensure the input complied
|
||||
// with RFC 8738, Sec. 3. ("The identifier value MUST contain the textual
|
||||
// form of the address as defined in RFC 1123, Sec. 2.1 for IPv4 and in RFC
|
||||
// 5952, Sec. 4 for IPv6.") ParseAddr() will accept a non-compliant but
|
||||
// otherwise valid string; String() will output a compliant string.
|
||||
parsedIP, err := netip.ParseAddr(ip)
|
||||
if err != nil || parsedIP.String() != ip {
|
||||
return errIPInvalid
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"math/rand/v2"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -59,7 +60,7 @@ func TestLimiter_CheckWithLimitOverrides(t *testing.T) {
|
|||
testCtx, limiters, txnBuilder, clk, testIP := setup(t)
|
||||
for name, l := range limiters {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
overriddenBucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, net.ParseIP(tenZeroZeroTwo))
|
||||
overriddenBucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, netip.MustParseAddr(tenZeroZeroTwo))
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
overriddenLimit, err := txnBuilder.getLimit(NewRegistrationsPerIPAddress, overriddenBucketKey)
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
|
@ -115,8 +116,7 @@ func TestLimiter_CheckWithLimitOverrides(t *testing.T) {
|
|||
// Wait 1 second for a full bucket reset.
|
||||
clk.Add(d.resetIn)
|
||||
|
||||
testIP := net.ParseIP(testIP)
|
||||
normalBucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, testIP)
|
||||
normalBucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, netip.MustParseAddr(testIP))
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
normalLimit, err := txnBuilder.getLimit(NewRegistrationsPerIPAddress, normalBucketKey)
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
|
@ -247,7 +247,7 @@ func TestLimiter_InitializationViaCheckAndSpend(t *testing.T) {
|
|||
testCtx, limiters, txnBuilder, _, testIP := setup(t)
|
||||
for name, l := range limiters {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
bucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, net.ParseIP(testIP))
|
||||
bucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, netip.MustParseAddr(testIP))
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
limit, err := txnBuilder.getLimit(NewRegistrationsPerIPAddress, bucketKey)
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
|
@ -310,7 +310,7 @@ func TestLimiter_DefaultLimits(t *testing.T) {
|
|||
testCtx, limiters, txnBuilder, clk, testIP := setup(t)
|
||||
for name, l := range limiters {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
bucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, net.ParseIP(testIP))
|
||||
bucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, netip.MustParseAddr(testIP))
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
limit, err := txnBuilder.getLimit(NewRegistrationsPerIPAddress, bucketKey)
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
|
@ -373,7 +373,7 @@ func TestLimiter_RefundAndReset(t *testing.T) {
|
|||
testCtx, limiters, txnBuilder, clk, testIP := setup(t)
|
||||
for name, l := range limiters {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
bucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, net.ParseIP(testIP))
|
||||
bucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, netip.MustParseAddr(testIP))
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
limit, err := txnBuilder.getLimit(NewRegistrationsPerIPAddress, bucketKey)
|
||||
test.AssertNotError(t, err, "should not error")
|
||||
|
|
|
@ -3,6 +3,7 @@ package ratelimits
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -126,8 +127,8 @@ func (n Name) EnumString() string {
|
|||
|
||||
// validIPAddress validates that the provided string is a valid IP address.
|
||||
func validIPAddress(id string) error {
|
||||
ip := net.ParseIP(id)
|
||||
if ip == nil {
|
||||
_, err := netip.ParseAddr(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid IP address, %q must be an IP address", id)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -3,7 +3,7 @@ package ratelimits
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
@ -16,7 +16,7 @@ var ErrInvalidCostOverLimit = fmt.Errorf("invalid cost, must be <= limit.Burst")
|
|||
|
||||
// newIPAddressBucketKey validates and returns a bucketKey for limits that use
|
||||
// the 'enum:ipAddress' bucket key format.
|
||||
func newIPAddressBucketKey(name Name, ip net.IP) (string, error) { //nolint:unparam // Only one named rate limit uses this helper
|
||||
func newIPAddressBucketKey(name Name, ip netip.Addr) (string, error) { //nolint:unparam // Only one named rate limit uses this helper
|
||||
id := ip.String()
|
||||
err := validateIdForName(name, id)
|
||||
if err != nil {
|
||||
|
@ -27,14 +27,16 @@ func newIPAddressBucketKey(name Name, ip net.IP) (string, error) { //nolint:unpa
|
|||
|
||||
// newIPv6RangeCIDRBucketKey validates and returns a bucketKey for limits that
|
||||
// use the 'enum:ipv6RangeCIDR' bucket key format.
|
||||
func newIPv6RangeCIDRBucketKey(name Name, ip net.IP) (string, error) {
|
||||
if ip.To4() != nil {
|
||||
func newIPv6RangeCIDRBucketKey(name Name, ip netip.Addr) (string, error) {
|
||||
if ip.Is4() {
|
||||
return "", fmt.Errorf("invalid IPv6 address, %q must be an IPv6 address", ip.String())
|
||||
}
|
||||
ipMask := net.CIDRMask(48, 128)
|
||||
ipNet := &net.IPNet{IP: ip.Mask(ipMask), Mask: ipMask}
|
||||
id := ipNet.String()
|
||||
err := validateIdForName(name, id)
|
||||
prefix, err := ip.Prefix(48)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid IPv6 address, can't calculate prefix of %q: %s", ip.String(), err)
|
||||
}
|
||||
id := prefix.String()
|
||||
err = validateIdForName(name, id)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -206,7 +208,7 @@ func NewTransactionBuilder(defaults LimitConfigs) (*TransactionBuilder, error) {
|
|||
|
||||
// registrationsPerIPAddressTransaction returns a Transaction for the
|
||||
// NewRegistrationsPerIPAddress limit for the provided IP address.
|
||||
func (builder *TransactionBuilder) registrationsPerIPAddressTransaction(ip net.IP) (Transaction, error) {
|
||||
func (builder *TransactionBuilder) registrationsPerIPAddressTransaction(ip netip.Addr) (Transaction, error) {
|
||||
bucketKey, err := newIPAddressBucketKey(NewRegistrationsPerIPAddress, ip)
|
||||
if err != nil {
|
||||
return Transaction{}, err
|
||||
|
@ -224,7 +226,7 @@ func (builder *TransactionBuilder) registrationsPerIPAddressTransaction(ip net.I
|
|||
// registrationsPerIPv6RangeTransaction returns a Transaction for the
|
||||
// NewRegistrationsPerIPv6Range limit for the /48 IPv6 range which contains the
|
||||
// provided IPv6 address.
|
||||
func (builder *TransactionBuilder) registrationsPerIPv6RangeTransaction(ip net.IP) (Transaction, error) {
|
||||
func (builder *TransactionBuilder) registrationsPerIPv6RangeTransaction(ip netip.Addr) (Transaction, error) {
|
||||
bucketKey, err := newIPv6RangeCIDRBucketKey(NewRegistrationsPerIPv6Range, ip)
|
||||
if err != nil {
|
||||
return Transaction{}, err
|
||||
|
@ -617,7 +619,7 @@ func (builder *TransactionBuilder) NewOrderLimitTransactions(regId int64, names
|
|||
// NewAccountLimitTransactions takes in an IP address from a new-account request
|
||||
// and returns the set of rate limit transactions that should be evaluated
|
||||
// before allowing the request to proceed.
|
||||
func (builder *TransactionBuilder) NewAccountLimitTransactions(ip net.IP) ([]Transaction, error) {
|
||||
func (builder *TransactionBuilder) NewAccountLimitTransactions(ip netip.Addr) ([]Transaction, error) {
|
||||
makeTxnError := func(err error, limit Name) error {
|
||||
return fmt.Errorf("error constructing rate limit transaction for %s rate limit: %w", limit, err)
|
||||
}
|
||||
|
@ -629,7 +631,7 @@ func (builder *TransactionBuilder) NewAccountLimitTransactions(ip net.IP) ([]Tra
|
|||
}
|
||||
transactions = append(transactions, txn)
|
||||
|
||||
if ip.To4() != nil {
|
||||
if ip.Is4() {
|
||||
// This request was made from an IPv4 address.
|
||||
return transactions, nil
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package ratelimits
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -34,7 +34,7 @@ func TestNewRegistrationsPerIPAddressTransactions(t *testing.T) {
|
|||
test.AssertNotError(t, err, "creating TransactionBuilder")
|
||||
|
||||
// A check-and-spend transaction for the global limit.
|
||||
txn, err := tb.registrationsPerIPAddressTransaction(net.ParseIP("1.2.3.4"))
|
||||
txn, err := tb.registrationsPerIPAddressTransaction(netip.MustParseAddr("1.2.3.4"))
|
||||
test.AssertNotError(t, err, "creating transaction")
|
||||
test.AssertEquals(t, txn.bucketKey, "1:1.2.3.4")
|
||||
test.Assert(t, txn.check && txn.spend, "should be check-and-spend")
|
||||
|
@ -47,7 +47,7 @@ func TestNewRegistrationsPerIPv6AddressTransactions(t *testing.T) {
|
|||
test.AssertNotError(t, err, "creating TransactionBuilder")
|
||||
|
||||
// A check-and-spend transaction for the global limit.
|
||||
txn, err := tb.registrationsPerIPv6RangeTransaction(net.ParseIP("2001:db8::1"))
|
||||
txn, err := tb.registrationsPerIPv6RangeTransaction(netip.MustParseAddr("2001:db8::1"))
|
||||
test.AssertNotError(t, err, "creating transaction")
|
||||
test.AssertEquals(t, txn.bucketKey, "2:2001:db8::/48")
|
||||
test.Assert(t, txn.check && txn.spend, "should be check-and-spend")
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
"math/big"
|
||||
"math/bits"
|
||||
mrand "math/rand/v2"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"reflect"
|
||||
|
@ -2221,7 +2220,7 @@ func TestFinalizeAuthorization2(t *testing.T) {
|
|||
authzID := createPendingAuthorization(t, sa, identifier.NewDNS("aaa"), fc.Now().Add(time.Hour))
|
||||
expires := fc.Now().Add(time.Hour * 2).UTC()
|
||||
attemptedAt := fc.Now()
|
||||
ip, _ := net.ParseIP("1.1.1.1").MarshalText()
|
||||
ip, _ := netip.MustParseAddr("1.1.1.1").MarshalText()
|
||||
|
||||
_, err := sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{
|
||||
Id: authzID,
|
||||
|
@ -2292,7 +2291,7 @@ func TestRehydrateHostPort(t *testing.T) {
|
|||
|
||||
expires := fc.Now().Add(time.Hour * 2).UTC()
|
||||
attemptedAt := fc.Now()
|
||||
ip, _ := net.ParseIP("1.1.1.1").MarshalText()
|
||||
ip, _ := netip.MustParseAddr("1.1.1.1").MarshalText()
|
||||
|
||||
// Implicit good port with good scheme
|
||||
authzID := createPendingAuthorization(t, sa, identifier.NewDNS("aaa"), fc.Now().Add(time.Hour))
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"regexp"
|
||||
"slices"
|
||||
|
@ -35,9 +34,8 @@ func (mock caaMockDNS) LookupTXT(_ context.Context, hostname string) ([]string,
|
|||
return nil, bdns.ResolverAddrs{"caaMockDNS"}, nil
|
||||
}
|
||||
|
||||
func (mock caaMockDNS) LookupHost(_ context.Context, hostname string) ([]net.IP, bdns.ResolverAddrs, error) {
|
||||
ip := net.ParseIP("127.0.0.1")
|
||||
return []net.IP{ip}, bdns.ResolverAddrs{"caaMockDNS"}, nil
|
||||
func (mock caaMockDNS) LookupHost(_ context.Context, hostname string) ([]netip.Addr, bdns.ResolverAddrs, error) {
|
||||
return []netip.Addr{netip.MustParseAddr("127.0.0.1")}, bdns.ResolverAddrs{"caaMockDNS"}, nil
|
||||
}
|
||||
|
||||
func (mock caaMockDNS) LookupCAA(_ context.Context, domain string) ([]*dns.CAA, string, bdns.ResolverAddrs, error) {
|
||||
|
@ -601,7 +599,7 @@ func (b caaBrokenDNS) LookupTXT(_ context.Context, hostname string) ([]string, b
|
|||
return nil, bdns.ResolverAddrs{"caaBrokenDNS"}, errCAABrokenDNSClient
|
||||
}
|
||||
|
||||
func (b caaBrokenDNS) LookupHost(_ context.Context, hostname string) ([]net.IP, bdns.ResolverAddrs, error) {
|
||||
func (b caaBrokenDNS) LookupHost(_ context.Context, hostname string) ([]netip.Addr, bdns.ResolverAddrs, error) {
|
||||
return nil, bdns.ResolverAddrs{"caaBrokenDNS"}, errCAABrokenDNSClient
|
||||
}
|
||||
|
||||
|
@ -619,9 +617,8 @@ func (h caaHijackedDNS) LookupTXT(_ context.Context, hostname string) ([]string,
|
|||
return nil, bdns.ResolverAddrs{"caaHijackedDNS"}, nil
|
||||
}
|
||||
|
||||
func (h caaHijackedDNS) LookupHost(_ context.Context, hostname string) ([]net.IP, bdns.ResolverAddrs, error) {
|
||||
ip := net.ParseIP("127.0.0.1")
|
||||
return []net.IP{ip}, bdns.ResolverAddrs{"caaHijackedDNS"}, nil
|
||||
func (h caaHijackedDNS) LookupHost(_ context.Context, hostname string) ([]netip.Addr, bdns.ResolverAddrs, error) {
|
||||
return []netip.Addr{netip.MustParseAddr("127.0.0.1")}, bdns.ResolverAddrs{"caaHijackedDNS"}, nil
|
||||
}
|
||||
func (h caaHijackedDNS) LookupCAA(_ context.Context, domain string) ([]*dns.CAA, string, bdns.ResolverAddrs, error) {
|
||||
// These records are altered from their caaMockDNS counterparts. Use this to
|
||||
|
|
18
va/dns.go
18
va/dns.go
|
@ -6,7 +6,7 @@ import (
|
|||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/letsencrypt/boulder/bdns"
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
|
@ -15,12 +15,12 @@ import (
|
|||
)
|
||||
|
||||
// getAddr will query for all A/AAAA records associated with hostname and return
|
||||
// the preferred address, the first net.IP in the addrs slice, and all addresses
|
||||
// resolved. This is the same choice made by the Go internal resolution library
|
||||
// used by net/http. If there is an error resolving the hostname, or if no
|
||||
// usable IP addresses are available then a berrors.DNSError instance is
|
||||
// returned with a nil net.IP slice.
|
||||
func (va ValidationAuthorityImpl) getAddrs(ctx context.Context, hostname string) ([]net.IP, bdns.ResolverAddrs, error) {
|
||||
// the preferred address, the first netip.Addr in the addrs slice, and all
|
||||
// addresses resolved. This is the same choice made by the Go internal
|
||||
// resolution library used by net/http. If there is an error resolving the
|
||||
// hostname, or if no usable IP addresses are available then a berrors.DNSError
|
||||
// instance is returned with a nil netip.Addr slice.
|
||||
func (va ValidationAuthorityImpl) getAddrs(ctx context.Context, hostname string) ([]netip.Addr, bdns.ResolverAddrs, error) {
|
||||
addrs, resolvers, err := va.dnsClient.LookupHost(ctx, hostname)
|
||||
if err != nil {
|
||||
return nil, resolvers, berrors.DNSError("%v", err)
|
||||
|
@ -37,9 +37,9 @@ func (va ValidationAuthorityImpl) getAddrs(ctx context.Context, hostname string)
|
|||
|
||||
// availableAddresses takes a ValidationRecord and splits the AddressesResolved
|
||||
// into a list of IPv4 and IPv6 addresses.
|
||||
func availableAddresses(allAddrs []net.IP) (v4 []net.IP, v6 []net.IP) {
|
||||
func availableAddresses(allAddrs []netip.Addr) (v4 []netip.Addr, v6 []netip.Addr) {
|
||||
for _, addr := range allAddrs {
|
||||
if addr.To4() != nil {
|
||||
if addr.Is4() {
|
||||
v4 = append(v4, addr)
|
||||
} else {
|
||||
v6 = append(v6, addr)
|
||||
|
|
|
@ -3,7 +3,6 @@ package va
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -127,51 +126,51 @@ func TestDNSValidationNoAuthorityOK(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAvailableAddresses(t *testing.T) {
|
||||
v6a := net.ParseIP("::1")
|
||||
v6b := net.ParseIP("2001:db8::2:1") // 2001:DB8 is reserved for docs (RFC 3849)
|
||||
v4a := net.ParseIP("127.0.0.1")
|
||||
v4b := net.ParseIP("192.0.2.1") // 192.0.2.0/24 is reserved for docs (RFC 5737)
|
||||
v6a := netip.MustParseAddr("::1")
|
||||
v6b := netip.MustParseAddr("2001:db8::2:1") // 2001:DB8 is reserved for docs (RFC 3849)
|
||||
v4a := netip.MustParseAddr("127.0.0.1")
|
||||
v4b := netip.MustParseAddr("192.0.2.1") // 192.0.2.0/24 is reserved for docs (RFC 5737)
|
||||
|
||||
testcases := []struct {
|
||||
input []net.IP
|
||||
v4 []net.IP
|
||||
v6 []net.IP
|
||||
input []netip.Addr
|
||||
v4 []netip.Addr
|
||||
v6 []netip.Addr
|
||||
}{
|
||||
// An empty validation record
|
||||
{
|
||||
[]net.IP{},
|
||||
[]net.IP{},
|
||||
[]net.IP{},
|
||||
[]netip.Addr{},
|
||||
[]netip.Addr{},
|
||||
[]netip.Addr{},
|
||||
},
|
||||
// A validation record with one IPv4 address
|
||||
{
|
||||
[]net.IP{v4a},
|
||||
[]net.IP{v4a},
|
||||
[]net.IP{},
|
||||
[]netip.Addr{v4a},
|
||||
[]netip.Addr{v4a},
|
||||
[]netip.Addr{},
|
||||
},
|
||||
// A dual homed record with an IPv4 and IPv6 address
|
||||
{
|
||||
[]net.IP{v4a, v6a},
|
||||
[]net.IP{v4a},
|
||||
[]net.IP{v6a},
|
||||
[]netip.Addr{v4a, v6a},
|
||||
[]netip.Addr{v4a},
|
||||
[]netip.Addr{v6a},
|
||||
},
|
||||
// The same as above but with the v4/v6 order flipped
|
||||
{
|
||||
[]net.IP{v6a, v4a},
|
||||
[]net.IP{v4a},
|
||||
[]net.IP{v6a},
|
||||
[]netip.Addr{v6a, v4a},
|
||||
[]netip.Addr{v4a},
|
||||
[]netip.Addr{v6a},
|
||||
},
|
||||
// A validation record with just IPv6 addresses
|
||||
{
|
||||
[]net.IP{v6a, v6b},
|
||||
[]net.IP{},
|
||||
[]net.IP{v6a, v6b},
|
||||
[]netip.Addr{v6a, v6b},
|
||||
[]netip.Addr{},
|
||||
[]netip.Addr{v6a, v6b},
|
||||
},
|
||||
// A validation record with interleaved IPv4/IPv6 records
|
||||
{
|
||||
[]net.IP{v6a, v4a, v6b, v4b},
|
||||
[]net.IP{v4a, v4b},
|
||||
[]net.IP{v6a, v6b},
|
||||
[]netip.Addr{v6a, v4a, v6b, v4b},
|
||||
[]netip.Addr{v4a, v4b},
|
||||
[]netip.Addr{v6a, v6b},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
26
va/http.go
26
va/http.go
|
@ -42,7 +42,7 @@ const (
|
|||
// The hostname of the preresolvedDialer is used to ensure the dial only completes
|
||||
// using the pre-resolved IP/port when used for the correct host.
|
||||
type preresolvedDialer struct {
|
||||
ip net.IP
|
||||
ip netip.Addr
|
||||
port int
|
||||
hostname string
|
||||
timeout time.Duration
|
||||
|
@ -170,14 +170,14 @@ type httpValidationTarget struct {
|
|||
// following redirects)
|
||||
query string
|
||||
// all of the IP addresses available for the host
|
||||
available []net.IP
|
||||
available []netip.Addr
|
||||
// the IP addresses that were tried for validation previously that were cycled
|
||||
// out of cur by calls to nextIP()
|
||||
tried []net.IP
|
||||
tried []netip.Addr
|
||||
// the IP addresses that will be drawn from by calls to nextIP() to set curIP
|
||||
next []net.IP
|
||||
next []netip.Addr
|
||||
// the current IP address being used for validation (if any)
|
||||
cur net.IP
|
||||
cur netip.Addr
|
||||
// the DNS resolver(s) that will attempt to fulfill the validation request
|
||||
resolvers bdns.ResolverAddrs
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ func (va *ValidationAuthorityImpl) newHTTPValidationTarget(
|
|||
port int,
|
||||
path string,
|
||||
query string) (*httpValidationTarget, error) {
|
||||
var addrs []net.IP
|
||||
var addrs []netip.Addr
|
||||
var resolvers bdns.ResolverAddrs
|
||||
switch ident.Type {
|
||||
case identifier.TypeDNS:
|
||||
|
@ -219,7 +219,11 @@ func (va *ValidationAuthorityImpl) newHTTPValidationTarget(
|
|||
}
|
||||
addrs, resolvers = dnsAddrs, dnsResolvers
|
||||
case identifier.TypeIP:
|
||||
addrs = []net.IP{net.ParseIP(ident.Value)}
|
||||
netIP, err := netip.ParseAddr(ident.Value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't parse IP address %q: %s", ident.Value, err)
|
||||
}
|
||||
addrs = []netip.Addr{netIP}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown identifier type: %s", ident.Type)
|
||||
}
|
||||
|
@ -245,15 +249,15 @@ func (va *ValidationAuthorityImpl) newHTTPValidationTarget(
|
|||
} else if !hasV6Addrs && hasV4Addrs {
|
||||
// If there are no v6 addrs and there are v4 addrs then use the first v4
|
||||
// address. There's no fallback address.
|
||||
target.next = []net.IP{v4Addrs[0]}
|
||||
target.next = []netip.Addr{v4Addrs[0]}
|
||||
} else if hasV6Addrs && hasV4Addrs {
|
||||
// If there are both v6 addrs and v4 addrs then use the first v6 address and
|
||||
// fallback with the first v4 address.
|
||||
target.next = []net.IP{v6Addrs[0], v4Addrs[0]}
|
||||
target.next = []netip.Addr{v6Addrs[0], v4Addrs[0]}
|
||||
} else if hasV6Addrs && !hasV4Addrs {
|
||||
// If there are just v6 addrs then use the first v6 address. There's no
|
||||
// fallback address.
|
||||
target.next = []net.IP{v6Addrs[0]}
|
||||
target.next = []netip.Addr{v6Addrs[0]}
|
||||
}
|
||||
|
||||
// Advance the target using nextIP to populate the cur IP before returning
|
||||
|
@ -380,7 +384,7 @@ func (va *ValidationAuthorityImpl) setupHTTPValidation(
|
|||
|
||||
// Get the target IP to build a preresolved dialer with
|
||||
targetIP := target.cur
|
||||
if targetIP == nil {
|
||||
if (targetIP == netip.Addr{}) {
|
||||
return nil,
|
||||
record,
|
||||
fmt.Errorf(
|
||||
|
|
100
va/http_test.go
100
va/http_test.go
|
@ -35,7 +35,7 @@ import (
|
|||
// a dial to another host produces the expected dialerMismatchError.
|
||||
func TestDialerMismatchError(t *testing.T) {
|
||||
d := preresolvedDialer{
|
||||
ip: net.ParseIP("127.0.0.1"),
|
||||
ip: netip.MustParseAddr("127.0.0.1"),
|
||||
port: 1337,
|
||||
hostname: "letsencrypt.org",
|
||||
}
|
||||
|
@ -61,8 +61,8 @@ type dnsMockReturnsUnroutable struct {
|
|||
*bdns.MockClient
|
||||
}
|
||||
|
||||
func (mock dnsMockReturnsUnroutable) LookupHost(_ context.Context, hostname string) ([]net.IP, bdns.ResolverAddrs, error) {
|
||||
return []net.IP{net.ParseIP("198.51.100.1")}, bdns.ResolverAddrs{"dnsMockReturnsUnroutable"}, nil
|
||||
func (mock dnsMockReturnsUnroutable) LookupHost(_ context.Context, hostname string) ([]netip.Addr, bdns.ResolverAddrs, error) {
|
||||
return []netip.Addr{netip.MustParseAddr("198.51.100.1")}, bdns.ResolverAddrs{"dnsMockReturnsUnroutable"}, nil
|
||||
}
|
||||
|
||||
// TestDialerTimeout tests that the preresolvedDialer's DialContext
|
||||
|
@ -199,7 +199,7 @@ func TestHTTPValidationTarget(t *testing.T) {
|
|||
// order.
|
||||
for i, expectedIP := range tc.ExpectedIPs {
|
||||
gotIP := target.cur
|
||||
if gotIP == nil {
|
||||
if (gotIP == netip.Addr{}) {
|
||||
t.Errorf("Expected IP %d to be %s got nil", i, expectedIP)
|
||||
} else {
|
||||
test.AssertEquals(t, gotIP.String(), expectedIP)
|
||||
|
@ -531,12 +531,12 @@ func TestSetupHTTPValidation(t *testing.T) {
|
|||
DnsName: "ipv4.and.ipv6.localhost",
|
||||
Port: strconv.Itoa(va.httpPort),
|
||||
URL: "http://ipv4.and.ipv6.localhost/yellow/brick/road",
|
||||
AddressesResolved: []net.IP{net.ParseIP("::1"), net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("::1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("::1"), netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("::1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
ExpectedDialer: &preresolvedDialer{
|
||||
ip: net.ParseIP("::1"),
|
||||
ip: netip.MustParseAddr("::1"),
|
||||
port: va.httpPort,
|
||||
timeout: va.singleDialTimeout,
|
||||
},
|
||||
|
@ -549,12 +549,12 @@ func TestSetupHTTPValidation(t *testing.T) {
|
|||
DnsName: "ipv4.and.ipv6.localhost",
|
||||
Port: strconv.Itoa(va.httpsPort),
|
||||
URL: "https://ipv4.and.ipv6.localhost/yellow/brick/road",
|
||||
AddressesResolved: []net.IP{net.ParseIP("::1"), net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("::1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("::1"), netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("::1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
ExpectedDialer: &preresolvedDialer{
|
||||
ip: net.ParseIP("::1"),
|
||||
ip: netip.MustParseAddr("::1"),
|
||||
port: va.httpsPort,
|
||||
timeout: va.singleDialTimeout,
|
||||
},
|
||||
|
@ -886,8 +886,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: url,
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
})
|
||||
}
|
||||
|
@ -907,8 +907,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: url,
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
})
|
||||
}
|
||||
|
@ -949,8 +949,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/timeout",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -984,8 +984,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/redir-bad-proto",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1002,8 +1002,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/redir-bad-port",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1018,16 +1018,16 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/redir-bare-ipv4",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
{
|
||||
DnsName: "127.0.0.1",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://127.0.0.1/ok",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
},
|
||||
},
|
||||
}, {
|
||||
|
@ -1041,16 +1041,16 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "ipv6.localhost",
|
||||
Port: strconv.Itoa(httpPortIPv6),
|
||||
URL: "http://ipv6.localhost/redir-bare-ipv6",
|
||||
AddressesResolved: []net.IP{net.ParseIP("::1")},
|
||||
AddressUsed: net.ParseIP("::1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("::1")},
|
||||
AddressUsed: netip.MustParseAddr("::1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
{
|
||||
DnsName: "::1",
|
||||
Port: strconv.Itoa(httpPortIPv6),
|
||||
URL: "http://[::1]/ok",
|
||||
AddressesResolved: []net.IP{net.ParseIP("::1")},
|
||||
AddressUsed: net.ParseIP("::1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("::1")},
|
||||
AddressUsed: netip.MustParseAddr("::1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1065,8 +1065,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/redir-path-too-long",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1082,8 +1082,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/bad-status-code",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1099,8 +1099,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/303-see-other",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1117,8 +1117,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/resp-too-big",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1134,8 +1134,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "ipv6.localhost",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://ipv6.localhost/ok",
|
||||
AddressesResolved: []net.IP{net.ParseIP("::1")},
|
||||
AddressUsed: net.ParseIP("::1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("::1")},
|
||||
AddressUsed: netip.MustParseAddr("::1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1150,18 +1150,18 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "ipv4.and.ipv6.localhost",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://ipv4.and.ipv6.localhost/ok",
|
||||
AddressesResolved: []net.IP{net.ParseIP("::1"), net.ParseIP("127.0.0.1")},
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("::1"), netip.MustParseAddr("127.0.0.1")},
|
||||
// The first validation record should have used the IPv6 addr
|
||||
AddressUsed: net.ParseIP("::1"),
|
||||
AddressUsed: netip.MustParseAddr("::1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
{
|
||||
DnsName: "ipv4.and.ipv6.localhost",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://ipv4.and.ipv6.localhost/ok",
|
||||
AddressesResolved: []net.IP{net.ParseIP("::1"), net.ParseIP("127.0.0.1")},
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("::1"), netip.MustParseAddr("127.0.0.1")},
|
||||
// The second validation record should have used the IPv4 addr as a fallback
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1176,8 +1176,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/ok",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1192,16 +1192,16 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/redir-uppercase-publicsuffix",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
{
|
||||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/ok",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
@ -1221,8 +1221,8 @@ func TestFetchHTTP(t *testing.T) {
|
|||
DnsName: "example.com",
|
||||
Port: strconv.Itoa(httpPortIPv4),
|
||||
URL: "http://example.com/printf-verbs",
|
||||
AddressesResolved: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
AddressUsed: net.ParseIP("127.0.0.1"),
|
||||
AddressesResolved: []netip.Addr{netip.MustParseAddr("127.0.0.1")},
|
||||
AddressUsed: netip.MustParseAddr("127.0.0.1"),
|
||||
ResolverAddrs: []string{"MockClient"},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -68,7 +68,7 @@ func (va *ValidationAuthorityImpl) tryGetChallengeCert(
|
|||
Port: strconv.Itoa(va.tlsPort),
|
||||
}
|
||||
|
||||
var addrs []net.IP
|
||||
var addrs []netip.Addr
|
||||
switch ident.Type {
|
||||
case identifier.TypeDNS:
|
||||
// Resolve IP addresses for the identifier
|
||||
|
@ -79,7 +79,11 @@ func (va *ValidationAuthorityImpl) tryGetChallengeCert(
|
|||
addrs, validationRecord.ResolverAddrs = dnsAddrs, dnsResolvers
|
||||
validationRecord.AddressesResolved = addrs
|
||||
case identifier.TypeIP:
|
||||
addrs = []net.IP{net.ParseIP(ident.Value)}
|
||||
netIP, err := netip.ParseAddr(ident.Value)
|
||||
if err != nil {
|
||||
return nil, nil, validationRecord, fmt.Errorf("can't parse IP address %q: %s", ident.Value, err)
|
||||
}
|
||||
addrs = []netip.Addr{netIP}
|
||||
default:
|
||||
// This should never happen. The calling function should check the
|
||||
// identifier type.
|
||||
|
@ -172,11 +176,12 @@ func (va *ValidationAuthorityImpl) getChallengeCert(
|
|||
if err != nil {
|
||||
va.log.Infof("%s connection failure for %s. err=[%#v] errStr=[%s]", core.ChallengeTypeTLSALPN01, ident, err, err)
|
||||
host, _, splitErr := net.SplitHostPort(hostPort)
|
||||
if splitErr == nil && net.ParseIP(host) != nil {
|
||||
netIP, ipErr := netip.ParseAddr(host)
|
||||
if splitErr == nil && ipErr == nil {
|
||||
// Wrap the validation error and the IP of the remote host in an
|
||||
// IPError so we can display the IP in the problem details returned
|
||||
// to the client.
|
||||
return nil, nil, ipError{net.ParseIP(host), err}
|
||||
return nil, nil, ipError{netIP, err}
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
6
va/va.go
6
va/va.go
|
@ -301,13 +301,13 @@ func maxAllowedFailures(perspectiveCount int) int {
|
|||
// ipError is an error type used to pass though the IP address of the remote
|
||||
// host when an error occurs during HTTP-01 and TLS-ALPN domain validation.
|
||||
type ipError struct {
|
||||
ip net.IP
|
||||
ip netip.Addr
|
||||
err error
|
||||
}
|
||||
|
||||
// newIPError wraps an error and the IP of the remote host in an ipError so we
|
||||
// can display the IP in the problem details returned to the client.
|
||||
func newIPError(ip net.IP, err error) error {
|
||||
func newIPError(ip netip.Addr, err error) error {
|
||||
return ipError{ip: ip, err: err}
|
||||
}
|
||||
|
||||
|
@ -330,7 +330,7 @@ func detailedError(err error) *probs.ProblemDetails {
|
|||
var ipErr ipError
|
||||
if errors.As(err, &ipErr) {
|
||||
detailedErr := detailedError(ipErr.err)
|
||||
if ipErr.ip == nil {
|
||||
if (ipErr.ip == netip.Addr{}) {
|
||||
// This should never happen.
|
||||
return detailedErr
|
||||
}
|
||||
|
|
|
@ -723,12 +723,12 @@ func TestMultiVALogging(t *testing.T) {
|
|||
func TestDetailedError(t *testing.T) {
|
||||
cases := []struct {
|
||||
err error
|
||||
ip net.IP
|
||||
ip netip.Addr
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
err: ipError{
|
||||
ip: net.ParseIP("192.168.1.1"),
|
||||
ip: netip.MustParseAddr("192.168.1.1"),
|
||||
err: &net.OpError{
|
||||
Op: "dial",
|
||||
Net: "tcp",
|
||||
|
@ -760,7 +760,7 @@ func TestDetailedError(t *testing.T) {
|
|||
Err: syscall.ECONNRESET,
|
||||
},
|
||||
},
|
||||
ip: nil,
|
||||
ip: netip.Addr{},
|
||||
expected: "Connection reset by peer",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
"crypto/rsa"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -136,7 +136,8 @@ func (r *responseWriterWithStatus) WriteHeader(code int) {
|
|||
func (th *TopHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Check that this header is well-formed, since we assume it is when logging.
|
||||
realIP := r.Header.Get("X-Real-IP")
|
||||
if net.ParseIP(realIP) == nil {
|
||||
_, err := netip.ParseAddr(realIP)
|
||||
if err != nil {
|
||||
realIP = "0.0.0.0"
|
||||
}
|
||||
|
||||
|
|
13
wfe2/wfe.go
13
wfe2/wfe.go
|
@ -13,6 +13,7 @@ import (
|
|||
"math/rand/v2"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -660,7 +661,7 @@ func contactsToEmails(contacts *[]string) []string {
|
|||
// function is returned that can be called to refund the quota if the account
|
||||
// creation fails, the func will be nil if any error was encountered during the
|
||||
// check.
|
||||
func (wfe *WebFrontEndImpl) checkNewAccountLimits(ctx context.Context, ip net.IP) (func(), error) {
|
||||
func (wfe *WebFrontEndImpl) checkNewAccountLimits(ctx context.Context, ip netip.Addr) (func(), error) {
|
||||
txns, err := wfe.txnBuilder.NewAccountLimitTransactions(ip)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("building new account limit transactions: %w", err)
|
||||
|
@ -2701,16 +2702,16 @@ func (wfe *WebFrontEndImpl) RenewalInfo(ctx context.Context, logEvent *web.Reque
|
|||
}
|
||||
}
|
||||
|
||||
func extractRequesterIP(req *http.Request) (net.IP, error) {
|
||||
ip := net.ParseIP(req.Header.Get("X-Real-IP"))
|
||||
if ip != nil {
|
||||
func extractRequesterIP(req *http.Request) (netip.Addr, error) {
|
||||
ip, err := netip.ParseAddr(req.Header.Get("X-Real-IP"))
|
||||
if err == nil {
|
||||
return ip, nil
|
||||
}
|
||||
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return netip.Addr{}, err
|
||||
}
|
||||
return net.ParseIP(host), nil
|
||||
return netip.ParseAddr(host)
|
||||
}
|
||||
|
||||
func urlForAuthz(authz core.Authorization, request *http.Request) string {
|
||||
|
|
Loading…
Reference in New Issue