Subject: make usr.sbin/sup IPv6 ready
To: None <tech-net@netbsd.org>
From: Jun-ichiro itojun Hagino <itojun@iijlab.net>
List: tech-net
Date: 09/11/2001 11:26:09
the following diff makes sup IPv6 ready. client side was tested over
IPv6-to-IPv4 translator. is it okay to commit it?
itojun
Index: source/scm.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/sup/source/scm.c,v
retrieving revision 1.10
diff -u -r1.10 scm.c
--- source/scm.c 2000/03/12 12:16:49 1.10
+++ source/scm.c 2001/09/11 02:28:04
@@ -181,6 +181,7 @@
#else
#include <varargs.h>
#endif
+#include <ifaddrs.h>
#include "supcdefs.h"
#include "supextern.h"
@@ -211,7 +212,7 @@
int netfile = -1; /* network file descriptor */
static int sock = -1; /* socket used to make connection */
-static struct in_addr remoteaddr; /* remote host address */
+static struct sockaddr_storage remoteaddr; /* remote host address */
static char *remotename = NULL; /* remote host name */
static int swapmode; /* byte-swapping needed on server? */
@@ -224,47 +225,71 @@
***************************************************/
int
-servicesetup (server) /* listen for clients */
+servicesetup (server, af) /* listen for clients */
char *server;
+int af;
{
- struct sockaddr_in sin;
- struct servent *sp;
- short port;
+ struct addrinfo hints, *res0, *res;
+ char port[NI_MAXSERV];
+ int error;
+ const char *cause = "unknown";
int one = 1;
- if (myhost () == NULL)
- return (scmerr (-1,"Local hostname not known"));
- if ((sp = getservbyname(server,"tcp")) == 0) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_socktype = AI_PASSIVE;
+ error = getaddrinfo(NULL, server, &hints, &res0);
+ if (error) {
+ /* retry with precompiled knowledge */
if (strcmp(server, FILEPORT) == 0)
- port = htons((u_short)FILEPORTNUM);
+ snprintf(port, sizeof(port), "%u", FILEPORTNUM);
else if (strcmp(server, DEBUGFPORT) == 0)
- port = htons((u_short)DEBUGFPORTNUM);
+ snprintf(port, sizeof(port), "%u", DEBUGFPORTNUM);
else
- return (scmerr (-1,"Can't find %s server description",server));
- (void) scmerr (-1,"%s/tcp: unknown service: using port %d",
- server,port);
- } else
- port = sp->s_port;
- endservent ();
- sock = socket (AF_INET,SOCK_STREAM,0);
- if (sock < 0)
- return (scmerr (errno,"Can't create socket for connections"));
- if (setsockopt (sock,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(int)) < 0)
- (void) scmerr (errno,"Can't set SO_REUSEADDR socket option");
- (void) bzero ((char *)&sin,sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = port;
- if (bind (sock,(struct sockaddr *)&sin,sizeof(sin)) < 0)
- return (scmerr (errno,"Can't bind socket for connections"));
- if (listen (sock,NCONNECTS) < 0)
- return (scmerr (errno,"Can't listen on socket"));
- return (SCMOK);
+ port[0] = '\0';
+ if (port[0])
+ error = getaddrinfo(NULL, port, &hints, &res0);
+ if (error)
+ return (scmerr (-1, "%s: %s", server,
+ gai_strerror(error)));
+ }
+ for (res = res0; res; res = res->ai_next) {
+ sock = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (sock < 0) {
+ cause = "socket";
+ continue;
+ }
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&one, sizeof(int)) < 0) {
+ cause = "setsockopt(SO_REUSEADDR)";
+ close(sock);
+ continue;
+ }
+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
+ cause = "bind";
+ close(sock);
+ continue;
+ }
+ if (listen(sock, NCONNECTS) < 0) {
+ cause = "listen";
+ close(sock);
+ continue;
+ }
+
+ freeaddrinfo(res0);
+ return SCMOK;
+ }
+
+ freeaddrinfo(res0);
+ return (scmerr (errno, "%s", cause));
}
int
service ()
{
- struct sockaddr_in from;
+ struct sockaddr_storage from;
int x,len;
remotename = NULL;
@@ -274,7 +299,11 @@
} while (netfile < 0 && errno == EINTR);
if (netfile < 0)
return (scmerr (errno,"Can't accept connections"));
- remoteaddr = from.sin_addr;
+ if (len > sizeof(remoteaddr)) {
+ close(netfile);
+ return (scmerr (errno,"Can't accept connections"));
+ }
+ memcpy(&remoteaddr, &from, len);
if (read(netfile,(char *)&x,sizeof(int)) != sizeof(int))
return (scmerr (errno,"Can't transmit data on connection"));
if (x == 0x01020304)
@@ -358,54 +387,65 @@
char *hostname;
int *retry;
{
- int x, backoff;
- struct hostent *h;
- struct servent *sp;
- struct sockaddr_in sin, tin;
- short port;
-
- if ((sp = getservbyname(server,"tcp")) == 0) {
+ struct addrinfo hints, *res, *res0;
+ int error;
+ char port[NI_MAXSERV];
+ int backoff;
+ int x;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(hostname, server, &hints, &res0);
+ if (error) {
+ /* retry with precompiled knowledge */
if (strcmp(server, FILEPORT) == 0)
- port = htons((u_short)FILEPORTNUM);
+ snprintf(port, sizeof(port), "%u", FILEPORTNUM);
else if (strcmp(server, DEBUGFPORT) == 0)
- port = htons((u_short)DEBUGFPORTNUM);
+ snprintf(port, sizeof(port), "%u", DEBUGFPORTNUM);
else
- return (scmerr (-1,"Can't find %s server description",
- server));
- if (!silent)
- (void) scmerr (-1,"%s/tcp: unknown service: using port %d",
- server,port);
- } else
- port = sp->s_port;
- (void) bzero ((char *)&sin,sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = inet_addr (hostname);
- if (sin.sin_addr.s_addr == (u_long) INADDR_NONE) {
- if ((h = gethostbyname (hostname)) == NULL)
- return (scmerr (-1,"Can't find host entry for %s",
- hostname));
- hostname = h->h_name;
- (void) bcopy (h->h_addr,(char *)&sin.sin_addr,h->h_length);
+ port[0] = '\0';
+ if (port[0])
+ error = getaddrinfo(hostname, port, &hints, &res0);
+ if (error)
+ return (scmerr (-1, "%s: %s", server,
+ gai_strerror(error)));
}
- sin.sin_port = port;
backoff = 1;
- for (;;) {
- netfile = socket (AF_INET,SOCK_STREAM,0);
- if (netfile < 0)
- return (scmerr (errno,"Can't create socket"));
- tin = sin;
- if (connect(netfile,(struct sockaddr *)&tin,sizeof(tin)) >= 0)
+ while (1) {
+ netfile = -1;
+ for (res = res0; res; res = res->ai_next) {
+ if (res->ai_addrlen > sizeof(remoteaddr))
+ continue;
+ netfile = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (netfile < 0)
+ continue;
+ if (connect(netfile, res->ai_addr, res->ai_addrlen) < 0) {
+ close(netfile);
+ netfile = -1;
+ continue;
+ }
+
break;
- (void) scmerr (errno,"Can't connect to server for %s",server);
- (void) close(netfile);
- if (!dobackoff (retry,&backoff))
- return (SCMERR);
+ }
+
+ if (netfile < 0) {
+ if (!dobackoff (retry, &backoff)) {
+ freeaddrinfo(res0);
+ return (SCMERR);
+ }
+ continue;
+ } else
+ break;
}
- remoteaddr = sin.sin_addr;
+
+ memcpy(&remoteaddr, res->ai_addr, res->ai_addrlen);
remotename = salloc(hostname);
x = 0x01020304;
(void) write (netfile,(char *)&x,sizeof(int));
swapmode = 0; /* swap only on server, not client */
+ freeaddrinfo(res0);
return (SCMOK);
}
@@ -447,12 +487,13 @@
char *remotehost () /* remote host name (if known) */
{
- register struct hostent *h;
+ char h1[NI_MAXHOST];
if (remotename == NULL) {
- h = gethostbyaddr ((char *)&remoteaddr,sizeof(remoteaddr),
- AF_INET);
- remotename = salloc (h ? h->h_name : inet_ntoa(remoteaddr));
+ if (getnameinfo((struct sockaddr *)&remoteaddr,
+ remoteaddr.ss_len, h1, sizeof(h1), NULL, 0, 0))
+ return("UNKNOWN");
+ remotename = salloc (h1);
if (remotename == NULL)
return("UNKNOWN");
}
@@ -474,59 +515,66 @@
int samehost () /* is remote host same as local host? */
{
- static struct in_addr *intp;
- static int nint = 0;
- struct in_addr *ifp;
- int n;
-
- if (nint <= 0) {
- int s;
- char buf[BUFSIZ];
- struct ifconf ifc;
- struct ifreq *ifr;
- struct sockaddr_in sin;
-
- if ((s = socket (AF_INET,SOCK_DGRAM,0)) < 0)
- logquit (1,"Can't create socket for SIOCGIFCONF");
- ifc.ifc_len = sizeof(buf);
- ifc.ifc_buf = buf;
- if (ioctl (s,SIOCGIFCONF,(char *)&ifc) < 0)
- logquit (1,"SIOCGIFCONF failed");
- (void) close(s);
- if ((nint = ifc.ifc_len/sizeof(struct ifreq)) <= 0)
- return (0);
- intp = (struct in_addr *)
- malloc ((unsigned) nint*sizeof(struct in_addr));
- if ((ifp = intp) == 0)
- logquit (1,"no space for interfaces");
- for (ifr = ifc.ifc_req, n = nint; n > 0; --n, ifr++) {
- (void) bcopy ((char *)&ifr->ifr_addr,(char *)&sin,sizeof(sin));
- *ifp++ = sin.sin_addr;
+ struct ifaddrs *ifap, *ifa;
+ char h1[NI_MAXHOST], h2[NI_MAXHOST];
+#ifdef NI_WITHSCOPEID
+ const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
+#else
+ const int niflags = NI_NUMERICHOST;
+#endif
+
+ if (getnameinfo((struct sockaddr *)&remoteaddr, remoteaddr.ss_len,
+ h1, sizeof(h1), NULL, 0, niflags))
+ return (0);
+ if (getifaddrs(&ifap) < 0)
+ return (0);
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (remoteaddr.ss_family != ifa->ifa_addr->sa_family)
+ continue;
+ if (getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len,
+ h2, sizeof(h2), NULL, 0, niflags))
+ continue;
+ if (strcmp(h1, h2) == 0) {
+ freeifaddrs(ifap);
+ return (1);
}
}
- if (remoteaddr.s_addr == htonl(INADDR_LOOPBACK))
- return (1);
- for (ifp = intp, n = nint; n > 0; --n, ifp++)
- if (remoteaddr.s_addr == ifp->s_addr)
- return (1);
+ freeifaddrs(ifap);
return (0);
}
int matchhost (name) /* is this name of remote host? */
char *name;
{
- struct hostent *h;
- struct in_addr addr;
- char **ap;
- if ((addr.s_addr = inet_addr(name)) != (u_long) INADDR_NONE)
- return (addr.s_addr == remoteaddr.s_addr);
- if ((h = gethostbyname (name)) == 0)
+ char h1[NI_MAXHOST], h2[NI_MAXHOST];
+#ifdef NI_WITHSCOPEID
+ const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
+#else
+ const int niflags = NI_NUMERICHOST;
+#endif
+ struct addrinfo hints, *res0, *res;
+
+ if (getnameinfo((struct sockaddr *)&remoteaddr, remoteaddr.ss_len,
+ h1, sizeof(h1), NULL, 0, niflags))
return (0);
- if (h->h_addrtype != AF_INET || h->h_length != sizeof(struct in_addr))
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(name, "0", &hints, &res0) != 0)
return (0);
- for (ap = h->h_addr_list; *ap; ap++)
- if (bcmp ((char *)&remoteaddr,*ap,h->h_length) == 0)
+ for (res = res0; res; res = res->ai_next) {
+ if (remoteaddr.ss_family != res->ai_family)
+ continue;
+ if (getnameinfo(res->ai_addr, res->ai_addrlen,
+ h2, sizeof(h2), NULL, 0, niflags))
+ continue;
+ if (strcmp(h1, h2) == 0) {
+ freeaddrinfo(res0);
return (1);
+ }
+ }
+ freeaddrinfo(res0);
return (0);
}
Index: source/supextern.h
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/sup/source/supextern.h,v
retrieving revision 1.14
diff -u -r1.14 supextern.h
--- source/supextern.h 2000/12/30 21:36:23 1.14
+++ source/supextern.h 2001/09/11 02:28:04
@@ -82,7 +82,7 @@
void cdprefix __P((char *));
/* scm.c */
-int servicesetup __P((char *));
+int servicesetup __P((char *, int));
int service __P((void));
int serviceprep __P((void));
int servicekill __P((void));
Index: source/supfilesrv.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/sup/source/supfilesrv.c,v
retrieving revision 1.20
diff -u -r1.20 supfilesrv.c
--- source/supfilesrv.c 2001/01/16 02:50:32 1.20
+++ source/supfilesrv.c 2001/09/11 02:28:06
@@ -232,6 +232,7 @@
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/mount.h>
+#include <sys/socket.h>
#ifndef HAS_POSIX_DIR
#include <sys/dir.h>
#else
@@ -500,9 +501,9 @@
usage ()
{
#ifdef LIBWRAP
- quit (1,"Usage: supfilesrv [ -l | -d | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
+ quit (1,"Usage: supfilesrv [ -4 | -6 | -l | -d | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
#else
- quit (1,"Usage: supfilesrv [ -d | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
+ quit (1,"Usage: supfilesrv [ -4 | -6 | -d | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
#endif
}
@@ -518,6 +519,7 @@
char buf[STRINGLENGTH];
int maxsleep;
register FILE *f;
+ int af = AF_INET;
#ifdef RCS
candorcs = FALSE;
@@ -574,6 +576,12 @@
candorcs = TRUE;
break;
#endif
+ case '4':
+ af = AF_INET;
+ break;
+ case '6':
+ af = AF_INET6;
+ break;
default:
fprintf (stderr,"Unknown flag %s ignored\n",argv[0]);
break;
@@ -584,7 +592,7 @@
if (clienthost == NULL) {
if (argc != 0)
usage ();
- x = servicesetup (dbgportsq ? DEBUGFPORT : FILEPORT);
+ x = servicesetup (dbgportsq ? DEBUGFPORT : FILEPORT, af);
if (x != SCMOK)
quit (1,"Error in network setup");
for (i = 0; i < HASHSIZE; i++)