# ctfy/wireguard-base — VPN-delivery entry point for engagement-mode
# challenges that declare `vpn_backend: wireguard`.
#
# The WireGuard sibling of ctfy/openvpn-base. Same contract, same
# CTFY_* env schema, same isolation guarantees — a challenge switches
# backend by swapping which base its VPN service builds FROM, and the
# platform picks the matching topology strategy off `vpn_backend`.
#
# The base owns:
#
#   * Key material on first boot. Two `wg genkey` pairs — one for the
#     server, one for the single player peer — written under
#     /etc/wireguard/keys and persistent across container restarts.
#     There is deliberately no CA: WireGuard authenticates peers by
#     raw public key, so the EasyRSA machinery openvpn-base needs has
#     no counterpart here.
#   * Server + client config generated from CTFY_* env vars supplied
#     by the challenge's compose. As in openvpn-base v1.1+, the DMZ
#     topology and edge-dns IP are AUTO-DISCOVERED at bootstrap (the
#     container's own interface; docker DNS), so those vars are
#     optional — hardcoding them would force one instance per docker
#     daemon by making every fresh project collide on a fixed pool.
#     Setting any explicitly still wins over auto-discovery.
#       CTFY_DMZ_SUBNET       optional (default: from interface)
#       CTFY_EDGE_DNS_IP      optional (default: getent hosts edge-dns)
#       CTFY_VPN_PUBLIC_HOST  external host the client config points at
#       CTFY_VPN_PUBLIC_PORT  external port (the host port the platform
#                             maps to 51820/udp)
#       CTFY_TUNNEL_NET       /24 for VPN clients
#                             (default 192.168.255.0; server takes .1,
#                             the player peer takes .2)
#   * Hard isolation: iptables FORWARD policy DROP, allow ONLY
#     wg0 ⇄ eth0 traffic toward the DMZ subnet. Drops the docker host
#     gateway, all other RFC1918, cloud-metadata (169.254.0.0/16),
#     link-local, and the public internet. Challenge authors cannot
#     disable this — it is part of the base image's ENTRYPOINT.
#
# ⚠️ **DNS is not pushed, it is written into the client config.**
# WireGuard has no protocol-level equivalent of OpenVPN's
# `dhcp-option DOMAIN-ROUTE`, so there is no split-DNS to negotiate:
# the client config carries `DNS = <edge-dns>` and every lookup made
# while the tunnel is up goes to the challenge's resolver. That is
# only safe because edge-dns forwards what it does not own — a
# non-forwarding resolver there would NXDOMAIN the player's whole
# internet for the duration of the session.
#
# ⚠️ **What the challenge's compose MUST supply**, because this image
# physically cannot:
#
#     cap_add:  [NET_ADMIN]
#     sysctls:  { net.ipv4.ip_forward: 1 }
#     ports:    ["51820:51820/udp"]     # platform re-maps to ephemeral
#
# `net.ipv4.ip_forward` is the one that bites. /proc/sys is mounted
# read-only in a container, so `sysctl -w` from this entrypoint fails
# — declaring it in compose is the ONLY way to guarantee it. Docker
# usually inherits 1 from the host, which means a challenge that omits
# it works until it lands on a daemon where it does not, and then
# fails as "handshake succeeds, nothing is reachable". The audit rules
# enforce the declaration for exactly that reason.
#
# Note what is NOT required, versus openvpn-base: no
# `devices: [/dev/net/tun]`. Kernel WireGuard is a netdev, not a tun
# device, so there is no host device to hand in. NET_ADMIN alone is
# enough to create wg0, and the kernel autoloads the `wireguard`
# module on first use even from a NET_ADMIN-only container — the host
# needs no preparation.
FROM alpine:3.20

LABEL org.ctfy.component="wireguard-base"
LABEL org.ctfy.version="1.0"

# bash: wg-quick is a bash script, not POSIX sh.
# iproute2: interface/route inspection during DMZ auto-discovery.
# iptables: the isolation policy below.
RUN apk add --no-cache bash wireguard-tools iproute2 iptables

COPY --chmod=0755 ctfy-wireguard-bootstrap.sh /usr/local/bin/ctfy-wireguard-bootstrap.sh
COPY --chmod=0755 ctfy-wireguard-isolation.sh /usr/local/bin/ctfy-wireguard-isolation.sh

# The base image's entrypoint owns key generation + isolation rules
# and then holds the namespace open. Challenges cannot override this —
# they only supply env vars via compose.
ENTRYPOINT ["/usr/local/bin/ctfy-wireguard-bootstrap.sh"]
