# Looking glass · AS402801

Ping, traceroute, DNS and TLS checks, run on request from AS402801's own network. At https://noc.andrii.net/mtlg/ they stream into the page live; from a terminal or a script, the API below runs the same tools with the same parameters.

Locations:

- `sea`: Seattle (Seattle, WA, US), at `https://sea.noc.andrii.net/api/1/…`

## The tools

Each table gives the API's own defaults, used for whatever a request leaves out. The page starts a few differently: DNS asks A and AAAA with DO set.

### Ping (`ping`)

ICMP or ICMPv6 echo requests (RFC 792, RFC 4443): round-trip times, loss and the replies' TTL.

| parameter | what | default | applies when |
|---|---|---|---|
| `target` | a host name, an IPv4 or IPv6 address, or an http(s) URL's host | required |  |
| `families` | families: `["ipv4"]`, `["ipv6"]` or both | `["ipv4","ipv6"]` |  |
| `count` | count: 1 to 10 | `5` |  |
| `size_bytes` | payload bytes: 16 to 1472 B | `56` |  |
| `df` | don't fragment: `true` or `false` | `false` |  |

### Traceroute (`trace`)

The path, hop by hop, by ICMP or UDP probes with rising TTLs (the time-exceeded answers of RFC 792 and RFC 4443), with each hop's address, AS and place, and an MTU drop flagged where a hop reports one (RFC 1191, RFC 8201).

| parameter | what | default | applies when |
|---|---|---|---|
| `target` | a host name, an IPv4 or IPv6 address, or an http(s) URL's host | required |  |
| `families` | families: `["ipv4"]`, `["ipv6"]` or both | `["ipv4","ipv6"]` |  |
| `mode` | mode: `icmp`, `udp` | `"icmp"` |  |
| `port` | UDP port: 1 to 65440 | `33434` | `mode` is udp |
| `first_hop` | first hop: 1 to 32 | `1` |  |
| `max_hops` | max hops: 1 to 32 | `32` |  |
| `probes_per_hop` | probes per hop: 1 to 3 | `3` |  |

### DNS (`dns`)

Up to 8 questions (one per type) to Lynceus's own resolver, a public one (Cloudflare, Google, Quad9, AdGuard) or an address you name, over UDP, TCP, DoT, DoH or DoQ (RFC 1035, RFC 7766, RFC 7858, RFC 8484, RFC 9250), with every EDNS option (RFC 6891), the client subnet (RFC 7871, from one subnet or many regions), the DNSSEC signatures checked (RFC 4033–4035), and the related queries followed.

| parameter | what | default | applies when |
|---|---|---|---|
| `name` | the name asked (an address, for `PTR`), or an http(s) URL's host | required |  |
| `type` | types: up to 8 RR types by name or `TYPE`n, separated by commas or spaces | `"A"` |  |
| `families` | families: `["ipv4"]`, `["ipv6"]` or both | `["ipv4","ipv6"]` |  |
| `server` | server: `cloudflare`, `google`, `quad9`, `adguard`, or an IPv4 or IPv6 address; left out, Lynceus's own resolver | Lynceus's own resolver |  |
| `transport` | transport: `udp`, `tcp`, `dot`, `doh`, `doq` | `"udp"` |  |
| `tls_name` | certificate host: text | the preset's, or the address | `transport` is dot or doh or doq |
| `doh_path` | DoH path: text | the preset's, or `/dns-query` | `transport` is doh |
| `port` | port: 1 to 65535 | the transport's own (53, 853 or 443) |  |
| `recursion_desired` | recursion desired (RD): `true` or `false` | `true` |  |
| `class` | class: `IN`, `CH`, `HS` | `"IN"` |  |
| `checking_disabled` | checking disabled (CD): `true` or `false` | `false` |  |
| `authentic_data` | authentic data (AD): `true` or `false` | `false` |  |
| `edns` | EDNS: `true` or `false` | `true` |  |
| `dnssec_ok` | DNSSEC OK (DO): `true` or `false` | `false` | `edns` is true |
| `edns_version` | EDNS version: 0 to 255 | `0` | `edns` is true |
| `udp_payload` | UDP payload: 512 to 65535 B | `1232` | `edns` is true |
| `nsid` | NSID: `true` or `false` | on whenever EDNS is | `edns` is true |
| `compact_ok` | compact answers (CO): `true` or `false` | `false` | `edns` is true |
| `cookie` | cookie: `true` or `false` | `false` | `edns` is true |
| `padding` | padding: `true` or `false` | `false` | `edns` is true |
| `expire` | EXPIRE: `true` or `false` | `false` | `edns` is true |
| `zoneversion` | ZONEVERSION: `true` or `false` | `false` | `edns` is true |
| `keepalive` | TCP keepalive: `true` or `false` | `false` | `edns` is true, `transport` is tcp or dot |
| `ecs` | client subnets: one client subnet, `my` or `my/len` (your own) | none | `edns` is true |
| `ecs_regions` | client subnet regions: several subnets or region ids, asked once each | none | `edns` is true |

### TLS (`tls`)

A TLS handshake (RFC 8446) and the certificate chain checked (RFC 5280), on port 443, 465, 853, 993 or 995: version, cipher suite, key exchange group, ALPN, OCSP stapling and each certificate.

| parameter | what | default | applies when |
|---|---|---|---|
| `target` | a host name, an IPv4 or IPv6 address, or an http(s) URL's host | required |  |
| `port` | port: 443, 465, 853, 993, 995 | `443` |  |
| `families` | families: `["ipv4"]`, `["ipv6"]` or both | `["ipv4","ipv6"]` |  |

## Calling the looking glass

`POST https://sea.noc.andrii.net/api/1/{ping,trace,dns,tls}` with a JSON body of the parameters (at most 4 KiB). The answer is an NDJSON stream (`application/x-ndjson`): `{"t":"batch","seq":N,"ev":[…]}` lines of live events as they happen, then one `{"t":"done","result":{…},"quotas":[…]}` line whose `result` is the envelope (schema `lynceus/1`: `tool`, `id`, `started`, `finished`, `vantage`, `request`, and `result.runs`, one per family and, for DNS, per type, each with its `result`, or `skipped` or `error`). A refusal is one `{"t":"error","code":…,"reason":…}` line instead. Use `curl -N` so the stream isn't buffered. Measurements leave from Seattle, WA, US, AS402801.

```sh
# five pings to example.net, in IPv4 and in IPv6 (two runs)
curl -N 'https://sea.noc.andrii.net/api/1/ping' -d '{"target":"example.net","count":5}'
# a UDP traceroute to 1.1.1.1 (one run: an address runs in its own family)
curl -N 'https://sea.noc.andrii.net/api/1/trace' -d '{"target":"1.1.1.1","mode":"udp"}'
# andrii.co's A and AAAA records from Cloudflare over DoH, reached over IPv4 (two runs, one per type)
curl -N 'https://sea.noc.andrii.net/api/1/dns' -d '{"name":"andrii.co","type":"A, AAAA","server":"cloudflare","transport":"doh","families":["ipv4"]}'
# andrii.co's TLS handshake and certificate chain on port 443, both families (two runs)
curl -N 'https://sea.noc.andrii.net/api/1/tls' -d '{"target":"andrii.co","port":443}'
```

Your own connection, as the server sees it (the address, its AS and place, the TCP and TLS it negotiated): `curl 'https://noc.andrii.net/me'` for text, `curl 'https://noc.andrii.net/me?format=json'` for JSON.

## What it will and won't do

- **Limits**, without signing in: 500 runs an hour and 3,000 a day per IPv4 address or IPv6 /64 (5× that per /24 or /48), one run in flight at a time. Each family and each DNS type is one run, and a family with no address isn't charged. Every `done` line carries what is left; a refusal for a limit says which (`rate_limited`, with `quota` and `retry_after_s`).
- **Refused targets** (`target_refused`, HTTP 422, before anything is sent), each with a sentence saying what the address is and why:
  - "no address" or "this network" (RFC 791 §3.2; RFC 4291 §2.5.2)
  - a private address (RFC 1918)
  - carrier-grade NAT space (RFC 6598)
  - loopback (RFC 1122 §3.2.1.3; RFC 4291 §2.5.3)
  - link-local (RFC 3927; RFC 4291 §2.5.6)
  - reserved for a protocol's own use (ietf-protocol-assignments, RFC 6890 §2.1; ipv4-service-continuity, RFC 7335; ipv4-dummy-address, RFC 7600; nat64-dns64-discovery, RFC 8880, RFC 7050; nat64-local-use, RFC 8215; ietf-protocol-assignments, RFC 2928; srv6-sids, RFC 9602)
  - reserved for documentation and examples (RFC 5737; RFC 3849; RFC 9637)
  - the retired 6to4 relay anycast prefix (RFC 7526)
  - for lab benchmarking (RFC 2544; RFC 5180)
  - a multicast (or broadcast) address (IANA IPv4 Multicast Address Space; RFC 8190, RFC 919 §7; IANA IPv6 Multicast Address Space)
  - reserved, the old class E (RFC 1112 §4)
  - part of AS402801, the network this looking glass runs in
  - outside IPv6's global unicast space (2000::/3)
  - an IPv4 address inside an IPv6 one (an IPv4-mapped address, RFC 4291 §2.5.5.2; the NAT64 well-known prefix, RFC 6052; as a Teredo client's public address, RFC 4380 §4; 6to4, RFC 3056)
  - a discard prefix (RFC 6666)
  - in the retired ORCHID prefix (RFC 4843)
  - a unique local address (RFC 4193)
  An IPv6 address that carries an IPv4 one is refused and names the IPv4 address to measure instead.
- **Malformed addresses** (`malformed_address`, HTTP 422): an input that can only be an IP address (it contains a `:`, or its last label is all digits) and isn't one is never looked up. It comes back with `malformed`: the `field`, the `family`, the problem's `code` and `message`, and the `spans` of what is wrong. `23.219.78.303` is refused as `ipv4_part_range`: "Not an IPv4 address: 303 is more than 255".
- **Other refusals:** `bad_request` (HTTP 400: a parameter the server doesn't take, with the reason), `queue_full` (503), `internal` (500).

