From 9d63cb2085c2e34ecf7fdeced7953897170810f6 Mon Sep 17 00:00:00 2001 From: wollman Date: Fri, 22 Sep 2000 01:06:40 +0000 Subject: Implement IPv6 support. Also restructure the way multi-homed hosts are treated, regardless of protocol. --- usr.bin/finger/net.c | 148 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 57 deletions(-) (limited to 'usr.bin/finger/net.c') diff --git a/usr.bin/finger/net.c b/usr.bin/finger/net.c index 2903c06..00547ec 100644 --- a/usr.bin/finger/net.c +++ b/usr.bin/finger/net.c @@ -62,66 +62,72 @@ static const char rcsid[] = #include #include "finger.h" -void -cleanup(sig) - int sig; -{ - exit(0); -} +extern int lflag; /* XXX finger.h? */ +extern int Tflag; /* XXX finger.h? */ + +static void cleanup(int sig);; +static int do_protocol(const char *name, const struct addrinfo *ai); +static void trying(const struct addrinfo *ai); void netfinger(name) char *name; { - int cnt; - int line_len; - extern int lflag; - extern int Tflag; - register FILE *fp; - register int c, lastc; - struct in_addr defaddr; - struct hostent *hp, def; - struct servent *sp; - struct sockaddr_in sin; - int s; - char *alist[1], *host; - struct iovec iov[3]; - struct msghdr msg; + int error, multi; + char *host; + struct addrinfo *ai, *ai0; + static struct addrinfo hint; - if (!(host = rindex(name, '@'))) + host = strrchr(name, '@'); + if (host == 0) return; *host++ = '\0'; signal(SIGALRM, cleanup); - (void) alarm(TIME_LIMIT); - if (isdigit(*host) && (defaddr.s_addr = inet_addr(host)) != -1) { - def.h_name = host; - def.h_addr_list = alist; - def.h_addr = (char *)&defaddr; - def.h_length = sizeof(struct in_addr); - def.h_addrtype = AF_INET; - def.h_aliases = 0; - hp = &def; - } else if (!(hp = gethostbyname(host))) { - warnx("unknown host: %s", host); - return; - } - if (!(sp = getservbyname("finger", "tcp"))) { - warnx("tcp/finger: unknown service"); + alarm(TIME_LIMIT); + + hint.ai_flags = AI_CANONNAME; + hint.ai_family = PF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + + error = getaddrinfo(host, "finger", &hint, &ai0); + if (error) { + warnx("%s: %s", host, gai_strerror(error)); return; } - sin.sin_family = hp->h_addrtype; - bcopy(hp->h_addr, (char *)&sin.sin_addr, MIN(hp->h_length,sizeof(sin.sin_addr))); - sin.sin_port = sp->s_port; - if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { - perror("finger: socket"); - return; + + multi = (ai0->ai_next) != 0; + printf("[%s]\n", ai0->ai_canonname); + + for (ai = ai0; ai != 0; ai = ai->ai_next) { + if (multi) + trying(ai); + + error = do_protocol(name, ai); + if (!error) + break; } + alarm(0); + freeaddrinfo(ai0); +} - /* have network connection; identify the host connected with */ - (void)printf("[%s]\n", hp->h_name); +static int +do_protocol(const char *name, const struct addrinfo *ai) +{ + int cnt, error, line_len, s; + register FILE *fp; + register int c, lastc; + struct iovec iov[3]; + struct msghdr msg; - msg.msg_name = (void *)&sin; - msg.msg_namelen = sizeof sin; + s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (s < 0) { + warn("socket(%d, %d, %d)", ai->ai_family, ai->ai_socktype, + ai->ai_protocol); + return -1; + } + + msg.msg_name = (void *)ai->ai_addr; + msg.msg_namelen = ai->ai_addrlen; msg.msg_iov = iov; msg.msg_iovlen = 0; msg.msg_control = 0; @@ -139,16 +145,22 @@ netfinger(name) iov[msg.msg_iovlen].iov_base = "\r\n"; iov[msg.msg_iovlen++].iov_len = 2; - /* -T disables T/TCP: compatibility option to finger broken hosts */ - if (Tflag && connect(s, (struct sockaddr *)&sin, sizeof (sin))) { - perror("finger: connect"); - return; + /* + * -T disables data-on-SYN: compatibility option to finger broken + * hosts. Also, the implicit-open API is broken on IPv6, so do + * the explicit connect there, too. + */ + if ((Tflag || ai->ai_addr->sa_family == AF_INET6) + && connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { + warn("connect"); + close(s); + return -1; } if (sendmsg(s, &msg, 0) < 0) { - perror("finger: sendmsg"); + warn("sendmsg"); close(s); - return; + return -1; } /* @@ -199,15 +211,37 @@ netfinger(name) if (lastc == '\n' || lastc == '\r') line_len = 0; } - if (lastc != '\n') - putchar('\n'); - if (ferror(fp)) { /* * Assume that whatever it was set errno... */ - perror("finger: read"); + warn("reading from network"); } - (void)fclose(fp); + if (lastc != '\n') + putchar('\n'); + + fclose(fp); } + return 0; +} + +static void +trying(const struct addrinfo *ai) +{ + char buf[NI_MAXHOST]; + + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, buf, sizeof buf, + (char *)0, 0, NI_NUMERICHOST) != 0) + return; /* XXX can't happen */ + + printf("Trying %s...\n", buf); } + +void +cleanup(int sig) +{ +#define ERRSTR "Timed out.\n" + write(STDERR_FILENO, ERRSTR, sizeof ERRSTR); + exit(1); +} + -- cgit v1.1