Draft v0.13: checkResolvedIp counts an address of NAT64 by its IPv4

testdata at a83b44d, with resolved_ip.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main
dev 1 day ago
parent e2c51bca3a
commit 28f0c3f524

@ -4,6 +4,11 @@ Cambios notables de la librería TypeScript y de la página. El proyecto usa ver
## Especificación 0.10, en la rama `v0.10` — sin versión
### NAT64, del borrador v0.13 (06-10-2026)
- `testdata` se sincroniza con `datekeys-go` en `a83b44d`, el borrador v0.13, sin aprobar: añade `vectors/resolved_ip.json`, y ningún otro fichero cambia. `SPEC_VERSION` sigue en `0.12`.
- `checkResolvedIp` cuenta una dirección de NAT64 a la que resuelve un nombre, de `64:ff9b::/96` o del prefijo de la red (el parámetro `nat64`), por la IPv4 que lleva dentro, con los textos de `locator.CheckResolvedIP` de Go. `ipaddr.ts` exporta `isIpv4In6`. Un bloque nuevo de `vectors.test.ts` corre los 42 casos.
### El localizador de `datekeys.capsule` (06-10-2026)
El paquete `locator` de `datekeys-go` en `spec-v0.12` (§43 a §44.1), con los mismos checks en el mismo orden, los mismos códigos y los mismos textos de error, byte a byte, como lo portó `datekeys-dart` en sus partes 7a y 7b.

@ -114,7 +114,7 @@ El localizador sigue al paquete `locator` de Go en `spec-v0.12` también donde e
- `parseInfo` no mira la cadena del stanza sellado, acepta una cabecera `age` sin cuerpo, e `infoExtension` no comprueba que el perfil esté pinneado;
- `openSealed` lee como mucho 1 MiB del texto del localizador, y un defecto posterior queda oculto tras el error de `unmarshalLocator`.
`checkResolvedIp` rechaza hoy `64:ff9b::/96`, la de NAT64, como el §44.1 de la v0.12; es una función aparte, para cambiarla sola si una versión siguiente del spec lo cambia.
`checkResolvedIp` sigue el borrador v0.13 (§44.1, cambio 1 del §76), como `locator.CheckResolvedIP` de Go: una dirección de NAT64 a la que resuelve un nombre, de `64:ff9b::/96` o del prefijo de la red que la aplicación le pasa en `nat64`, cuenta por la IPv4 que lleva dentro. `vectors.test.ts` corre los 42 casos de `resolved_ip.json`.
Diferencias de forma con Go, sin efecto en lo que se lee o se escribe:

@ -41,8 +41,8 @@ export const isIpv4 = (a: IpAddress): boolean => a.bytes.length === 4;
/** Whether `a` is an IPv6 address, IPv4-mapped ones included. */
export const isIpv6 = (a: IpAddress): boolean => a.bytes.length === 16;
// Whether the IPv6 address a is an IPv4-mapped one, of ::ffff:0:0/96.
function is4In6(a: IpAddress): boolean {
/** Whether `a` is an IPv4-mapped IPv6 address, of ::ffff:0:0/96, as netip's Is4In6. */
export function isIpv4In6(a: IpAddress): boolean {
for (let i = 0; i < 10; i++) if (a.bytes[i] !== 0) return false;
return a.bytes[10] === 0xff && a.bytes[11] === 0xff;
}
@ -59,7 +59,7 @@ export function ipString(a: IpAddress): string {
const b = a.bytes;
if (isIpv4(a)) return dotted(b, 0);
const zoned = a.zone === '' ? '' : `%${a.zone}`;
if (is4In6(a)) return `::ffff:${dotted(b, 12)}${zoned}`;
if (isIpv4In6(a)) return `::ffff:${dotted(b, 12)}${zoned}`;
const groups: number[] = [];
for (let i = 0; i < 8; i++) groups.push((b[2 * i]! << 8) | b[2 * i + 1]!);
// The first longest run of two or more groups of zeros, as appendTo6.

@ -123,7 +123,7 @@ describe('IP addresses (locator-uris.json)', () => {
}
});
it('checkResolvedIp checks the bytes of an address as publicIP of Go, IPv4-mapped and NAT64 addresses not public', () => {
it('checkResolvedIp checks the bytes of an address as publicIP of Go, IPv4-mapped addresses not public', () => {
const cases = rows(uris, 'public');
expect(cases.length).toBe(868);
for (const c of cases) {
@ -135,12 +135,20 @@ describe('IP addresses (locator-uris.json)', () => {
const a = ipFromBytes(b);
expect(ipString(a)).toBe(c[2]);
expect(isPublicIp(a), ipString(a)).toBe(c[1]);
// An address of NAT64 counts by the IPv4 address it holds (spec
// v0.13): vectors.test.ts runs resolved_ip.json.
if (toHex(b).startsWith('0064ff9b0000000000000000')) continue;
expect(errorText(() => checkResolvedIp(b))).toBe(
c[1] === true ? '' : `locator: an https address whose name resolves to ${c[2] as string}, an IP address that is not public`,
);
}
expect(() => checkResolvedIp(Uint8Array.of(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 8, 8, 8, 8))).toThrow(LocatorError);
expect(() => checkResolvedIp(fromHex('0064ff9b000000000000000008080808'))).toThrow(LocatorError);
checkResolvedIp(fromHex('0064ff9b000000000000000008080808'));
expect(() => checkResolvedIp(fromHex('0064ff9b00000000000000000a000001'))).toThrow(LocatorError);
expect(errorText(() => checkResolvedIp(Uint8Array.of(8, 8, 8, 8), '::ffff:0.0.0.0/96'))).toBe('locator: the NAT64 prefix ::ffff:0.0.0.0/96 is not an IPv6 prefix');
for (const bad of ['64:ff9b::', '64:ff9b::/129', '64:ff9b::/-1', '64:ff9b::/096', 'x/96', '64:ff9b::%eth0/96']) {
expect(() => checkResolvedIp(Uint8Array.of(8, 8, 8, 8), bad), bad).toThrow(RangeError);
}
checkResolvedIp(Uint8Array.of(8, 8, 8, 8));
// An embedded IPv4 address with no room left, which netip refuses too.
expect(parseIpAddress('1::2:3:4:5:6:7:1.2.3.4')).toBeUndefined();

@ -40,7 +40,7 @@ import { type Decoder, Encoder, MAX_SAFE_UINT, unmarshal } from './cbor.ts';
import { compactDateKey, type DateKey, parseDateKey } from './datekey.ts';
import { DateKeysError, withContext } from './errors.ts';
import { CAPSULE_ID, type Extension, type ExtensionRegistry, newExtension, NOTE_ID } from './extension.ts';
import { ipFromBytes, ipString, isIpv4, isIpv6, isPublicIp, parseIpAddress } from './ipaddr.ts';
import { type IpAddress, ipFromBytes, ipString, isIpv4, isIpv4In6, isIpv6, isPublicIp, parseIpAddress } from './ipaddr.ts';
import { checkNote, checkNoteData, MAX_NOTE_LEN } from './note.ts';
/** The most addresses of a locator (spec §44.1). */
@ -573,19 +573,112 @@ function uvarint(b: readonly number[], at: number): [bigint, number] | undefined
* redirections included (spec §44.1). Public is what an IP literal of an
* address must be, as publicIP of Go: an IPv4 address outside the blocks of
* §44.1, or an IPv6 address of 2000::/3 outside 2001::/23, 2001:db8::/32,
* 2002::/16 and 3fff::/20. An IPv6 address that holds an IPv4 one is not,
* IPv4-mapped and NAT64 (64:ff9b::/96) included: an IPv4 address is checked
* as its 4 bytes.
* 2002::/16 and 3fff::/20. An IPv4-mapped address is not public: an IPv4
* address is checked as its 4 bytes.
*
* Throws a LocatorError for an address that is not public, with the text of
* datekeys-dart's checkResolvedIp, and a RangeError for any other length. Go
* has no such function: a reader of the reference does not download.
* On an IPv6-only network with DNS64 and NAT64, a name that has only IPv4
* addresses resolves to an IPv6 address that holds one (RFC 6052): one of the
* well-known prefix 64:ff9b::/96 is public when the IPv4 address in its last
* 32 bits is (spec v0.13, §44.1). `nat64` is the NAT64 prefix of the network,
* in the notation of netip.ParsePrefix (`64:ff9b:1::/48`), which the
* application discovers with RFC 7050, or undefined for none: an address in
* it is public only when the IPv4 address it holds, at the positions of RFC
* 6052, is, even when the prefix is a public one. The prefix must have one of
* the lengths of RFC 6052 and lie in 64:ff9b::/16 or be a public IPv6 prefix.
*
* Throws a LocatorError for an address that is not public or a prefix that
* cannot be one of NAT64, with the texts of locator.CheckResolvedIP of Go,
* and a RangeError for an address of another length or a prefix that does
* not parse.
*/
export function checkResolvedIp(ip: Uint8Array): void {
export function checkResolvedIp(ip: Uint8Array, nat64?: string): void {
const a = ipFromBytes(ip);
let network: Nat64Prefix | undefined;
if (nat64 !== undefined) {
network = parseNat64Prefix(nat64);
checkNat64Prefix(network);
}
// The prefixes of NAT64 decide first: the prefix of a network may be a
// public one, and an address in it reaches the IPv4 address it holds,
// which may be private.
for (const p of network === undefined ? [NAT64_WELL_KNOWN] : [NAT64_WELL_KNOWN, network]) {
if (!prefixContains(p, a)) continue;
const v4 = nat64Ipv4(p, a);
if (v4 === undefined) {
throw fail(`an https address whose name resolves to ${ipString(a)}, an address of the NAT64 prefix ${prefixString(p)} whose bits 64 to 71 are not zero`);
}
if (!isPublicIp(v4)) {
throw fail(`an https address whose name resolves to ${ipString(a)}, an address of NAT64 that holds ${ipString(v4)}, an IP address that is not public`);
}
return;
}
if (!isPublicIp(a)) throw fail(`an https address whose name resolves to ${ipString(a)}, an IP address that is not public`);
}
// A NAT64 prefix (RFC 6052), as the netip.Prefix that CheckResolvedIP of Go
// receives: the address as written and its length, the bits after the length
// kept, so that checkNat64Prefix can refuse them.
interface Nat64Prefix {
readonly addr: IpAddress;
readonly bits: number;
}
// netip.ParsePrefix: an address without a zone, "/", and a length in
// decimal without a sign or leading zeros, up to the bits of the address.
function parseNat64Prefix(s: string): Nat64Prefix {
const slash = s.lastIndexOf('/');
const addr = slash < 0 ? undefined : parseIpAddress(s.slice(0, slash));
const len = slash < 0 ? '' : s.slice(slash + 1);
const bits = /^(0|[1-9][0-9]{0,2})$/.test(len) ? Number(len) : -1;
if (addr === undefined || addr.zone !== '' || bits < 0 || bits > addr.bytes.length * 8) {
throw new RangeError(`locator: ${JSON.stringify(s)} is not an IP prefix`);
}
return { addr, bits };
}
const NAT64_WELL_KNOWN = parseNat64Prefix('64:ff9b::/96');
const NAT64_BLOCK = parseNat64Prefix('64:ff9b::/16');
const prefixString = (p: Nat64Prefix): string => `${ipString(p.addr)}/${p.bits}`;
// netip.Prefix.Contains: an address of the same family, without a zone,
// whose first bits are those of the prefix.
function prefixContains(p: Nat64Prefix, a: IpAddress): boolean {
const pb = p.addr.bytes;
const b = a.bytes;
if (a.zone !== '' || b.length !== pb.length) return false;
for (let i = 0; i < p.bits; i++) {
const m = 0x80 >> (i & 7);
if ((b[i >> 3]! & m) !== (pb[i >> 3]! & m)) return false;
}
return true;
}
// checkNAT64Prefix of Go.
function checkNat64Prefix(p: Nat64Prefix): void {
const b = p.addr.bytes;
if (!isIpv6(p.addr) || isIpv4In6(p.addr)) throw fail(`the NAT64 prefix ${prefixString(p)} is not an IPv6 prefix`);
for (let i = p.bits; i < 128; i++) {
if ((b[i >> 3]! & (0x80 >> (i & 7))) !== 0) throw fail(`the NAT64 prefix ${prefixString(p)} has bits set after its length`);
}
if (![32, 40, 48, 56, 64, 96].includes(p.bits)) throw fail(`the NAT64 prefix ${prefixString(p)} is not of 32, 40, 48, 56, 64 or 96 bits (RFC 6052)`);
if (!prefixContains(NAT64_BLOCK, p.addr) && !isPublicIp(p.addr)) {
throw fail(`the NAT64 prefix ${prefixString(p)} is neither in 64:ff9b::/16 nor a public IPv6 prefix`);
}
}
// nat64IPv4 of Go: the IPv4 address that `a`, an address of the prefix `p`,
// holds at the positions of RFC 6052, section 2.2, the 32 bits after the
// prefix without bits 64 to 71, which must be zero; undefined if they are
// not.
function nat64Ipv4(p: Nat64Prefix, a: IpAddress): IpAddress | undefined {
const b = a.bytes;
if (p.bits < 96 && b[8] !== 0) return undefined;
const v4: number[] = [];
for (let i = p.bits >> 3; v4.length < 4; i++) if (i !== 8) v4.push(b[i]!);
return ipFromBytes(Uint8Array.from(v4));
}
// ---------------------------------------------------------------------------
// The locator

@ -50,6 +50,7 @@ import { inspect, inspectJSON, inspectView } from './inspect.ts';
import {
addressHost,
BLOCK,
checkResolvedIp,
checkURI,
LocatorError,
marshalLocator,
@ -59,6 +60,7 @@ import {
unmarshalLocator,
usableAddresses,
} from './locator.ts';
import { parseIpAddress } from './ipaddr.ts';
import { checkNoteData, newNote, NOTE_ID, publicNote, unusableNote } from './note.ts';
import { open } from './open.ts';
import { checkPath, nfd, pathKey } from './pathrule.ts';
@ -1550,6 +1552,54 @@ describe('vectors/locator.json', () => {
});
});
// ---------------------------------------------------------------------------
// vectors/resolved_ip.json
//
// The IP address that the name of an https address of a locator resolves to,
// the NAT64 prefix of the network or none, and whether a reader may connect
// (spec §44.1 of the draft v0.13): ok, or the text of Go's
// locator.CheckResolvedIP.
interface ResolvedIpVector {
name: string;
ip: string;
nat64: string;
error?: string;
}
describe('vectors/resolved_ip.json', () => {
const f = load('vectors/resolved_ip.json', (json) => {
const o = object(json, 'resolved_ip.json');
keys(o, 'resolved_ip.json', ['spec', 'description', 'cases']);
checkSpec(o, 'resolved_ip.json');
return array(o.cases, 'cases').map((v, i): ResolvedIpVector => {
const at = `cases[${i}]`;
const c = object(v, at);
const res = str(c.result, `${at}.result`);
if (res !== 'ok' && res !== 'error') throw new FormatError(`${at}.result`, 'not ok or error');
keys(c, at, ['name', 'ip', 'nat64', 'result', ...(res === 'ok' ? [] : ['error'])]);
const r: ResolvedIpVector = { name: str(c.name, `${at}.name`), ip: str(c.ip, `${at}.ip`), nat64: str(c.nat64, `${at}.nat64`) };
if (res === 'error') r.error = str(c.error, `${at}.error`);
return r;
});
});
if (f === undefined) return;
it('has the cases of README, that pass and that fail', () => {
expect(f.length).toBeGreaterThanOrEqual(40);
expect(f.some((c) => c.error === undefined)).toBe(true);
expect(f.some((c) => c.error !== undefined)).toBe(true);
});
it.each(f.map((c) => [c.name, c] as const))('%s', (_name, c) => {
const ip = parseIpAddress(c.ip);
expect(ip, c.ip).toBeDefined();
const check = (): void => checkResolvedIp(ip!.bytes, c.nat64 === '' ? undefined : c.nat64);
if (c.error === undefined) expect(check).not.toThrow();
else expect(check).toThrow(new LocatorError(c.error));
});
});
// The vector files the blocks above run; a new export needs its own block.
const VECTOR_FILES = [
'vectors/cbor.json',
@ -1565,6 +1615,7 @@ const VECTOR_FILES = [
'vectors/paths.json',
'vectors/profile_quicknet.json',
'vectors/quicknet_rounds.json',
'vectors/resolved_ip.json',
'vectors/security.json',
'vectors/security_cms.json',
'vectors/tlock_ibe.json',

23
testdata/README.md vendored

@ -56,6 +56,7 @@ Conventions for every file:
| `vectors/security_cms.json` | security areas with a signature of `alg` 2 or a seal of `seal_type` 2, each with its context, verdicts, results and lines | §29.7, §29.10, §29.11 |
| `vectors/ed25519_strict.json` | Ed25519 signatures and the result of the strict profile of the author signature | §29.9 |
| `vectors/note.json` | the data of the public note and the result of its rules | §24.1, §29.6 |
| `vectors/resolved_ip.json` | the IP address a name of a locator resolves to, NAT64 included, and whether a reader may connect | §44.1 (draft v0.13) |
| `vectors/wordkey.json` | the key of words: the words of a text, what a writer refuses, and the identity the words derive | §38.1, §64 |
| `vectors/locator.json` | the extension `datekeys.capsule` of a `.dkk`, its envelope and its locator, and what a reader rejects and uses of them | §44.1, §64 |
| `vectors/mutations.json` | the mutation corpus: the 178 mutations of §64 and further cases | §63, §64 |
@ -585,6 +586,28 @@ feed, a space at either end, U+202E, U+200B, a byte order mark, a
noncharacter, a byte that is not UTF-8 and the UTF-8 of a lone surrogate,
refused.
## `vectors/resolved_ip.json`
The IP address that the name of an https address of a locator resolves to,
which a reader checks on every connection (spec §44.1 of the draft v0.13):
`ip`, `nat64`, the NAT64 prefix of the network that the reader knows, or ""
for none, and `result`, `ok`, or `error` with the text of the reference in
`error`.
```json
{ "name": "the well-known prefix with 192.168.1.10", "ip": "64:ff9b::c0a8:10a", "nat64": "", "result": "error", "error": "locator: an https address whose name resolves to 64:ff9b::c0a8:10a, an address of NAT64 that holds 192.168.1.10, an IP address that is not public" }
```
A public address is accepted. An address of NAT64 (RFC 6052) of
`64:ff9b::/96`, or of the prefix of the network, counts by the IPv4 address
it holds, at the positions of RFC 6052: the cases put a public one and one of
several blocks that are not public in each, and the prefix of the network in
each length of RFC 6052. A prefix of another length, with bits after its
length, outside `64:ff9b::/16` and the public IPv6 addresses, or of IPv4, is
refused. Among the addresses that are not public: IPv4-mapped, 6to4, Teredo,
link-local, unique local, loopback, and the local-use prefix of RFC 8215
without the prefix of the network.
## `vectors/wordkey.json`
The key of words of spec §38.1, the cases that §64 of v0.11 asks for, in

@ -1,8 +1,8 @@
{
"module": "g.activething.com/go/DateKeys",
"commit": "fe405e2348744f50e54c72e35ae10470a01dc552",
"commit": "a83b44d1c88ca253f7fc5340c58ef38a170a6f2c",
"files": {
"README.md": "0c4244bf5ec7fe3865bef4dd2f69e4370184bc95060339d82422a4ff29d44b75",
"README.md": "9832dcbef136c29ae5147e99e041e5419b7b3e3f3a24c12fe0284fe3f62a4367",
"fixtures/empty_payload.dkc": "871e9bf05b52bbae17f3adfbbf97b46e7f0e53aa8f57bcaa506e43f36f53a9d4",
"fixtures/empty_payload.inspect.json": "373e5d012b023ad58bbb54cbdffe0bed9e50c637438a4083ddb74d5414c59f59",
"fixtures/empty_payload.json": "a8586332e32de5e052e48a420a8a61ec81b1274c1867527f43c37b5d6d9ba4ea",
@ -132,6 +132,7 @@
"vectors/paths.json": "bfdbcc9ceb8f6f1220bc998e00b6d32061e49bb8e6fcd3d903a43521b86e3388",
"vectors/profile_quicknet.json": "c5b9a57db1e9c64a226c08ab4a51ffcb2e29599a74b5b145308a13ba8f195445",
"vectors/quicknet_rounds.json": "b053c423d75a602d23777aa9fe0ec7860dbfb6ee42275a88a880731338c4ffe4",
"vectors/resolved_ip.json": "cc1112aae424bc6f358a39211d7e5cc5a9a3b04c27c40e9e4070a74524055b72",
"vectors/security.json": "41da683fb4f0275c903d7e79029fed885c7b94e03c0160ab94bad6acf325f0b5",
"vectors/security_cms.json": "13e0deece70f640e4507adc33c9df25545fc30a4b0a543cff07dcdddc8923ea4",
"vectors/tlock_ibe.json": "fdc846000dd4da5fcb0d976994e07e4acf335819cf434a2badc973e90aa5dbfe",

@ -0,0 +1,287 @@
{
"spec": "0.12",
"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.",
"cases": [
{
"name": "a public IPv4 address",
"ip": "203.0.114.5",
"nat64": "",
"result": "ok"
},
{
"name": "a public IPv6 address",
"ip": "2a01:4f8::1",
"nat64": "",
"result": "ok"
},
{
"name": "a private IPv4 address",
"ip": "192.168.1.10",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 192.168.1.10, an IP address that is not public"
},
{
"name": "loopback",
"ip": "127.0.0.1",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 127.0.0.1, an IP address that is not public"
},
{
"name": "IPv6 loopback",
"ip": "::1",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to ::1, an IP address that is not public"
},
{
"name": "an IPv6 link-local address",
"ip": "fe80::1",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to fe80::1, an IP address that is not public"
},
{
"name": "an IPv6 unique local address",
"ip": "fd00::1",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to fd00::1, an IP address that is not public"
},
{
"name": "an IPv4-mapped address of a public IPv4 address",
"ip": "::ffff:203.0.114.5",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to ::ffff:203.0.114.5, an IP address that is not public"
},
{
"name": "6to4",
"ip": "2002:cb00:7205::1",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 2002:cb00:7205::1, an IP address that is not public"
},
{
"name": "Teredo",
"ip": "2001:0:cb00:7205::1",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 2001:0:cb00:7205::1, an IP address that is not public"
},
{
"name": "the well-known prefix with a public IPv4 address",
"ip": "64:ff9b::cb00:7205",
"nat64": "",
"result": "ok"
},
{
"name": "the well-known prefix with 8.8.8.8",
"ip": "64:ff9b::808:808",
"nat64": "",
"result": "ok"
},
{
"name": "the well-known prefix with an IPv4 address of 10.0.0.0/8",
"ip": "64:ff9b::a00:1",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b::a00:1, an address of NAT64 that holds 10.0.0.1, an IP address that is not public"
},
{
"name": "the well-known prefix with 192.168.1.10",
"ip": "64:ff9b::c0a8:10a",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b::c0a8:10a, an address of NAT64 that holds 192.168.1.10, an IP address that is not public"
},
{
"name": "the well-known prefix with loopback",
"ip": "64:ff9b::7f00:1",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b::7f00:1, an address of NAT64 that holds 127.0.0.1, an IP address that is not public"
},
{
"name": "the well-known prefix with 169.254.169.254",
"ip": "64:ff9b::a9fe:a9fe",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b::a9fe:a9fe, an address of NAT64 that holds 169.254.169.254, an IP address that is not public"
},
{
"name": "the well-known prefix with 100.64.0.1",
"ip": "64:ff9b::6440:1",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b::6440:1, an address of NAT64 that holds 100.64.0.1, an IP address that is not public"
},
{
"name": "the well-known prefix with 0.0.0.0",
"ip": "64:ff9b::",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b::, an address of NAT64 that holds 0.0.0.0, an IP address that is not public"
},
{
"name": "the well-known prefix with 255.255.255.255",
"ip": "64:ff9b::ffff:ffff",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b::ffff:ffff, an address of NAT64 that holds 255.255.255.255, an IP address that is not public"
},
{
"name": "the well-known prefix with a documentation address",
"ip": "64:ff9b::cb00:7105",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b::cb00:7105, an address of NAT64 that holds 203.0.113.5, an IP address that is not public"
},
{
"name": "an address of 64:ff9b::/16 outside 64:ff9b::/96",
"ip": "64:ff9b::1:cb00:7205",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b::1:cb00:7205, an IP address that is not public"
},
{
"name": "the local-use prefix of RFC 8215 without the prefix of the network",
"ip": "64:ff9b:1::cb00:7205",
"nat64": "",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b:1::cb00:7205, an IP address that is not public"
},
{
"name": "the well-known prefix, given as the prefix of the network",
"ip": "64:ff9b::cb00:7205",
"nat64": "64:ff9b::/96",
"result": "ok"
},
{
"name": "the well-known prefix with another prefix of the network",
"ip": "64:ff9b::cb00:7205",
"nat64": "64:ff9b:1::/48",
"result": "ok"
},
{
"name": "the local-use prefix of RFC 8215, /48",
"ip": "64:ff9b:1:cb00:72:500::",
"nat64": "64:ff9b:1::/48",
"result": "ok"
},
{
"name": "the local-use prefix, /48, with a private IPv4 address",
"ip": "64:ff9b:1:c0a8:1:a00::",
"nat64": "64:ff9b:1::/48",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b:1:c0a8:1:a00::, an address of NAT64 that holds 192.168.1.10, an IP address that is not public"
},
{
"name": "the local-use prefix, /48, with bits 64 to 71 set",
"ip": "64:ff9b:1:cb00:172:500::",
"nat64": "64:ff9b:1::/48",
"result": "error",
"error": "locator: an https address whose name resolves to 64:ff9b:1:cb00:172:500::, an address of the NAT64 prefix 64:ff9b:1::/48 whose bits 64 to 71 are not zero"
},
{
"name": "a public prefix of the network, /96",
"ip": "2a01:4f8:c0:64::cb00:7205",
"nat64": "2a01:4f8:c0:64::/96",
"result": "ok"
},
{
"name": "a public prefix of the network, /96, with a private IPv4 address",
"ip": "2a01:4f8:c0:64::c0a8:10a",
"nat64": "2a01:4f8:c0:64::/96",
"result": "error",
"error": "locator: an https address whose name resolves to 2a01:4f8:c0:64::c0a8:10a, an address of NAT64 that holds 192.168.1.10, an IP address that is not public"
},
{
"name": "a public prefix of the network, /96, with loopback",
"ip": "2a01:4f8:c0:64::7f00:1",
"nat64": "2a01:4f8:c0:64::/96",
"result": "error",
"error": "locator: an https address whose name resolves to 2a01:4f8:c0:64::7f00:1, an address of NAT64 that holds 127.0.0.1, an IP address that is not public"
},
{
"name": "a public prefix of the network, /32",
"ip": "2a01:4f8:cb00:7205::",
"nat64": "2a01:4f8::/32",
"result": "ok"
},
{
"name": "a public prefix of the network, /40",
"ip": "2a01:4f8:c0cb:72:5::",
"nat64": "2a01:4f8:c000::/40",
"result": "ok"
},
{
"name": "a public prefix of the network, /56",
"ip": "2a01:4f8:c0:64cb:0:7205::",
"nat64": "2a01:4f8:c0:6400::/56",
"result": "ok"
},
{
"name": "a public prefix of the network, /64",
"ip": "2a01:4f8:c0:64:cb:72:500:0",
"nat64": "2a01:4f8:c0:64::/64",
"result": "ok"
},
{
"name": "a public prefix of the network, /64, with a private IPv4 address",
"ip": "2a01:4f8:c0:64:c0:a801:a00:0",
"nat64": "2a01:4f8:c0:64::/64",
"result": "error",
"error": "locator: an https address whose name resolves to 2a01:4f8:c0:64:c0:a801:a00:0, an address of NAT64 that holds 192.168.1.10, an IP address that is not public"
},
{
"name": "a public address outside the prefix of the network",
"ip": "2a01:4f8::1",
"nat64": "64:ff9b:1::/48",
"result": "ok"
},
{
"name": "a prefix of the network of 80 bits",
"ip": "64:ff9b:1::cb00:7205",
"nat64": "64:ff9b:1::/80",
"result": "error",
"error": "locator: the NAT64 prefix 64:ff9b:1::/80 is not of 32, 40, 48, 56, 64 or 96 bits (RFC 6052)"
},
{
"name": "a link-local prefix of the network",
"ip": "fe80::cb00:7205",
"nat64": "fe80::/96",
"result": "error",
"error": "locator: the NAT64 prefix fe80::/96 is neither in 64:ff9b::/16 nor a public IPv6 prefix"
},
{
"name": "a unique local prefix of the network",
"ip": "fd00::cb00:7205",
"nat64": "fd00::/96",
"result": "error",
"error": "locator: the NAT64 prefix fd00::/96 is neither in 64:ff9b::/16 nor a public IPv6 prefix"
},
{
"name": "a prefix of the network of 2001:db8::/32",
"ip": "2001:db8::cb00:7205",
"nat64": "2001:db8::/96",
"result": "error",
"error": "locator: the NAT64 prefix 2001:db8::/96 is neither in 64:ff9b::/16 nor a public IPv6 prefix"
},
{
"name": "a prefix of the network with bits after its length",
"ip": "64:ff9b::cb00:7205",
"nat64": "64:ff9b::1/96",
"result": "error",
"error": "locator: the NAT64 prefix 64:ff9b::1/96 has bits set after its length"
},
{
"name": "an IPv4 prefix of the network",
"ip": "203.0.114.5",
"nat64": "203.0.114.0/24",
"result": "error",
"error": "locator: the NAT64 prefix 203.0.114.0/24 is not an IPv6 prefix"
}
]
}
Loading…
Cancel
Save

Powered by TurnKey Linux.