You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
5.7 KiB
110 lines
5.7 KiB
package testkit
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/netip"
|
|
|
|
"g.activething.com/go/DateKeys/locator"
|
|
)
|
|
|
|
// ResolvedIPVectorFile is testdata/vectors/resolved_ip.json: the IP address
|
|
// that the name of an https address of a locator resolved to, the NAT64
|
|
// prefix of the network, if the reader knows one, and whether the reader
|
|
// may connect (spec v0.13, §44.1).
|
|
type ResolvedIPVectorFile struct {
|
|
Spec string `json:"spec"`
|
|
Description string `json:"description"`
|
|
Cases []ResolvedIPVector `json:"cases"`
|
|
}
|
|
|
|
// ResolvedIPVector is an address, a NAT64 prefix or "" for none, and the
|
|
// result of locator.CheckResolvedIP: ResultOK, or "error" with its text.
|
|
type ResolvedIPVector struct {
|
|
Name string `json:"name"`
|
|
IP string `json:"ip"`
|
|
NAT64 string `json:"nat64"`
|
|
Result string `json:"result"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
// ResolvedIPVectors computes testdata/vectors/resolved_ip.json, and fails if
|
|
// a case does not get the result it is written for.
|
|
func ResolvedIPVectors() (ResolvedIPVectorFile, error) {
|
|
f := ResolvedIPVectorFile{
|
|
Spec: SpecVersion,
|
|
Description: "The IP address that the name of an https address of a locator resolves to, and whether a reader may connect (spec v0.13, 44.1): " +
|
|
"a public address, or an address of NAT64 (RFC 6052) of 64:ff9b::/96 or of the NAT64 prefix of the network, whose IPv4 address inside is public. See testdata/README.md.",
|
|
}
|
|
const bad = "error"
|
|
type tc struct{ name, ip, nat64, want string }
|
|
cases := []tc{
|
|
{"a public IPv4 address", "203.0.114.5", "", ResultOK},
|
|
{"a public IPv6 address", "2a01:4f8::1", "", ResultOK},
|
|
{"a private IPv4 address", "192.168.1.10", "", bad},
|
|
{"loopback", "127.0.0.1", "", bad},
|
|
{"IPv6 loopback", "::1", "", bad},
|
|
{"an IPv6 link-local address", "fe80::1", "", bad},
|
|
{"an IPv6 unique local address", "fd00::1", "", bad},
|
|
{"an IPv4-mapped address of a public IPv4 address", "::ffff:203.0.114.5", "", bad},
|
|
{"6to4", "2002:cb00:7205::1", "", bad},
|
|
{"Teredo", "2001:0:cb00:7205::1", "", bad},
|
|
{"the well-known prefix with a public IPv4 address", "64:ff9b::cb00:7205", "", ResultOK},
|
|
{"the well-known prefix with 8.8.8.8", "64:ff9b::808:808", "", ResultOK},
|
|
{"the well-known prefix with an IPv4 address of 10.0.0.0/8", "64:ff9b::a00:1", "", bad},
|
|
{"the well-known prefix with 192.168.1.10", "64:ff9b::c0a8:10a", "", bad},
|
|
{"the well-known prefix with loopback", "64:ff9b::7f00:1", "", bad},
|
|
{"the well-known prefix with 169.254.169.254", "64:ff9b::a9fe:a9fe", "", bad},
|
|
{"the well-known prefix with 100.64.0.1", "64:ff9b::6440:1", "", bad},
|
|
{"the well-known prefix with 0.0.0.0", "64:ff9b::", "", bad},
|
|
{"the well-known prefix with 255.255.255.255", "64:ff9b::ffff:ffff", "", bad},
|
|
{"the well-known prefix with a documentation address", "64:ff9b::cb00:7105", "", bad},
|
|
{"an address of 64:ff9b::/16 outside 64:ff9b::/96", "64:ff9b::1:cb00:7205", "", bad},
|
|
{"the local-use prefix of RFC 8215 without the prefix of the network", "64:ff9b:1::cb00:7205", "", bad},
|
|
{"the well-known prefix, given as the prefix of the network", "64:ff9b::cb00:7205", "64:ff9b::/96", ResultOK},
|
|
{"the well-known prefix with another prefix of the network", "64:ff9b::cb00:7205", "64:ff9b:1::/48", ResultOK},
|
|
{"the local-use prefix of RFC 8215, /48", "64:ff9b:1:cb00:72:500::", "64:ff9b:1::/48", ResultOK},
|
|
{"the local-use prefix, /48, with a private IPv4 address", "64:ff9b:1:c0a8:1:a00::", "64:ff9b:1::/48", bad},
|
|
{"the local-use prefix, /48, with bits 64 to 71 set", "64:ff9b:1:cb00:172:500::", "64:ff9b:1::/48", bad},
|
|
{"a public prefix of the network, /96", "2a01:4f8:c0:64::cb00:7205", "2a01:4f8:c0:64::/96", ResultOK},
|
|
{"a public prefix of the network, /96, with a private IPv4 address", "2a01:4f8:c0:64::c0a8:10a", "2a01:4f8:c0:64::/96", bad},
|
|
{"a public prefix of the network, /96, with loopback", "2a01:4f8:c0:64::7f00:1", "2a01:4f8:c0:64::/96", bad},
|
|
{"a public prefix of the network, /32", "2a01:4f8:cb00:7205::", "2a01:4f8::/32", ResultOK},
|
|
{"a public prefix of the network, /40", "2a01:4f8:c0cb:72:5::", "2a01:4f8:c000::/40", ResultOK},
|
|
{"a public prefix of the network, /56", "2a01:4f8:c0:64cb:0:7205::", "2a01:4f8:c0:6400::/56", ResultOK},
|
|
{"a public prefix of the network, /64", "2a01:4f8:c0:64:cb:72:500:0", "2a01:4f8:c0:64::/64", ResultOK},
|
|
{"a public prefix of the network, /64, with a private IPv4 address", "2a01:4f8:c0:64:c0:a801:a00:0", "2a01:4f8:c0:64::/64", bad},
|
|
{"a public address outside the prefix of the network", "2a01:4f8::1", "64:ff9b:1::/48", ResultOK},
|
|
{"a prefix of the network of 80 bits", "64:ff9b:1::cb00:7205", "64:ff9b:1::/80", bad},
|
|
{"a link-local prefix of the network", "fe80::cb00:7205", "fe80::/96", bad},
|
|
{"a unique local prefix of the network", "fd00::cb00:7205", "fd00::/96", bad},
|
|
{"a prefix of the network of 2001:db8::/32", "2001:db8::cb00:7205", "2001:db8::/96", bad},
|
|
{"a prefix of the network with bits after its length", "64:ff9b::cb00:7205", "64:ff9b::1/96", bad},
|
|
{"an IPv4 prefix of the network", "203.0.114.5", "203.0.114.0/24", bad},
|
|
}
|
|
var errs []error
|
|
for _, c := range cases {
|
|
ip, err := netip.ParseAddr(c.ip)
|
|
if err != nil {
|
|
return f, fmt.Errorf("%s: %w", c.name, err)
|
|
}
|
|
var p netip.Prefix
|
|
if c.nat64 != "" {
|
|
// ParsePrefix keeps the bits after the length, which the check
|
|
// refuses.
|
|
if p, err = netip.ParsePrefix(c.nat64); err != nil {
|
|
return f, fmt.Errorf("%s: %w", c.name, err)
|
|
}
|
|
}
|
|
v := ResolvedIPVector{Name: c.name, IP: c.ip, NAT64: c.nat64, Result: ResultOK}
|
|
if err := locator.CheckResolvedIP(ip, p); err != nil {
|
|
v.Result, v.Error = bad, err.Error()
|
|
}
|
|
if v.Result != c.want {
|
|
errs = append(errs, fmt.Errorf("resolved ip %q: %s %s, want %s", c.name, v.Result, v.Error, c.want))
|
|
}
|
|
f.Cases = append(f.Cases, v)
|
|
}
|
|
return f, errors.Join(errs...)
|
|
}
|