mirror of
https://github.com/sheumann/telnetd.git
synced 2024-11-29 16:50:58 +00:00
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:
parent
92a0e6dadf
commit
d2ec198a69
@ -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"))
|
||||||
|
Loading…
Reference in New Issue
Block a user