diff options
author | ume <ume@FreeBSD.org> | 2000-05-25 16:38:22 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2000-05-25 16:38:22 +0000 |
commit | 96ab0c2c8f9f2ca7d3466f5a45d469ba0224c598 (patch) | |
tree | 0e4851a1c2d374b1d70b19f9c6d2ccc80b4ef33e /gnu/libexec/uucp/libunix | |
parent | f8a289a9a13527f37032e3cb9b395ac7f9e6ffb5 (diff) | |
download | FreeBSD-src-96ab0c2c8f9f2ca7d3466f5a45d469ba0224c598.zip FreeBSD-src-96ab0c2c8f9f2ca7d3466f5a45d469ba0224c598.tar.gz |
IPv6 support.
Add $FreeBSD$.
Diffstat (limited to 'gnu/libexec/uucp/libunix')
-rw-r--r-- | gnu/libexec/uucp/libunix/tcp.c | 227 |
1 files changed, 133 insertions, 94 deletions
diff --git a/gnu/libexec/uucp/libunix/tcp.c b/gnu/libexec/uucp/libunix/tcp.c index 0791900..595b414 100644 --- a/gnu/libexec/uucp/libunix/tcp.c +++ b/gnu/libexec/uucp/libunix/tcp.c @@ -63,7 +63,7 @@ const char tcp_rcsid[] = "$FreeBSD$"; interface. */ /* The normal "uucp" port number. */ -#define IUUCP_PORT (540) +#define IUUCP_PORT "540" /* Local functions. */ static void utcp_free P((struct sconnection *qconn)); @@ -78,7 +78,9 @@ static boolean ftcp_dial P((struct sconnection *qconn, pointer puuconf, const char *zphone, struct uuconf_dialer *qdialer, enum tdialerfound *ptdialer)); -static int itcp_port_number P((const char *zport)); +static int itcp_getaddrinfo P((const char *zhost, const char *zport, + const struct addrinfo *hints, + struct addrinfo **res)); /* The command table for a TCP connection. */ static const struct sconncmds stcpcmds = @@ -131,34 +133,13 @@ utcp_free (qconn) { xfree (qconn->psysdep); } - -/* Open a TCP connection. If the fwait argument is TRUE, we are - running as a server. Otherwise we are just trying to reach another - system. */ static boolean -ftcp_open (qconn, ibaud, fwait) - struct sconnection *qconn; - long ibaud; - boolean fwait; +utcp_init (qsysdep) + struct ssysdep_conn *qsysdep; { - struct ssysdep_conn *qsysdep; - struct sockaddr_in s; - const char *zport; - uid_t ieuid; - boolean fswap; - - ulog_device ("TCP"); - - qsysdep = (struct ssysdep_conn *) qconn->psysdep; - - qsysdep->o = socket (AF_INET, SOCK_STREAM, 0); - if (qsysdep->o < 0) - { - ulog (LOG_ERROR, "socket: %s", strerror (errno)); - return FALSE; - } - + if (!qsysdep) + return FALSE; if (fcntl (qsysdep->o, F_SETFD, fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) { @@ -176,6 +157,32 @@ ftcp_open (qconn, ibaud, fwait) qsysdep->o = -1; return FALSE; } +} + +/* Open a TCP connection. If the fwait argument is TRUE, we are + running as a server. Otherwise we are just trying to reach another + system. */ + +static boolean +ftcp_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + struct ssysdep_conn *qsysdep; + struct addrinfo hints, *res, *res0; + struct sockaddr_storage s; + const char *zport; + int zfamily; + uid_t ieuid; + boolean fswap; + int err; + + ulog_device ("TCP"); + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + qsysdep->o = -1; /* We save our process ID in the qconn structure. This is checked in ftcp_close. */ @@ -190,11 +197,68 @@ ftcp_open (qconn, ibaud, fwait) From this point on if the server gets an error we exit; we only return if we have received a connection. It would be more robust to respawn the server if it fails; someday. */ - bzero ((pointer) &s, sizeof s); - s.sin_family = AF_INET; zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; - s.sin_port = itcp_port_number (zport); - s.sin_addr.s_addr = htonl (INADDR_ANY); + zfamily = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zfamily; + memset (&hints, 0, sizeof(hints)); + hints.ai_family = zfamily; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if ((err = itcp_getaddrinfo (NULL, zport, &hints, &res0)) != 0) + { + ulog (LOG_ERROR, "getaddrinfo (NULL, %s): %s", + zport, gai_strerror (err)); + return FALSE; + } +#if HAVE_GETADDRINFO + if (zfamily == PF_UNSPEC) + { + for (res = res0; res; res = res->ai_next) + { + if (res->ai_family == AF_INET6) + { + qsysdep->o = socket (res->ai_family, res->ai_socktype, + res->ai_protocol); + if (qsysdep->o >= 0) + break; + } + } + } +#endif + if (qsysdep->o < 0) + { + for (res = res0; res; res = res->ai_next) + { + qsysdep->o = socket (res->ai_family, res->ai_socktype, + res->ai_protocol); + if (qsysdep->o >= 0) + break; + } + if (qsysdep->o < 0) + { + freeaddrinfo (res); + ulog (LOG_ERROR, "socket: %s", strerror (errno)); + return FALSE; + } + } +#ifdef IPV6_BINDV6ONLY + if (res->ai_family == AF_INET6) + { + int flag = (zfamily == PF_UNSPEC) ? 0 : 1; + + if (setsockopt (qsysdep->o, IPPROTO_IPV6, IPV6_BINDV6ONLY, + (char *)&flag, sizeof (flag)) < 0) + { + freeaddrinfo (res); + ulog (LOG_FATAL, "setsockopt: %s", strerror (errno)); + return FALSE; + } + } +#endif + if (!utcp_init (qsysdep)) + { + freeaddrinfo (res); + return FALSE; + } /* Swap to our real user ID when doing the bind call. This will permit the server to use privileged TCP ports when invoked by @@ -208,16 +272,19 @@ ftcp_open (qconn, ibaud, fwait) { (void) close (qsysdep->o); qsysdep->o = -1; + freeaddrinfo (res); return FALSE; } } - if (bind (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) + if (bind (qsysdep->o, res->ai_addr, res->ai_addrlen) < 0) { + freeaddrinfo (res); if (fswap) (void) fsuucp_perms ((long) ieuid); ulog (LOG_FATAL, "bind: %s", strerror (errno)); } + freeaddrinfo (res); /* Now swap back to the uucp user ID. */ if (fswap) @@ -333,8 +400,8 @@ ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer) { struct ssysdep_conn *qsysdep; const char *zhost; - struct hostent *q; - struct sockaddr_in s; + struct addrinfo hints, *res, *res0; + int err, connected = FALSE; const char *zport; char **pzdialer; @@ -354,37 +421,38 @@ ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer) } errno = 0; - q = gethostbyname ((char *) zhost); - if (q != NULL) + zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; + memset (&hints, 0, sizeof(hints)); + hints.ai_family = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zfamily; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + if ((err = itcp_getaddrinfo (zhost, zport, &hints, &res0)) != 0) { - s.sin_family = q->h_addrtype; - memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length); + ulog (LOG_ERROR, "getaddrinfo (%s, %s): %s", + zhost, zport, gai_strerror (err)); + return FALSE; } - else - { - if (errno != 0) - { - ulog (LOG_ERROR, "gethostbyname (%s): %s", zhost, strerror (errno)); - return FALSE; - } - s.sin_family = AF_INET; - s.sin_addr.s_addr = inet_addr ((char *) zhost); - if ((long) s.sin_addr.s_addr == (long) -1) - { - ulog (LOG_ERROR, "%s: unknown host name", zhost); - return FALSE; + for (res = res0; res; res = res->ai_next) + { + qsysdep->o = socket (res->ai_family, res->ai_socktype, res->ai_protocol); + if (qsysdep->o < 0) + continue; + if (connect (qsysdep->o, res->ai_addr, res->ai_addrlen) >= 0) + { + connected = TRUE; + break; } + close (qsysdep->o); } - - zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; - s.sin_port = itcp_port_number (zport); - - if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) + freeaddrinfo (res0); + if (!connected) { ulog (LOG_ERROR, "connect: %s", strerror (errno)); return FALSE; } + if (!utcp_init (qsysdep)) + return FALSE; /* Handle the dialer sequence, if any. */ pzdialer = qconn->qport->uuconf_u.uuconf_stcp.uuconf_pzdialer; @@ -398,47 +466,18 @@ ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer) return TRUE; } -/* Get the port number given a name. The argument will almost always - be "uucp" so we cache that value. The return value is always in - network byte order. This returns -1 on error. */ - static int -itcp_port_number (zname) - const char *zname; +itcp_getaddrinfo (zhost, zport, hints, res) + const char *zhost, *zport; + const struct addrinfo *hints; + struct addrinfo **res; { - boolean fuucp; - static int iuucp; - int i; - char *zend; - struct servent *q; - - fuucp = strcmp (zname, "uucp") == 0; - if (fuucp && iuucp != 0) - return iuucp; - - /* Try it as a number first. */ - i = strtol ((char *) zname, &zend, 10); - if (i != 0 && *zend == '\0') - return htons (i); - - q = getservbyname ((char *) zname, (char *) "tcp"); - if (q == NULL) - { - /* We know that the "uucp" service should be 540, even if isn't - in /etc/services. */ - if (fuucp) - { - iuucp = htons (IUUCP_PORT); - return iuucp; - } - ulog (LOG_ERROR, "getservbyname (%s): %s", zname, strerror (errno)); - return -1; - } - - if (fuucp) - iuucp = q->s_port; + int err; - return q->s_port; + if ((err = getaddrinfo (zhost, zport, hints, res)) != EAI_SERVICE || + strcmp(zport, "uucp") != 0) + return err; + return getaddrinfo (zhost, IUUCP_PORT, hints, res); } #endif /* HAVE_TCP */ |