Download raw body.
relayd: support multiple resolveble addresses
On Sat May 16, 2026 at 04:30:31PM +0200, Kirill A. Korinsky wrote:
> On Mon, 06 Apr 2026 11:33:21 +0200,
> "Kirill A. Korinsky" <kirill@korins.ky> wrote:
> >
> > tech@,
> >
> > relayd supports interface name, DNS hostname or interface group at
> > listen on but it binds only to the first discovered IP address which is
> > usually IPv4.
> >
> > Here I changed parser to create a dedicated listener for each discovered
> > and confiugred on a local inerface address.
> >
> > This means that listen on egress port 80 binds to all IPv4 and IPv6
> > addresses on the egress group.
> >
>
> Ok?
Tested with "lo" with all regression tests. OK rsadowski@
>
> Index: etc/examples/relayd.conf
> ===================================================================
> RCS file: /home/cvs/src/etc/examples/relayd.conf,v
> diff -u -p -r1.6 relayd.conf
> --- etc/examples/relayd.conf 29 Oct 2023 11:27:11 -0000 1.6
> +++ etc/examples/relayd.conf 2 May 2026 11:41:39 -0000
> @@ -2,7 +2,6 @@
> #
> # Macros
> #
> -ext_addr="192.168.1.1"
> webhost1="10.0.0.1"
> webhost2="10.0.0.2"
> sshhost1="10.0.0.3"
> @@ -24,7 +23,7 @@ table <fallback> { 127.0.0.1 }
> # Services will be mapped to a rdr rule.
> #
> redirect www {
> - listen on $ext_addr port http interface trunk0
> + listen on egress port http
>
> # tag every packet that goes thru the rdr rule with RELAYD
> pftag RELAYD
> @@ -51,7 +50,7 @@ http protocol https {
>
> relay wwwtls {
> # Run as a TLS accelerator
> - listen on $ext_addr port 443 tls
> + listen on egress port https tls
> protocol https
>
> # Forward to hosts in the webhosts table using a src/dst hash
> @@ -69,7 +68,7 @@ protocol sshtcp {
>
> relay sshgw {
> # Run as a simple TCP relay
> - listen on $ext_addr port 2222
> + listen on egress port 2222
> protocol sshtcp
>
> # Forward to the shared carp(4) address of an internal gateway
> Index: usr.sbin/relayd/parse.y
> ===================================================================
> RCS file: /home/cvs/src/usr.sbin/relayd/parse.y,v
> diff -u -p -r1.263 parse.y
> --- usr.sbin/relayd/parse.y 15 May 2026 13:57:24 -0000 1.263
> +++ usr.sbin/relayd/parse.y 16 May 2026 14:29:10 -0000
> @@ -131,8 +131,10 @@ int host_dns(const char *, struct addr
> int, struct portrange *, const char *, int);
> int host_if(const char *, struct addresslist *,
> int, struct portrange *, const char *, int);
> +int host_ifaddr(struct sockaddr_storage *, struct ifaddrs *);
> int host(const char *, struct addresslist *,
> int, struct portrange *, const char *, int);
> +int host_local(struct addresslist *);
> void host_free(struct addresslist *);
>
> struct table *table_inherit(struct table *);
> @@ -1995,35 +1997,60 @@ relayopts_l : relayopts_l relayoptsl nl
> relayoptsl : LISTEN ON STRING port opttls {
> struct addresslist al;
> struct address *h;
> - struct relay *r;
> + struct relay *nr, *r;
> + int cnt = 0;
>
> if (rlay->rl_conf.ss.ss_family != AF_UNSPEC) {
> - if ((r = calloc(1, sizeof (*r))) == NULL)
> + if ((r = calloc(1, sizeof(*r))) == NULL)
> fatal("out of memory");
> - TAILQ_INSERT_TAIL(&relays, r, rl_entry);
> } else
> r = rlay;
> if ($4.op != PF_OP_EQ) {
> yyerror("invalid port");
> free($3);
> + if (r != rlay)
> + free(r);
> YYERROR;
> }
>
> TAILQ_INIT(&al);
> - if (host($3, &al, 1, &$4, NULL, -1) <= 0) {
> + if (host($3, &al, SRV_MAX_VIRTS, &$4, NULL, -1) <= 0) {
> yyerror("invalid listen ip: %s", $3);
> free($3);
> + if (r != rlay)
> + free(r);
> + YYERROR;
> + }
> + if (host_local(&al) == 0) {
> + yyerror("no local listen ip: %s", $3);
> + free($3);
> + host_free(&al);
> + if (r != rlay)
> + free(r);
> YYERROR;
> }
> free($3);
> - h = TAILQ_FIRST(&al);
> - bcopy(&h->ss, &r->rl_conf.ss, sizeof(r->rl_conf.ss));
> - r->rl_conf.port = h->port.val[0];
> - if ($5) {
> - r->rl_conf.flags |= F_TLS;
> - conf->sc_conf.flags |= F_TLS;
> + TAILQ_FOREACH(h, &al, entry) {
> + if (cnt == 0) {
> + nr = r;
> + if (nr != rlay)
> + TAILQ_INSERT_TAIL(&relays, nr,
> + rl_entry);
> + } else {
> + if ((nr = calloc(1, sizeof(*nr))) == NULL)
> + fatal("out of memory");
> + TAILQ_INSERT_TAIL(&relays, nr, rl_entry);
> + }
> + bcopy(&h->ss, &nr->rl_conf.ss,
> + sizeof(nr->rl_conf.ss));
> + nr->rl_conf.port = h->port.val[0];
> + if ($5)
> + nr->rl_conf.flags |= F_TLS;
> + cnt++;
> }
> - tableport = h->port.val[0];
> + if ($5)
> + conf->sc_conf.flags |= F_TLS;
> + tableport = $4.val[0];
> host_free(&al);
> }
> | forwardmode opttlsclient TO forwardspec dstaf optproxyproto {
> @@ -3376,6 +3403,64 @@ host(const char *s, struct addresslist *
>
> TAILQ_INSERT_HEAD(al, h, entry);
> return (1);
> +}
> +
> +int
> +host_ifaddr(struct sockaddr_storage *ss, struct ifaddrs *ifap)
> +{
> + struct ifaddrs *p;
> + struct sockaddr_in *sin;
> + struct sockaddr_in6 *sin6;
> +
> + switch (ss->ss_family) {
> + case AF_INET:
> + sin = (struct sockaddr_in *)ss;
> + if (sin->sin_addr.s_addr == INADDR_ANY)
> + return (1);
> + break;
> + case AF_INET6:
> + sin6 = (struct sockaddr_in6 *)ss;
> + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
> + return (1);
> + break;
> + default:
> + return (0);
> + }
> +
> + for (p = ifap; p != NULL; p = p->ifa_next) {
> + if (p->ifa_addr == NULL ||
> + p->ifa_addr->sa_family != ss->ss_family ||
> + sockaddr_cmp((struct sockaddr *)ss, p->ifa_addr, -1) != 0)
> + continue;
> + bzero(ss, sizeof(*ss));
> + memcpy(ss, p->ifa_addr, p->ifa_addr->sa_len);
> + return (1);
> + }
> +
> + return (0);
> +}
> +
> +int
> +host_local(struct addresslist *al)
> +{
> + struct ifaddrs *ifap;
> + struct address *h, *next;
> + int cnt = 0;
> +
> + if (getifaddrs(&ifap) == -1)
> + fatal("getifaddrs");
> +
> + TAILQ_FOREACH_SAFE(h, al, entry, next) {
> + if (host_ifaddr(&h->ss, ifap)) {
> + cnt++;
> + continue;
> + }
> + TAILQ_REMOVE(al, h, entry);
> + free(h);
> + }
> +
> + freeifaddrs(ifap);
> + return (cnt);
> }
>
> void
> Index: usr.sbin/relayd/relayd.conf.5
> ===================================================================
> RCS file: /home/cvs/src/usr.sbin/relayd/relayd.conf.5,v
> diff -u -p -r1.216 relayd.conf.5
> --- usr.sbin/relayd/relayd.conf.5 15 May 2026 13:57:24 -0000 1.216
> +++ usr.sbin/relayd/relayd.conf.5 16 May 2026 14:29:10 -0000
> @@ -727,7 +727,19 @@ Like the previous directive, but for red
> .Op Ic tls
> .Xc
> Specify the address and port for the relay to listen on.
> -The relay will accept incoming connections to the specified address.
> +The relay will accept incoming connections to the specified address or
> +addresses.
> +If
> +.Ar address
> +resolves to multiple IPv4 or IPv6 addresses, such as an interface
> +name, interface group, or DNS hostname,
> +.Xr relayd 8
> +will create a listener for each local address.
> +For DNS hostnames, all resolved IPv4 and IPv6 addresses are considered,
> +but only addresses configured on a local interface are used.
> +Addresses that are not configured on a local interface are ignored.
> +If none of the resolved addresses are local, the configuration is
> +invalid.
> If the
> .Ic tls
> keyword is present, the relay will accept connections using the
>
>
> --
> wbr, Kirill
relayd: support multiple resolveble addresses