# `ExSandbox.Egress.HostAliases`
[🔗](https://github.com/FoundryStack/ex_sandbox/blob/v1.2.0/lib/ex_sandbox/egress/host_aliases.ex#L1)

Every address that **is this host**, as this host currently reports itself
(029 T014's supply half, `029-FR-015`, D103).

## Why this exists as a separate module

`ExSandbox.Egress.Allowlist.parse/2` takes the alias set as **data** and must
keep doing so: it is the module that transfers whole to a second mechanism
precisely because it names no mechanism, and a capability query from inside it
would be the re-coupling that argument forbids. So somebody has to *produce*
the list, and that somebody is here — on the platform side of the seam, where
knowing about interfaces and routing tables is allowed.

⚠️ **Discovered, never configured, and the difference is the whole point.**
A configured constant would be right in the config file and wrong in the
namespace, and the drift *is* the defect: every parse-time test stays green
while the address actually in use is one no entry is refused for. The list is
read from the running kernel at the moment it is needed.

## What counts as the host

| source | why |
|---|---|
| every address on every interface (`:inet.getifaddrs/0`) | these are literally this machine, under every name it answers to |
| the default gateway | see below |

⚠️ **The default gateway is included even though `--no-map-gw` is passed**,
and that is belt-and-braces rather than confusion. `pasta`'s default is to map
the namespace's gateway address onto the host, which makes it a second name
for the host that is not `127.0.0.1` — the case D103 was written about. The
flag turns that default off, so today the gateway is the real upstream router
instead. Refusing it anyway costs an operator nothing they should have wanted
(a sandbox has no business dialling the host's own next hop), and it means the
exclusion does not quietly evaporate if the flag is ever dropped — which is
exactly the kind of silent re-widening `netns.ex` documents `--no-map-gw`
against.

⚠️ **`:host_alias` wins over `:rfc1918_private` when both match**, which is
the ordering `Allowlist.host_class/2` already fixes. Nearly every address here
is also private, so without that ordering this whole list would be invisible
in the error an operator reads.

## What this cannot see

Read at the moment of the call, so an address added afterwards is not in a
list already produced. That is a real gap and is stated rather than papered
over: the alternative — re-reading per comparison — would put a syscall
inside a pure policy function, which is the coupling the seam exists to
prevent. Provisioning is where the list is taken, and provisioning is also
where the refusal must land, so the two are the same moment.

⚠️ It also cannot see a **name** for the host (`host.docker.internal` and
friends). `Allowlist.parse/2` accepts names in the alias set and nothing here
produces one, so an operator who writes a host *name* is not refused as
`:host_alias` today. Unfixed here on purpose: guessing at names would produce
a list that is wrong in a different direction, and the answer-side filter in
`ExSandbox.Egress.Resolver` catches the name once it resolves.

# `host_alias`

```elixir
@type host_alias() :: :inet.ip_address()
```

An address that is this host.

# `detect`

```elixir
@spec detect() :: [host_alias()]
```

Every address that is this host, right now.

Returns `[]` on a host whose interfaces cannot be read — which is a **loss of
a guard**, so it is logged rather than passing silently. It is not fatal: the
static classes (`:loopback`, `:rfc1918_private`, …) still refuse most of what
this list would have caught, so an empty answer narrows the guard rather than
removing it.

# `parse_default_via`

```elixir
@spec parse_default_via(String.t()) :: [host_alias()]
```

The gateway addresses in `ip route show default` output.

Public so the parsing is testable on a host that has no `ip(8)` and no default
route — which is every machine this is written on. A parser exercised only
where the command runs is one whose failure mode is a silently empty guard.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
