(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
This commit is contained in:
Assar Westerlund
2000-05-05 17:37:36 +00:00
parent 181fbb2504
commit f695d00d40

View File

@@ -2063,10 +2063,6 @@ int
tn(int argc, char **argv) tn(int argc, char **argv)
{ {
struct servent *sp = 0; struct servent *sp = 0;
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
char *srp = 0;
int srlen;
#endif
char *cmd, *hostp = 0, *portp = 0; char *cmd, *hostp = 0, *portp = 0;
char *user = 0; char *user = 0;
int port = 0; int port = 0;
@@ -2122,6 +2118,22 @@ tn(int argc, char **argv)
if (hostp == 0) if (hostp == 0)
goto usage; 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) {
if (*portp == '-') { if (*portp == '-') {
portp++; portp++;
@@ -2166,14 +2178,12 @@ tn(int argc, char **argv)
snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); snprintf (portstr, sizeof(portstr), "%u", ntohs(port));
error = getaddrinfo (hostp, portstr, &hints, &ai); error = getaddrinfo (hostname, portstr, &hints, &ai);
if (error) { if (error) {
fprintf (stderr, "%s: %s\r\n", hostp, gai_strerror (error)); fprintf (stderr, "%s: %s\r\n", hostname, gai_strerror (error));
setuid (getuid ()); setuid (getuid ());
return 0; return 0;
} }
strlcpy (_hostname, hostp, sizeof(_hostname));
hostname = _hostname;
for (a = ai; a != NULL && connected == 0; a = a->ai_next) { for (a = ai; a != NULL && connected == 0; a = a->ai_next) {
char addrstr[256]; char addrstr[256];
@@ -2194,11 +2204,23 @@ tn(int argc, char **argv)
warn ("socket"); warn ("socket");
continue; continue;
} }
#if defined(IP_OPTIONS) && defined(IPPROTO_IP) && defined(HAVE_SETSOCKOPT) #if defined(IP_OPTIONS) && defined(IPPROTO_IP) && defined(HAVE_SETSOCKOPT)
if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, if (hostp[0] == '@' || hostp[0] == '!') {
(void *)srp, srlen) < 0) char *srp = 0;
perror("setsockopt (IP_OPTIONS)"); 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 #endif
#if defined(IPPROTO_IP) && defined(IP_TOS) #if defined(IPPROTO_IP) && defined(IP_TOS)
if (a->ai_family == AF_INET) { if (a->ai_family == AF_INET) {
# if defined(HAVE_GETTOSBYNAME) # if defined(HAVE_GETTOSBYNAME)
@@ -2450,16 +2472,15 @@ help(int argc, char **argv)
} }
#if 0 /* XXX - broken */
#if defined(IP_OPTIONS) && defined(IPPROTO_IP) #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
/* /*
* Source route is handed in as * Source route is handed in as
* [!]@hop1@hop2...[@|:]dst * [!]@hop1@hop2...@dst
* If the leading ! is present, it is a *
* strict source route, otherwise it is * If the leading ! is present, it is a strict source route, otherwise it is
* assmed to be a loose source route. * assmed to be a loose source route. Note that leading ! is effective
* only for IPv4 case.
* *
* We fill in the source route option as * We fill in the source route option as
* hop1,hop2,hop3...dest * hop1,hop2,hop3...dest
@@ -2467,134 +2488,197 @@ help(int argc, char **argv)
* be the address to connect() to. * be the address to connect() to.
* *
* Arguments: * 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 * arg: Pointer to route list to decipher
* pointer to a pointer to a character array
* that should be filled in with the option.
* *
* 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 * lenp: pointer to an integer that contains the
* length of *cpp if *cpp != NULL. * length of *cpp if *cpp != NULL.
* *
* Return values: * 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 * return value is -1, there was a syntax error in the
* option, either unknown characters, or too many hosts. * option, either arg contained unknown characters or too many hosts,
* If the return value is 0, one of the hostnames in the * or hostname cannot be resolved.
* path is unknown, and *cpp is set to point to the bad
* hostname.
* *
* *cpp: If *cpp was equal to NULL, it will be filled * The caller needs to pass return value (len), *cpp, *protop and *optp
* in with a pointer to our static area that has * to setsockopt(2).
* the option filled in. This will be 32bit aligned.
* *
* *lenp: This will be filled in with how long the option * *cpp: Points to the result buffer. The region is statically
* pointed to by *cpp is. * allocated by the function.
*
* *protop:
* protocol # to be passed to setsockopt(2).
*
* *optp: option # to be passed to setsockopt(2).
* *
*/ */
unsigned long int
sourceroute(char *arg, char **cpp, int *lenp) sourceroute(struct addrinfo *ai,
char *arg,
char **cpp,
int *protop,
int *optp)
{ {
static char lsr[44];
char *cp, *cp2, *lsrp, *lsrep; char *cp, *cp2, *lsrp, *lsrep;
int tmp; struct addrinfo hints, *res;
struct in_addr sin_addr; int len, error;
struct hostent *host = 0; struct sockaddr_in *sin;
char c; 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 * Verify the arguments.
* at least 7 bytes for the option.
*/ */
if (cpp == NULL || lenp == NULL) if (cpp == NULL)
return((unsigned long)-1); return -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;
}
cp = arg; cp = arg;
/* *cpp = NULL;
* Next, decide whether we have a loose source switch (ai->ai_family) {
* route or a strict source route, and fill in case AF_INET:
* the begining of the option. lsrp = lsr;
*/ lsrep = lsrp + sizeof(lsr);
if (*cp == '!') {
/*
* 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++; cp++;
*lsrp++ = IPOPT_SSRR; *protop = IPPROTO_IP;
} else *optp = IP_OPTIONS;
*lsrp++ = IPOPT_LSRR; 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 != '@') memset(&hints, 0, sizeof(hints));
return((unsigned long)-1); hints.ai_family = ai->ai_family;
hints.ai_socktype = SOCK_STREAM;
lsrp++; /* skip over length, we'll fill it in later */
*lsrp++ = 4;
cp++;
sin_addr.s_addr = 0;
for (c = 0;;) { for (c = 0;;) {
if (c == ':') if (c == ':')
cp2 = 0; cp2 = 0;
else for (cp2 = cp; (c = *cp2); cp2++) { else for (cp2 = cp; (c = *cp2) != '\0'; cp2++) {
if (c == ',') { if (c == ',') {
*cp2++ = '\0'; *cp2++ = '\0';
if (*cp2 == '@') if (*cp2 == '@')
cp2++; cp2++;
} else if (c == '@') { } else if (c == '@') {
*cp2++ = '\0'; *cp2++ = '\0';
} else if (c == ':') { }
#if 0 /*colon conflicts with IPv6 address*/
else if (c == ':') {
*cp2++ = '\0'; *cp2++ = '\0';
} else }
#endif
else
continue; continue;
break; break;
} }
if (!c) if (!c)
cp2 = 0; cp2 = 0;
if ((tmp = inet_addr(cp)) != -1) { error = getaddrinfo(cp, NULL, &hints, &res);
sin_addr.s_addr = tmp; if (error) {
} else if ((host = roken_gethostbyname(cp))) { fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
memmove(&sin_addr, return -1;
host->h_addr_list[0],
sizeof(sin_addr));
} else {
*cpp = cp;
return(0);
} }
memmove(lsrp, &sin_addr, 4); if (ai->ai_family != res->ai_family) {
lsrp += 4; 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) if (cp2)
cp = cp2; cp = cp2;
else else
break; 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) 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) { #ifdef INET6
*cpp = 0; else if (ai->ai_family == AF_INET6) {
*lenp = 0; inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
return((unsigned long)-1); len = cmsg->cmsg_len;
*cpp = rhbuf;
} }
*lsrp++ = IPOPT_NOP; /* 32 bit word align it */ #endif
*lenp = lsrp - *cpp; else
return(sin_addr.s_addr); return -1;
return len;
} }
#endif #endif
#endif