Deprecate "ip" in favour of "host" for domain fronting
Per review on #480: warn-and-ignore for the IP-shaped paths,
mirroring the net.Dialer.DualStack precedent — a config that
sets only "ip" will warn at startup and effectively disable
domain-fronting until the user switches to "host".
- mtglib.ProxyOpts: add DomainFrontingHost; mark DomainFrontingIP
Deprecated and warn-and-drop in NewProxy.
- internal/config: GetDomainFrontingHost returns only
[domain-fronting].host; deprecated keys are no longer used to
derive the dial target. runProxy logs a startup warning per
deprecated key that is set.
- internal/cli: add --domain-fronting-host; --domain-fronting-ip
flag is parsed only so the runtime warning can fire.
- internal/cli/doctor: redirect the existing 2.3.0 entry at "host"
and add a 2.4.0 entry for [domain-fronting].ip.
- example.config.toml: mark # ip = ... as deprecated.
Address round-two review: rename mtglib privates, reorder, more tests
- mtglib/proxy.go: rename private field domainFrontingIP -> domainFrontingHost
and update DomainFrontingAddress() doc comment to reflect that hostnames
are now accepted. The exported mtglib.ProxyOpts.DomainFrontingIP is
unchanged (public API), so the assignment in NewProxy now reads
`domainFrontingHost: opts.DomainFrontingIP,` which makes the
public-vs-internal naming explicitly visible at the boundary.
- internal/config/{parse,config}.go: reorder so Host comes before IP in
the [domain-fronting] struct. Cosmetic, but signals Host is the
preferred forward path.
- Add TestDomainFrontingHostAcceptsLiteralIP + domain_fronting_host_ip.toml
fixture exercising the documented "host accepts hostname or literal IP"
contract end-to-end.
Follow-up to the previous commit on this branch:
- Rename Config.GetDomainFrontingIP -> GetDomainFrontingHost. The
helper now returns a hostname or an IP, so the old name was a lie.
Drop the unused defaultValue net.IP parameter (every caller passed
nil). Update internal/cli/run_proxy.go and internal/cli/doctor.go;
rename the misleading `ip` local var in doctor.go to `override`.
- Add TOML fixtures (domain_fronting_host.toml, domain_fronting_ip.toml)
so the new field is exercised through the actual Parse()->JSON->Config
path users hit, not just via direct .Set() calls. Plus a positive
backward-compat test confirming an `ip`-only legacy config still
validates and resolves correctly, and a no-fronting test confirming
the unset case returns empty.
- Clarify example.config.toml: `ip` is kept for backward compatibility,
not because it has stricter validation semantics worth choosing over
`host`.
mtglib.ProxyOpts.DomainFrontingIP keeps its name (public API).
The existing `[domain-fronting].ip` only accepts a literal IP. That
forces SNI-router setups to pin a static container address (and a
static docker subnet) so mtg can dial the fronting backend directly
instead of resolving the secret's hostname via DNS, which would loop
back into mtg through the SNI router.
Add a sibling `[domain-fronting].host` that accepts either a hostname
or an IP. Hostnames are resolved at dial time by the native dialer
(Happy Eyeballs / dual-stack), so a docker-DNS or any A+AAAA record
naturally picks the right backend address family per client. Setting
both `host` and `ip` is rejected at validation.
The mtglib API stays backward compatible: ProxyOpts.DomainFrontingIP
is still a plain string and the dial path already calls JoinHostPort +
DialContext, both of which accept hostnames. Only the doc comment was
clarified.
Add public-ipv4/public-ipv6 config options for manual IP override
On some servers ifconfig.co is unreachable (e.g. Hetzner, AdGuard DNS
blocklists), causing 'mtg doctor' SNI-DNS check and 'mtg access' link
generation to fail. New config options allow specifying public IPs
manually, with automatic detection as fallback.
Fixes #405