From 84861c13f9cdaacde411cb90b3e11f57785ddeb2 Mon Sep 17 00:00:00 2001 From: Hajimu UMEMOTO Date: Thu, 25 May 2000 16:38:22 +0000 Subject: [PATCH] IPv6 support. Add $FreeBSD$. --- gnu/libexec/uucp/common_sources/config.h | 9 + gnu/libexec/uucp/common_sources/uuconf.h | 4 + gnu/libexec/uucp/doc/uucp.texi | 30 ++- gnu/libexec/uucp/libunix/tcp.c | 233 +++++++++++++---------- gnu/libexec/uucp/libuuconf/hport.c | 14 ++ gnu/libexec/uucp/libuuconf/tportc.c | 36 ++++ gnu/libexec/uucp/libuuconf/vsinfo.c | 14 ++ 7 files changed, 242 insertions(+), 98 deletions(-) diff --git a/gnu/libexec/uucp/common_sources/config.h b/gnu/libexec/uucp/common_sources/config.h index fdd90125dacc..504d011554fd 100644 --- a/gnu/libexec/uucp/common_sources/config.h +++ b/gnu/libexec/uucp/common_sources/config.h @@ -1,6 +1,8 @@ /* config.h. Generated automatically by configure. */ /* Configuration header file for Taylor UUCP. -*- C -*- */ +/* $FreeBSD$ */ + /* If your compiler does not use const correctly, then undefine it here. This #undef is commented out by the configure script if it determines that const is supported. */ @@ -217,6 +219,9 @@ is on AIX. */ #define HAVE_TXADDCD 0 +/* Set HAVE_SOCKADDR_SA_LEN to 1 if struct sockaddr has sa_len member. */ +#define HAVE_SOCKADDR_SA_LEN 1 + /* There are now a number of functions to check for. For each of these, the macro HAVE_FUNC should be set to 1 if your system has FUNC. For example, HAVE_VFPRINTF should be set to 1 if your system @@ -288,6 +293,10 @@ #define HAVE_STRRCHR 1 #define HAVE_RINDEX 1 +/* If neither of these functions exists, you should add getaddrinfo.o to + lib/Makefile. */ +#define HAVE_GETADDRINFO 1 + /* There are also Unix specific functions which are replaced in the subdirectory unix. If they are missing, the configure script will automatically add them to unix/Makefile to force them to be diff --git a/gnu/libexec/uucp/common_sources/uuconf.h b/gnu/libexec/uucp/common_sources/uuconf.h index 3909888b6a85..32f653d45a8d 100644 --- a/gnu/libexec/uucp/common_sources/uuconf.h +++ b/gnu/libexec/uucp/common_sources/uuconf.h @@ -29,6 +29,8 @@ c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. */ +/* $FreeBSD$ */ + #ifndef UUCONF_H #define UUCONF_H @@ -417,6 +419,8 @@ struct uuconf_tcp_port /* The TCP port number to use. May be a name or a number. May be NULL, in which case "uucp" is looked up using getservbyname. */ char *uuconf_zport; + /* Address family to use for a TCP connection. */ + int uuconf_zfamily; /* A NULL terminated sequence of dialer/token pairs (element 0 is a dialer name, element 1 is a token, etc.) May be NULL. */ char **uuconf_pzdialer; diff --git a/gnu/libexec/uucp/doc/uucp.texi b/gnu/libexec/uucp/doc/uucp.texi index 50ff55646f1b..a73d34b57898 100644 --- a/gnu/libexec/uucp/doc/uucp.texi +++ b/gnu/libexec/uucp/doc/uucp.texi @@ -1,4 +1,7 @@ \input texinfo @c -*-texinfo-*- + +@c $FreeBSD$ + @c %**start of header @setfilename uucp.info @settitle Taylor UUCP @@ -5204,6 +5207,13 @@ string @samp{uucp} is looked up in @file{/etc/services}. If it is not found, port number 540 (the standard UUCP-over-TCP port number) will be used. +@item family @var{string} [ tcp only ] +@findex family + +Name the protocol family to use. Available value is @samp{inet} for +IPv4 only, @samp{inet6} for IPv6 only, or @samp{inet46} for both IPv4 +and IPv6. The default is @samp{inet46}. + @item push @var{strings} [ tli only ] @findex push @@ -5474,7 +5484,12 @@ Files}), add the line @samp{port type tcp} to the entry in the @samp{uucp} in @file{/etc/services}; if the @samp{uucp} service is not defined, port 540 will be used. You can set the port number to use with the command @samp{port service @var{xxx}}, where @var{xxx} can be either -a number or a name to look up in @file{/etc/services}. You can specify +a number or a name to look up in @file{/etc/services}. By default UUCP +will determine the protocol family by querying DNS; if the AAAA record +is found, IPv6 will be used, and if not found, IPv4 will be used. You +can set the protocol family to use with the command @samp{port family +@var{xxx}}, where @var{xxx} can be @samp{inet} for IPv4 only, +@samp{inet6} for IPv6 only or @samp{inet46} for both. You can specify the address of the remote host with @samp{address @var{a.b.c}}; if you don't give an address, the remote system name will be used. You should give an explicit chat script for the system when you use TCP; the @@ -5506,6 +5521,10 @@ be called at any time, over TCP, using port number @samp{uucp} (as found in @file{/etc/services}; this may be specified as a number), using remote host @file{@var{host}.@var{domain}}, with some chat script. +@samp{port family @var{xxx}} command is not supported by V2 +configuration files or HDB configuration files. So, with these +configuration files, IPv6 is disabled for compatibility reason. + @node TCP Server, , TCP Client, UUCP Over TCP @subsection Running a TCP Server @@ -5525,6 +5544,15 @@ child for each one. Each connection will be prompted with @samp{login:} and @samp{Password:}; the results will be checked against the UUCP (not the system) password file (@pxref{Configuration File Names}). +By default UUCP will listen on both IPv4 and IPv6. You can set the +protocol family to listen with the command @samp{port family @var{xxx}}, +where @var{xxx} can be @samp{inet} for IPv4 only, @samp{inet6} for IPv6 +only or @samp{inet46} for both IPv4 and IPv6. + +@samp{port family @var{xxx}} command is not supported by V2 +configuration files or HDB configuration files. So, with these +configuration files, IPv6 is disabled for compatibility reason. + Another way to run a UUCP TCP server is to use the BSD @code{uucpd} program. diff --git a/gnu/libexec/uucp/libunix/tcp.c b/gnu/libexec/uucp/libunix/tcp.c index 0791900d56a2..595b4149c289 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) - { - s.sin_family = q->h_addrtype; - memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length); - } - 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; - } - } - zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; - s.sin_port = itcp_port_number (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) + { + ulog (LOG_ERROR, "getaddrinfo (%s, %s): %s", + zhost, zport, gai_strerror (err)); + return FALSE; + } - if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 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) + continue; + if (connect (qsysdep->o, res->ai_addr, res->ai_addrlen) >= 0) + { + connected = TRUE; + break; + } + close (qsysdep->o); + } + 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; + int err; - 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; - - 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 */ diff --git a/gnu/libexec/uucp/libuuconf/hport.c b/gnu/libexec/uucp/libuuconf/hport.c index 23d59abe8f46..2836fbc54ae3 100644 --- a/gnu/libexec/uucp/libuuconf/hport.c +++ b/gnu/libexec/uucp/libuuconf/hport.c @@ -29,6 +29,7 @@ const char _uuconf_hport_rcsid[] = "$FreeBSD$"; #endif +#include #include #include @@ -217,6 +218,19 @@ uuconf_hdb_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport) | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX | UUCONF_RELIABLE_SPECIFIED); qport->uuconf_u.uuconf_stcp.uuconf_zport = pzsplit[1]; + + /* I leave with IPv4 only for compatibility reason. If + you wish to use IPv6, please try Taylor UUCP + configuration instead. If you still wish to use IPv6 + with HDB configuration, re-make with INET6 defined. + In this case, you cannot specify the protocol family + in HDB configuration file. */ +#ifdef INET6 + qport->uuconf_u.uuconf_stcp.uuconf_zfamily = PF_UNSPEC; +#else + qport->uuconf_u.uuconf_stcp.uuconf_zfamily = PF_INET; +#endif + ppzdialer = &qport->uuconf_u.uuconf_stcp.uuconf_pzdialer; } else if (ctoks >= 5 diff --git a/gnu/libexec/uucp/libuuconf/tportc.c b/gnu/libexec/uucp/libuuconf/tportc.c index b07d49a15f95..60467bc03429 100644 --- a/gnu/libexec/uucp/libuuconf/tportc.c +++ b/gnu/libexec/uucp/libuuconf/tportc.c @@ -29,6 +29,7 @@ const char _uuconf_tportc_rcsid[] = "$FreeBSD$"; #endif +#include #include static int ipproto_param P((pointer pglobal, int argc, char **argv, @@ -37,6 +38,8 @@ static int ipbaud_range P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int ipdialer P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); +static int ipfamily P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); static int ipcunknown P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); @@ -151,6 +154,9 @@ static const struct cmdtab_offset asPtcp_cmds[] = { "service", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_zport), NULL }, + { "family", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_zfamily), + ipfamily }, { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_pzdialer), NULL }, @@ -279,6 +285,7 @@ _uuconf_iport_cmd (qglobal, argc, argv, qport) break; case UUCONF_PORTTYPE_TCP: qport->uuconf_u.uuconf_stcp.uuconf_zport = (char *) "uucp"; + qport->uuconf_u.uuconf_stcp.uuconf_zfamily = PF_UNSPEC; qport->uuconf_u.uuconf_stcp.uuconf_pzdialer = NULL; qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED | UUCONF_RELIABLE_ENDTOEND @@ -489,6 +496,35 @@ ipdialer (pglobal, argc, argv, pvar, pinfo) return iret; } } + +/* Handle a "family" commands. The first argument is "inet" for + PF_INET or "inet6" for PF_INET6 */ + +/*ARGSUSED*/ +static int +ipfamily (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + int *pzfamily = (int *) pvar; + + if (argc < 2) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + if (!strcmp(argv[1], "inet")) + *pzfamily = PF_INET; +#if HAVE_GETADDRINFO + else if (!strcmp(argv[1], "inet6")) + *pzfamily = PF_INET6; +#endif + else if (!strcmp(argv[1], "inet46")) + *pzfamily = PF_UNSPEC; + else + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + return UUCONF_CMDTABRET_KEEP; +} /* Give an error for an unknown port command. */ diff --git a/gnu/libexec/uucp/libuuconf/vsinfo.c b/gnu/libexec/uucp/libuuconf/vsinfo.c index 4ca8005b7e07..853ae70483e3 100644 --- a/gnu/libexec/uucp/libuuconf/vsinfo.c +++ b/gnu/libexec/uucp/libuuconf/vsinfo.c @@ -29,6 +29,7 @@ const char _uuconf_vsinfo_rcsid[] = "$FreeBSD$"; #endif +#include #include #include @@ -271,6 +272,19 @@ _uuconf_iv2_system_internal (qglobal, zsystem, qsys) else qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_zport = pzsplit[3]; + + /* I leave with IPv4 only for compatibility reason. If you + wish to use IPv6, please try Taylor UUCP configuration + instead. If you still wish to use IPv6 with V2 + configuration, re-make with INET6 defined. In this case, + you cannot specify the protocol family in V2 + configuration file. */ +#ifdef INET6 + qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_zfamily = PF_UNSPEC; +#else + qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_zfamily = PF_INET; +#endif + qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_pzdialer = NULL; }