Add more dual stack consideration.

-Should retry as much as possible when some of source
     routing intermediate hosts' address families missmatch
     happened.
     (such as when a host has only A record, and another host
     has each of A and AAAA record.)

    -Should retry as much as possible when dest addr and
     source addr(specified with -s option) address family
     missmatch happend

Approved by: jkh


git-svn-id: http://svn0.us-east.freebsd.org/base/head/contrib/telnet@57125 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f
This commit is contained in:
shin 2000-02-10 20:06:36 +00:00
parent 92a0e6dadf
commit d2ec198a69

View File

@ -108,6 +108,7 @@ extern int Ambiguous();
static int help(int argc, char *argv[]); static int help(int argc, char *argv[]);
static int call(); static int call();
static void cmdrc(char *m1, char *m2); static void cmdrc(char *m1, char *m2);
static int switch_af(struct addrinfo **aip);
int quit(void); int quit(void);
@ -2324,6 +2325,32 @@ setpolicy(net, res, policy)
free(buf); free(buf);
} }
#endif
#ifdef INET6
/*
* When an Address Family related error happend, check if retry with
* another AF is possible or not.
* Return 1, if retry with another af is OK. Else, return 0.
*/
static int
switch_af(aip)
struct addrinfo **aip;
{
int nextaf;
struct addrinfo *ai;
ai = *aip;
nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET;
do
ai=ai->ai_next;
while (ai != NULL && ai->ai_family != nextaf);
*aip = ai;
if (*aip != NULL) {
return 1;
}
return 0;
}
#endif #endif
int int
@ -2331,18 +2358,14 @@ tn(argc, argv)
int argc; int argc;
char *argv[]; char *argv[];
{ {
struct sockaddr_storage ss, src_ss;
char *srp = 0, *strrchr(); char *srp = 0, *strrchr();
int proto, opt; int proto, opt;
int sourceroute(), srlen; int sourceroute(), srlen;
int srcroute = 0, result; int srcroute = 0, result;
char *cmd, *hostp = 0, *portp = 0, *user = 0; char *cmd, *hostp = 0, *portp = 0, *user = 0;
char *src_addr = NULL; char *src_addr = NULL;
struct addrinfo hints, *res; struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL;
int error = 0; int error = 0, af_error = 0;
/* clear the socket address prior to use */
memset((char *)&ss, 0, sizeof(ss));
if (connected) { if (connected) {
printf("?Already connected to %s\n", hostname); printf("?Already connected to %s\n", hostname);
@ -2406,19 +2429,19 @@ tn(argc, argv)
hints.ai_flags = AI_NUMERICHOST; hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = family; hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(src_addr, 0, &hints, &res); error = getaddrinfo(src_addr, 0, &hints, &src_res);
if (error == EAI_NONAME) { if (error == EAI_NONAME) {
hints.ai_flags = 0; hints.ai_flags = 0;
error = getaddrinfo(src_addr, 0, &hints, &res); error = getaddrinfo(src_addr, 0, &hints, &src_res);
} }
if (error != 0) { if (error != 0) {
fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error)); fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
if (error == EAI_SYSTEM) if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", src_addr, strerror(errno)); fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
setuid(getuid());
return 0; return 0;
} }
memcpy((void *)&src_ss, (void *)res->ai_addr, res->ai_addrlen); src_res0 = src_res;
freeaddrinfo(res);
} }
if (hostp[0] == '@' || hostp[0] == '!') { if (hostp[0] == '@' || hostp[0] == '!') {
if ( if (
@ -2464,9 +2487,8 @@ tn(argc, argv)
if (error == EAI_SYSTEM) if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", hostname, strerror(errno)); fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
setuid(getuid()); setuid(getuid());
return 0; goto fail;
} }
memcpy((void *)&ss, (void *)res->ai_addr, res->ai_addrlen);
if (srcroute != 0) if (srcroute != 0)
(void) strncpy(_hostname, hostname, sizeof(_hostname) - 1); (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
else if (res->ai_canonname != NULL) else if (res->ai_canonname != NULL)
@ -2480,20 +2502,33 @@ tn(argc, argv)
if (error == EAI_SYSTEM) if (error == EAI_SYSTEM)
fprintf(stderr, "%s: %s\n", hostname, strerror(errno)); fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
setuid(getuid()); setuid(getuid());
return 0; goto fail;
} }
res0 = res;
if (srcroute != 0) { if (srcroute != 0) {
char hostbuf[BUFSIZ];
strncpy(hostbuf, hostp, BUFSIZ - 1);
hostbuf[BUFSIZ - 1] = '\0';
af_again:
if (af_error != 0)
hostp = hostbuf;
srp = 0; srp = 0;
result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt); result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
if (result == 0) { if (result == 0) {
#ifdef INET6
if (family == AF_UNSPEC && af_error == 0 &&
switch_af(&res) == 1) {
af_error = 1;
goto af_again;
}
#endif
setuid(getuid()); setuid(getuid());
freeaddrinfo(res); goto fail;
return 0;
} else if (result == -1) { } else if (result == -1) {
printf("Bad source route option: %s\n", hostp); printf("Bad source route option: %s\n", hostp);
setuid(getuid()); setuid(getuid());
freeaddrinfo(res); goto fail;
return 0;
} }
} }
printf("Trying %s...\n", sockaddr_ntop(res->ai_addr)); printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
@ -2501,8 +2536,15 @@ tn(argc, argv)
net = socket(res->ai_family, res->ai_socktype, res->ai_protocol); net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
setuid(getuid()); setuid(getuid());
if (net < 0) { if (net < 0) {
#ifdef INET6
if (family == AF_UNSPEC && af_error == 0 &&
switch_af(&res) == 1) {
af_error = 1;
goto af_again;
}
#endif
perror("telnet: socket"); perror("telnet: socket");
return 0; goto fail;
} }
if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0) if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
perror("setsockopt (source route)"); perror("setsockopt (source route)");
@ -2528,40 +2570,60 @@ tn(argc, argv)
} }
if (src_addr != NULL) { if (src_addr != NULL) {
if (bind(net, (struct sockaddr *)&src_ss, for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next)
((struct sockaddr *)&src_ss)->sa_len) == -1) { if (src_res->ai_family != res->ai_family)
continue;
if (src_res == NULL)
src_res = src_res0;
if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) {
#ifdef INET6
if (family == AF_UNSPEC && af_error == 0 &&
switch_af(&res) == 1) {
af_error = 1;
goto af_again;
}
#endif
perror("bind"); perror("bind");
return 0; goto fail;
} }
} }
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
if (setpolicy(net, res, ipsec_policy_in) < 0) if (setpolicy(net, res, ipsec_policy_in) < 0)
return 0; goto fail;
if (setpolicy(net, res, ipsec_policy_out) < 0) if (setpolicy(net, res, ipsec_policy_out) < 0)
return 0; goto fail;
#endif #endif
if (connect(net, res->ai_addr, res->ai_addrlen) < 0) { if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
if (res->ai_next) { struct addrinfo *next;
next = res->ai_next;
/* If already an af failed, only try same af. */
if (af_error != 0)
while (next != NULL && next->ai_family != res->ai_family)
next = next->ai_next;
if (next != NULL) {
int oerrno = errno; int oerrno = errno;
fprintf(stderr, "telnet: connect to address %s: ", fprintf(stderr, "telnet: connect to address %s: ",
sockaddr_ntop(res->ai_addr)); sockaddr_ntop(res->ai_addr));
errno = oerrno; errno = oerrno;
perror((char *)0); perror((char *)0);
res = res->ai_next; res = next;
(void) NetClose(net); (void) NetClose(net);
continue; continue;
} }
perror("telnet: Unable to connect to remote host"); perror("telnet: Unable to connect to remote host");
return 0; goto fail;
} }
connected++; connected++;
#if defined(AUTHENTICATION) || defined(ENCRYPTION) #if defined(AUTHENTICATION) || defined(ENCRYPTION)
auth_encrypt_connect(connected); auth_encrypt_connect(connected);
#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
} while (connected == 0); } while (connected == 0);
freeaddrinfo(res); freeaddrinfo(res0);
if (src_res0 != NULL)
freeaddrinfo(src_res0);
cmdrc(hostp, hostname); cmdrc(hostp, hostname);
if (autologin && user == NULL) { if (autologin && user == NULL) {
struct passwd *pw; struct passwd *pw;
@ -2585,6 +2647,12 @@ tn(argc, argv)
(void) NetClose(net); (void) NetClose(net);
ExitString("Connection closed by foreign host.\n",1); ExitString("Connection closed by foreign host.\n",1);
/*NOTREACHED*/ /*NOTREACHED*/
fail:
if (res0 != NULL)
freeaddrinfo(res0);
if (src_res0 != NULL)
freeaddrinfo(src_res0);
return 0;
} }
#define HELPINDENT (sizeof ("connect")) #define HELPINDENT (sizeof ("connect"))