From: Rafael Sadowski Subject: Re: relayd: support multiple resolveble addresses To: tech@openbsd.org Date: Sun, 17 May 2026 03:27:37 +0200 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" 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 { 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