From d96c3f211e59bdb210800c68cf8304a6c22163dd Mon Sep 17 00:00:00 2001 From: alfred Date: Thu, 11 Jul 2002 16:19:43 +0000 Subject: Add -h option to rpcbind, used to specify what address to bind to for UDP requests. Submitted by: mbr --- usr.sbin/rpcbind/rpcbind.8 | 23 +++++ usr.sbin/rpcbind/rpcbind.c | 251 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 223 insertions(+), 51 deletions(-) (limited to 'usr.sbin') diff --git a/usr.sbin/rpcbind/rpcbind.8 b/usr.sbin/rpcbind/rpcbind.8 index 1ea7096..42d0579 100644 --- a/usr.sbin/rpcbind/rpcbind.8 +++ b/usr.sbin/rpcbind/rpcbind.8 @@ -72,6 +72,29 @@ will not fork when it starts, will print additional information during operation, and will abort on certain errors. With this option, the name-to-address translation consistency checks are shown in detail. +.It Fl h +Specify specific IP addresses to bind to for UDP requests. +This option +may be specified multiple times and is typically necessary when running +on a multi-homed host. +If no +.Fl h +option is specified, +.Nm +will bind to +.Dv INADDR_ANY , +which could lead to problems on a multi-homed host due to +.Nm +returning a UDP packet from a different IP address than it was +sent to. +Note that when specifying IP addresses with +.Fl h , +.Nm +will automatically add +.Li 127.0.0.1 +and if IPv6 is enabled, +.Li ::1 +to the list. .It Fl i .Dq Insecure mode. diff --git a/usr.sbin/rpcbind/rpcbind.c b/usr.sbin/rpcbind/rpcbind.c index 8e93160..598ab6a 100644 --- a/usr.sbin/rpcbind/rpcbind.c +++ b/usr.sbin/rpcbind/rpcbind.c @@ -86,6 +86,10 @@ int insecure = 0; int oldstyle_local = 0; int verboselog = 0; +char **hosts = NULL; +int nhosts = 0; +int on = 1; + #ifdef WARMSTART /* Local Variable */ static int warmstart = 0; /* Grab a old copy of registrations */ @@ -220,7 +224,10 @@ init_transport(struct netconfig *nconf) int status; /* bound checking ? */ int aicode; int addrlen; + int nhostsbak; + int checkbind; struct sockaddr *sa; + u_int32_t host_addr[4]; /* IPv4 or IPv6 */ struct sockaddr_un sun; mode_t oldmask; @@ -242,11 +249,14 @@ init_transport(struct netconfig *nconf) #endif /* - * XXX - using RPC library internal functions. + * XXX - using RPC library internal functions. For NC_TPI_CLTS + * we call this later, for each socket we like to bind. */ - if ((fd = __rpc_nconf2fd(nconf)) < 0) { - syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid); - return (1); + if (nconf->nc_semantics != NC_TPI_CLTS) { + if ((fd = __rpc_nconf2fd(nconf)) < 0) { + syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid); + return (1); + } } if (!__rpc_nconf2sockinfo(nconf, &si)) { @@ -271,59 +281,189 @@ init_transport(struct netconfig *nconf) hints.ai_family = si.si_af; hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; - if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) { - syslog(LOG_ERR, "cannot get local address for %s: %s", - nconf->nc_netid, gai_strerror(aicode)); - return 1; - } - addrlen = res->ai_addrlen; - sa = (struct sockaddr *)res->ai_addr; - } - oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); - if (bind(fd, sa, addrlen) < 0) { - syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid); - if (res != NULL) - freeaddrinfo(res); - return 1; } - (void) umask(oldmask); + if (nconf->nc_semantics == NC_TPI_CLTS) { + /* + * If no hosts were specified, just bind to INADDR_ANY. Otherwise + * make sure 127.0.0.1 is added to the list. + */ + nhostsbak = nhosts; + nhostsbak++; + hosts = realloc(hosts, nhostsbak * sizeof(char *)); + if (nhostsbak == 1) + hosts[0] = "*"; + else { + if (hints.ai_family == AF_INET) { + hosts[nhostsbak - 1] = "127.0.0.1"; + } else if (hints.ai_family == AF_INET6) { + hosts[nhostsbak - 1] = "::1"; + } else + return 1; + } - /* Copy the address */ - taddr.addr.len = taddr.addr.maxlen = addrlen; - taddr.addr.buf = malloc(addrlen); - if (taddr.addr.buf == NULL) { - syslog(LOG_ERR, "cannot allocate memory for %s address", - nconf->nc_netid); - if (res != NULL) - freeaddrinfo(res); - return 1; - } - memcpy(taddr.addr.buf, sa, addrlen); + /* + * Bind to specific IPs if asked to + */ + checkbind = 1; + while (nhostsbak > 0) { + --nhostsbak; + /* + * XXX - using RPC library internal functions. + */ + if ((fd = __rpc_nconf2fd(nconf)) < 0) { + syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid); + return (1); + } + switch (hints.ai_family) { + case AF_INET: + if (inet_pton(AF_INET, hosts[nhostsbak], host_addr) == 1) { + hints.ai_flags &= AI_NUMERICHOST; + } else { + /* + * Skip if we have a AF_INET6 adress + */ + if (inet_pton(AF_INET6, hosts[nhostsbak], + host_addr) == 1) + continue; + } + break; + case AF_INET6: + if (inet_pton(AF_INET6, hosts[nhostsbak], host_addr) == 1) { + hints.ai_flags &= AI_NUMERICHOST; + } else { + /* + * Skip if we have a AF_INET adress + */ + if (inet_pton(AF_INET, hosts[nhostsbak], + host_addr) == 1) + continue; + } + if (setsockopt(fd, IPPROTO_IPV6, + IPV6_BINDV6ONLY, &on, sizeof on) < 0) { + syslog(LOG_ERR, "can't set v6-only binding for " + "udp6 socket: %m"); + continue; + } + break; + default: + break; + } + + /* + * If no hosts were specified, just bind to INADDR_ANY + */ + if (strcmp("*", hosts[nhostsbak]) == 0) + hosts[nhostsbak] = NULL; + + if ((aicode = getaddrinfo(hosts[nhostsbak], + servname, &hints, &res)) != 0) { + syslog(LOG_ERR, "cannot get local address for %s: %s", + nconf->nc_netid, gai_strerror(aicode)); + continue; + } + addrlen = res->ai_addrlen; + sa = (struct sockaddr *)res->ai_addr; + oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); + if (bind(fd, sa, addrlen) != 0) { + syslog(LOG_ERR, "cannot bind %s on %s: %m", + hosts[nhostsbak], nconf->nc_netid); + if (res != NULL) + freeaddrinfo(res); + continue; + } else + checkbind++; + (void) umask(oldmask); + + /* Copy the address */ + taddr.addr.len = taddr.addr.maxlen = addrlen; + taddr.addr.buf = malloc(addrlen); + if (taddr.addr.buf == NULL) { + syslog(LOG_ERR, "cannot allocate memory for %s address", + nconf->nc_netid); + if (res != NULL) + freeaddrinfo(res); + return 1; + } + memcpy(taddr.addr.buf, sa, addrlen); #ifdef ND_DEBUG - if (debugging) { - /* for debugging print out our universal address */ - char *uaddr; - struct netbuf nb; - - nb.buf = sa; - nb.len = nb.maxlen = sa->sa_len; - uaddr = taddr2uaddr(nconf, &nb); - (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); - (void) free(uaddr); - } + if (debugging) { + /* for debugging print out our universal address */ + char *uaddr; + struct netbuf nb; + + nb.buf = sa; + nb.len = nb.maxlen = sa->sa_len; + uaddr = taddr2uaddr(nconf, &nb); + (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); + (void) free(uaddr); + } #endif - if (res != NULL) - freeaddrinfo(res); + if (nconf->nc_semantics != NC_TPI_CLTS) + listen(fd, SOMAXCONN); - if (nconf->nc_semantics != NC_TPI_CLTS) - listen(fd, SOMAXCONN); + my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 0, 0); + if (my_xprt == (SVCXPRT *)NULL) { + syslog(LOG_ERR, "%s: could not create service", + nconf->nc_netid); + goto error; + } + } + if (!checkbind) + return 1; + } else { + if (strcmp(nconf->nc_netid, "unix") != 0) { + if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) { + syslog(LOG_ERR, "cannot get local address for %s: %s", + nconf->nc_netid, gai_strerror(aicode)); + return 1; + } + addrlen = res->ai_addrlen; + sa = (struct sockaddr *)res->ai_addr; + } + oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); + if (bind(fd, sa, addrlen) < 0) { + syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid); + if (res != NULL) + freeaddrinfo(res); + return 1; + } + (void) umask(oldmask); + + /* Copy the address */ + taddr.addr.len = taddr.addr.maxlen = addrlen; + taddr.addr.buf = malloc(addrlen); + if (taddr.addr.buf == NULL) { + syslog(LOG_ERR, "cannot allocate memory for %s address", + nconf->nc_netid); + if (res != NULL) + freeaddrinfo(res); + return 1; + } + memcpy(taddr.addr.buf, sa, addrlen); +#ifdef ND_DEBUG + if (debugging) { + /* for debugging print out our universal address */ + char *uaddr; + struct netbuf nb; + + nb.buf = sa; + nb.len = nb.maxlen = sa->sa_len; + uaddr = taddr2uaddr(nconf, &nb); + (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); + (void) free(uaddr); + } +#endif - my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 0, 0); - if (my_xprt == (SVCXPRT *)NULL) { - syslog(LOG_ERR, "%s: could not create service", - nconf->nc_netid); - goto error; + if (nconf->nc_semantics != NC_TPI_CLTS) + listen(fd, SOMAXCONN); + + my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 0, 0); + if (my_xprt == (SVCXPRT *)NULL) { + syslog(LOG_ERR, "%s: could not create service", + nconf->nc_netid); + goto error; + } } #ifdef PORTMAP @@ -513,7 +653,7 @@ parseargs(int argc, char *argv[]) { int c; - while ((c = getopt(argc, argv, "dwailLs")) != -1) { + while ((c = getopt(argc, argv, "dwah:ilLs")) != -1) { switch (c) { case 'a': doabort = 1; /* when debugging, do an abort on */ @@ -522,6 +662,15 @@ parseargs(int argc, char *argv[]) case 'd': debugging = 1; break; + case 'h': + ++nhosts; + hosts = realloc(hosts, nhosts * sizeof(char *)); + if (hosts == NULL) + errx(1, "Out of memory"); + hosts[nhosts - 1] = strdup(optarg); + if (hosts[nhosts - 1] == NULL) + errx(1, "Out of memory"); + break; case 'i': insecure = 1; break; -- cgit v1.1