From f695d00d401d3b83807885a482d705bb10db2098 Mon Sep 17 00:00:00 2001 From: Assar Westerlund Date: Fri, 5 May 2000 17:37:36 +0000 Subject: [PATCH] (tn): re-enable source routing (sourceroute): make it work again based on the code from itojun@kame.net git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@8204 ec53bebd-3082-4978-b11e-865c3cabbd6b --- appl/telnet/telnet/commands.c | 282 ++++++++++++++++++++++------------ 1 file changed, 183 insertions(+), 99 deletions(-) diff --git a/appl/telnet/telnet/commands.c b/appl/telnet/telnet/commands.c index df3c439e1..ef5ee2089 100644 --- a/appl/telnet/telnet/commands.c +++ b/appl/telnet/telnet/commands.c @@ -2063,10 +2063,6 @@ int tn(int argc, char **argv) { struct servent *sp = 0; -#if defined(IP_OPTIONS) && defined(IPPROTO_IP) - char *srp = 0; - int srlen; -#endif char *cmd, *hostp = 0, *portp = 0; char *user = 0; int port = 0; @@ -2122,6 +2118,22 @@ tn(int argc, char **argv) if (hostp == 0) goto usage; + strlcpy (_hostname, hostp, sizeof(_hostname)); + if (hostp[0] == '@' || hostp[0] == '!') { + char *p; + hostname = NULL; + for (p = hostp + 1; *p; p++) { + if (*p == ',' || *p == '@') + hostname = p; + } + if (hostname == NULL) { + fprintf(stderr, "%s: bad source route specification\n", hostp); + return 0; + } + *hostname++ = '\0'; + } else + hostname = hostp; + if (portp) { if (*portp == '-') { portp++; @@ -2166,14 +2178,12 @@ tn(int argc, char **argv) snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); - error = getaddrinfo (hostp, portstr, &hints, &ai); + error = getaddrinfo (hostname, portstr, &hints, &ai); if (error) { - fprintf (stderr, "%s: %s\r\n", hostp, gai_strerror (error)); + fprintf (stderr, "%s: %s\r\n", hostname, gai_strerror (error)); setuid (getuid ()); return 0; } - strlcpy (_hostname, hostp, sizeof(_hostname)); - hostname = _hostname; for (a = ai; a != NULL && connected == 0; a = a->ai_next) { char addrstr[256]; @@ -2194,11 +2204,23 @@ tn(int argc, char **argv) warn ("socket"); continue; } + #if defined(IP_OPTIONS) && defined(IPPROTO_IP) && defined(HAVE_SETSOCKOPT) - if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, - (void *)srp, srlen) < 0) - perror("setsockopt (IP_OPTIONS)"); + if (hostp[0] == '@' || hostp[0] == '!') { + char *srp = 0; + int srlen; + int proto, opt; + + if ((srlen = sourceroute(a, hostp, &srp, &proto, &opt)) < 0) { + (void) NetClose(net); + net = -1; + continue; + } + if (srp && setsockopt(net, proto, opt, srp, srlen) < 0) + perror("setsockopt (source route)"); + } #endif + #if defined(IPPROTO_IP) && defined(IP_TOS) if (a->ai_family == AF_INET) { # if defined(HAVE_GETTOSBYNAME) @@ -2450,16 +2472,15 @@ help(int argc, char **argv) } -#if 0 /* XXX - broken */ - #if defined(IP_OPTIONS) && defined(IPPROTO_IP) /* * Source route is handed in as - * [!]@hop1@hop2...[@|:]dst - * If the leading ! is present, it is a - * strict source route, otherwise it is - * assmed to be a loose source route. + * [!]@hop1@hop2...@dst + * + * If the leading ! is present, it is a strict source route, otherwise it is + * assmed to be a loose source route. Note that leading ! is effective + * only for IPv4 case. * * We fill in the source route option as * hop1,hop2,hop3...dest @@ -2467,134 +2488,197 @@ help(int argc, char **argv) * be the address to connect() to. * * Arguments: - * arg: pointer to route list to decipher + * ai: The address (by struct addrinfo) for the final destination. * - * cpp: If *cpp is not equal to NULL, this is a - * pointer to a pointer to a character array - * that should be filled in with the option. + * arg: Pointer to route list to decipher * + * cpp: Pointer to a pointer, so that sourceroute() can return + * the address of result buffer (statically alloc'ed). + * + * protop/optp: + * Pointer to an integer. The pointed variable * lenp: pointer to an integer that contains the * length of *cpp if *cpp != NULL. * * Return values: * - * Returns the address of the host to connect to. If the + * Returns the length of the option pointed to by *cpp. If the * return value is -1, there was a syntax error in the - * option, either unknown characters, or too many hosts. - * If the return value is 0, one of the hostnames in the - * path is unknown, and *cpp is set to point to the bad - * hostname. + * option, either arg contained unknown characters or too many hosts, + * or hostname cannot be resolved. * - * *cpp: If *cpp was equal to NULL, it will be filled - * in with a pointer to our static area that has - * the option filled in. This will be 32bit aligned. + * The caller needs to pass return value (len), *cpp, *protop and *optp + * to setsockopt(2). * - * *lenp: This will be filled in with how long the option - * pointed to by *cpp is. + * *cpp: Points to the result buffer. The region is statically + * allocated by the function. + * + * *protop: + * protocol # to be passed to setsockopt(2). + * + * *optp: option # to be passed to setsockopt(2). * */ -unsigned long -sourceroute(char *arg, char **cpp, int *lenp) +int +sourceroute(struct addrinfo *ai, + char *arg, + char **cpp, + int *protop, + int *optp) { - static char lsr[44]; char *cp, *cp2, *lsrp, *lsrep; - int tmp; - struct in_addr sin_addr; - struct hostent *host = 0; - char c; + struct addrinfo hints, *res; + int len, error; + struct sockaddr_in *sin; + register char c; + static char lsr[44]; +#ifdef INET6 + struct cmsghdr *cmsg; + struct sockaddr_in6 *sin6; + static char rhbuf[1024]; +#endif /* - * Verify the arguments, and make sure we have - * at least 7 bytes for the option. + * Verify the arguments. */ - if (cpp == NULL || lenp == NULL) - return((unsigned long)-1); - if (*cpp != NULL && *lenp < 7) - return((unsigned long)-1); - /* - * Decide whether we have a buffer passed to us, - * or if we need to use our own static buffer. - */ - if (*cpp) { - lsrp = *cpp; - lsrep = lsrp + *lenp; - } else { - *cpp = lsrp = lsr; - lsrep = lsrp + 44; - } + if (cpp == NULL) + return -1; cp = arg; - /* - * Next, decide whether we have a loose source - * route or a strict source route, and fill in - * the begining of the option. - */ - if (*cp == '!') { + *cpp = NULL; + switch (ai->ai_family) { + case AF_INET: + lsrp = lsr; + lsrep = lsrp + sizeof(lsr); + + /* + * Next, decide whether we have a loose source + * route or a strict source route, and fill in + * the begining of the option. + */ + if (*cp == '!') { + cp++; + *lsrp++ = IPOPT_SSRR; + } else + *lsrp++ = IPOPT_LSRR; + if (*cp != '@') + return -1; + lsrp++; /* skip over length, we'll fill it in later */ + *lsrp++ = 4; cp++; - *lsrp++ = IPOPT_SSRR; - } else - *lsrp++ = IPOPT_LSRR; + *protop = IPPROTO_IP; + *optp = IP_OPTIONS; + break; +#ifdef INET6 + case AF_INET6: + cmsg = inet6_rthdr_init(rhbuf, IPV6_RTHDR_TYPE_0); + if (*cp != '@') + return -1; + cp++; + *protop = IPPROTO_IPV6; + *optp = IPV6_PKTOPTIONS; + break; +#endif + default: + return -1; + } - if (*cp != '@') - return((unsigned long)-1); - - lsrp++; /* skip over length, we'll fill it in later */ - *lsrp++ = 4; - - cp++; - - sin_addr.s_addr = 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ai->ai_family; + hints.ai_socktype = SOCK_STREAM; for (c = 0;;) { if (c == ':') cp2 = 0; - else for (cp2 = cp; (c = *cp2); cp2++) { + else for (cp2 = cp; (c = *cp2) != '\0'; cp2++) { if (c == ',') { *cp2++ = '\0'; if (*cp2 == '@') cp2++; } else if (c == '@') { *cp2++ = '\0'; - } else if (c == ':') { + } +#if 0 /*colon conflicts with IPv6 address*/ + else if (c == ':') { *cp2++ = '\0'; - } else + } +#endif + else continue; break; } if (!c) cp2 = 0; - if ((tmp = inet_addr(cp)) != -1) { - sin_addr.s_addr = tmp; - } else if ((host = roken_gethostbyname(cp))) { - memmove(&sin_addr, - host->h_addr_list[0], - sizeof(sin_addr)); - } else { - *cpp = cp; - return(0); + error = getaddrinfo(cp, NULL, &hints, &res); + if (error) { + fprintf(stderr, "%s: %s\n", cp, gai_strerror(error)); + return -1; } - memmove(lsrp, &sin_addr, 4); - lsrp += 4; + if (ai->ai_family != res->ai_family) { + freeaddrinfo(res); + return -1; + } + if (ai->ai_family == AF_INET) { + /* + * Check to make sure there is space for address + */ + if (lsrp + 4 > lsrep) { + freeaddrinfo(res); + return -1; + } + sin = (struct sockaddr_in *)res->ai_addr; + memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr)); + lsrp += sizeof(struct in_addr); + } +#ifdef INET6 + else if (ai->ai_family == AF_INET6) { + sin6 = (struct sockaddr_in6 *)res->ai_addr; + inet6_rthdr_add(cmsg, &sin6->sin6_addr, + IPV6_RTHDR_LOOSE); + } +#endif + else { + freeaddrinfo(res); + return -1; + } + freeaddrinfo(res); if (cp2) cp = cp2; else break; - /* - * Check to make sure there is space for next address - */ + } + if (ai->ai_family == AF_INET) { + /* record the last hop */ if (lsrp + 4 > lsrep) - return((unsigned long)-1); + return -1; + sin = (struct sockaddr_in *)ai->ai_addr; + memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr)); + lsrp += sizeof(struct in_addr); +#ifndef sysV88 + lsr[IPOPT_OLEN] = lsrp - lsr; + if (lsr[IPOPT_OLEN] <= 7 || lsr[IPOPT_OLEN] > 40) + return -1; + *lsrp++ = IPOPT_NOP; /*32bit word align*/ + len = lsrp - lsr; + *cpp = lsr; +#else + ipopt.io_len = lsrp - lsr; + if (ipopt.io_len <= 5) /*is 3 better?*/ + return -1; + *cpp = (char 8)&ipopt; +#endif } - if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { - *cpp = 0; - *lenp = 0; - return((unsigned long)-1); +#ifdef INET6 + else if (ai->ai_family == AF_INET6) { + inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); + len = cmsg->cmsg_len; + *cpp = rhbuf; } - *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ - *lenp = lsrp - *cpp; - return(sin_addr.s_addr); +#endif + else + return -1; + return len; } #endif -#endif