b734a81d1c
Submitted by: Arjan.deVet@adv.iae.nl (Arjan de Vet) - do not exit in failure to connect using IPv6 and try to IPv4 when connecting to dualstack hosts. Approved by: torstenb
409 lines
13 KiB
Plaintext
409 lines
13 KiB
Plaintext
*** sshconnect.c.orig Wed May 12 20:19:29 1999
|
|
--- sshconnect.c Thu Feb 24 22:34:47 2000
|
|
***************
|
|
*** 337,343 ****
|
|
|
|
/* Creates a (possibly privileged) socket for use as the ssh connection. */
|
|
|
|
! int ssh_create_socket(uid_t original_real_uid, int privileged)
|
|
{
|
|
int sock;
|
|
|
|
--- 337,343 ----
|
|
|
|
/* Creates a (possibly privileged) socket for use as the ssh connection. */
|
|
|
|
! int ssh_create_socket(uid_t original_real_uid, int privileged, int family)
|
|
{
|
|
int sock;
|
|
|
|
***************
|
|
*** 345,379 ****
|
|
bind our own socket to a privileged port. */
|
|
if (privileged)
|
|
{
|
|
! struct sockaddr_in sin;
|
|
int p;
|
|
for (p = 1023; p > 512; p--)
|
|
{
|
|
! sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sock < 0)
|
|
! fatal("socket: %.100s", strerror(errno));
|
|
|
|
! /* Initialize the desired sockaddr_in structure. */
|
|
! memset(&sin, 0, sizeof(sin));
|
|
! sin.sin_family = AF_INET;
|
|
! sin.sin_addr.s_addr = INADDR_ANY;
|
|
! sin.sin_port = htons(p);
|
|
|
|
/* Try to bind the socket to the privileged port. */
|
|
#if defined(SOCKS)
|
|
! if (Rbind(sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
|
|
break; /* Success. */
|
|
#else /* SOCKS */
|
|
! if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
|
|
break; /* Success. */
|
|
#endif /* SOCKS */
|
|
if (errno == EADDRINUSE)
|
|
{
|
|
close(sock);
|
|
continue;
|
|
}
|
|
! fatal("bind: %.100s", strerror(errno));
|
|
}
|
|
debug("Allocated local port %d.", p);
|
|
}
|
|
else
|
|
--- 345,404 ----
|
|
bind our own socket to a privileged port. */
|
|
if (privileged)
|
|
{
|
|
! struct addrinfo hints, *ai = NULL;
|
|
! int errgai;
|
|
! char strport[PORTSTRLEN];
|
|
int p;
|
|
+ #if (defined(__OpenBSD__) || defined(__FreeBSD__)) && !defined(SOCKS)
|
|
+ p = 1023; /* Compat with old FreeBSD */
|
|
+ #if __FreeBSD__ >= 400014
|
|
+ sock = rresvport_af(&p, family);
|
|
+ if (sock < 0)
|
|
+ error("rresvport_af: %.100s", strerror(errno));
|
|
+ #else
|
|
+ sock = rresvport(&p);
|
|
+ if (sock < 0)
|
|
+ error("rresvport: %.100s", strerror(errno));
|
|
+ #endif
|
|
+ #else
|
|
for (p = 1023; p > 512; p--)
|
|
{
|
|
! sock = socket(family, SOCK_STREAM, 0);
|
|
if (sock < 0)
|
|
! error("socket: %.100s", strerror(errno));
|
|
|
|
! /* Initialize the desired addrinfo structure. */
|
|
! memset(&hints, 0, sizeof(hints));
|
|
! hints.ai_family = family;
|
|
! hints.ai_flags = AI_PASSIVE;
|
|
! hints.ai_socktype = SOCK_STREAM;
|
|
! sprintf(strport, "%d", p);
|
|
! #if defined(SOCKS)
|
|
! if ((errgai = Rgetaddrinfo(NULL, strport, &hints, &ai)) != 0)
|
|
! fatal("getaddrinfo: %.100s", gai_strerror(errgai));
|
|
! #else /* SOCKS */
|
|
! if ((errgai = getaddrinfo(NULL, strport, &hints, &ai)) != 0)
|
|
! fatal("getaddrinfo: %.100s", gai_strerror(errgai));
|
|
! #endif /* SOCKS */
|
|
|
|
/* Try to bind the socket to the privileged port. */
|
|
#if defined(SOCKS)
|
|
! if (Rbind(sock, ai->ai_addr, ai->ai_addrlen) >= 0)
|
|
break; /* Success. */
|
|
#else /* SOCKS */
|
|
! if (bind(sock, ai->ai_addr, ai->ai_addrlen) >= 0)
|
|
break; /* Success. */
|
|
#endif /* SOCKS */
|
|
if (errno == EADDRINUSE)
|
|
{
|
|
close(sock);
|
|
+ freeaddrinfo(ai);
|
|
continue;
|
|
}
|
|
! error("bind: %.100s", strerror(errno));
|
|
}
|
|
+ freeaddrinfo(ai);
|
|
+ #endif
|
|
debug("Allocated local port %d.", p);
|
|
}
|
|
else
|
|
***************
|
|
*** 396,409 ****
|
|
the daemon. */
|
|
|
|
int ssh_connect(const char *host, int port, int connection_attempts,
|
|
int anonymous, uid_t original_real_uid,
|
|
const char *proxy_command, RandomState *random_state)
|
|
{
|
|
int sock = -1, attempt, i;
|
|
int on = 1;
|
|
struct servent *sp;
|
|
! struct hostent *hp;
|
|
! struct sockaddr_in hostaddr;
|
|
#if defined(SO_LINGER) && defined(ENABLE_SO_LINGER)
|
|
struct linger linger;
|
|
#endif /* SO_LINGER */
|
|
--- 421,439 ----
|
|
the daemon. */
|
|
|
|
int ssh_connect(const char *host, int port, int connection_attempts,
|
|
+ #ifdef ENABLE_ANOTHER_PORT_TRY
|
|
+ int another_port,
|
|
+ #endif /* ENABLE_ANOTHER_PORT_TRY */
|
|
int anonymous, uid_t original_real_uid,
|
|
const char *proxy_command, RandomState *random_state)
|
|
{
|
|
int sock = -1, attempt, i;
|
|
int on = 1;
|
|
struct servent *sp;
|
|
! struct addrinfo hints, *ai, *aitop, *aitmp;
|
|
! struct sockaddr_storage hostaddr;
|
|
! char ntop[ADDRSTRLEN], strport[PORTSTRLEN];
|
|
! int gaierr;
|
|
#if defined(SO_LINGER) && defined(ENABLE_SO_LINGER)
|
|
struct linger linger;
|
|
#endif /* SO_LINGER */
|
|
***************
|
|
*** 421,430 ****
|
|
port = SSH_DEFAULT_PORT;
|
|
}
|
|
|
|
- /* Map localhost to ip-address locally */
|
|
- if (strcmp(host, "localhost") == 0)
|
|
- host = "127.0.0.1";
|
|
-
|
|
/* If a proxy command is given, connect using it. */
|
|
if (proxy_command != NULL && *proxy_command)
|
|
return ssh_proxy_connect(host, port, original_real_uid, proxy_command,
|
|
--- 451,456 ----
|
|
***************
|
|
*** 432,440 ****
|
|
|
|
/* No proxy command. */
|
|
|
|
! /* No host lookup made yet. */
|
|
! hp = NULL;
|
|
!
|
|
/* Try to connect several times. On some machines, the first time will
|
|
sometimes fail. In general socket code appears to behave quite
|
|
magically on many machines. */
|
|
--- 458,495 ----
|
|
|
|
/* No proxy command. */
|
|
|
|
! memset(&hints, 0, sizeof(hints));
|
|
! hints.ai_family = IPv4or6;
|
|
! hints.ai_socktype = SOCK_STREAM;
|
|
! sprintf(strport, "%d", port);
|
|
! #if defined(SOCKS)
|
|
! if ((gaierr = Rgetaddrinfo(host, strport, &hints, &aitop)) != 0)
|
|
! fatal("Bad host name: %.100s (%s)", host, gai_strerror(gaierr));
|
|
! #else /* SOCKS */
|
|
! if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
|
|
! fatal("Bad host name: %.100s (%s)", host, gai_strerror(gaierr));
|
|
! #endif /* SOCKS */
|
|
!
|
|
! #ifdef ENABLE_ANOTHER_PORT_TRY
|
|
! if (another_port)
|
|
! {
|
|
! aitmp = aitop;
|
|
! memset(&hints, 0, sizeof(hints));
|
|
! hints.ai_family = IPv4or6;
|
|
! hints.ai_socktype = SOCK_STREAM;
|
|
! sprintf(strport, "%d", another_port);
|
|
! #if defined(SOCKS)
|
|
! if ((gaierr = Rgetaddrinfo(host, strport, &hints, &aitop)) != 0)
|
|
! fatal("Bad host name: %.100s (%s)", host, gai_strerror(gaierr));
|
|
! #else /* SOCKS */
|
|
! if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
|
|
! fatal("Bad host name: %.100s (%s)", host, gai_strerror(gaierr));
|
|
! #endif /* SOCKS */
|
|
! for (ai = aitop; ai->ai_next; ai = ai->ai_next);
|
|
! ai->ai_next = aitmp;
|
|
! }
|
|
! #endif /* ENABLE_ANOTHER_PORT_TRY */
|
|
!
|
|
/* Try to connect several times. On some machines, the first time will
|
|
sometimes fail. In general socket code appears to behave quite
|
|
magically on many machines. */
|
|
***************
|
|
*** 443,545 ****
|
|
if (attempt > 0)
|
|
debug("Trying again...");
|
|
|
|
- /* Try to parse the host name as a numeric inet address. */
|
|
- memset(&hostaddr, 0, sizeof(hostaddr));
|
|
- hostaddr.sin_family = AF_INET;
|
|
- hostaddr.sin_port = htons(port);
|
|
- #ifdef BROKEN_INET_ADDR
|
|
- hostaddr.sin_addr.s_addr = inet_network(host);
|
|
- #else /* BROKEN_INET_ADDR */
|
|
- hostaddr.sin_addr.s_addr = inet_addr(host);
|
|
- #endif /* BROKEN_INET_ADDR */
|
|
- if ((hostaddr.sin_addr.s_addr & 0xffffffff) != 0xffffffff)
|
|
- {
|
|
- /* Create a socket. */
|
|
- sock = ssh_create_socket(original_real_uid,
|
|
- !anonymous && geteuid() == UID_ROOT);
|
|
-
|
|
- /* Valid numeric IP address */
|
|
- debug("Connecting to %.100s port %d.",
|
|
- inet_ntoa(hostaddr.sin_addr), port);
|
|
-
|
|
- /* Connect to the host. */
|
|
- #if defined(SOCKS)
|
|
- if (Rconnect(sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr))
|
|
- #else /* SOCKS */
|
|
- if (connect(sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr))
|
|
- #endif /* SOCKS */
|
|
- >= 0)
|
|
- {
|
|
- /* Successful connect. */
|
|
- break;
|
|
- }
|
|
- debug("connect: %.100s", strerror(errno));
|
|
-
|
|
- /* Destroy the failed socket. */
|
|
- shutdown(sock, 2);
|
|
- close(sock);
|
|
- }
|
|
- else
|
|
- {
|
|
- /* Not a valid numeric inet address. */
|
|
- /* Map host name to an address. */
|
|
- if (!hp)
|
|
- {
|
|
- struct hostent *hp_static;
|
|
-
|
|
- #if defined(SOCKS5)
|
|
- hp_static = Rgethostbyname(host);
|
|
- #else
|
|
- hp_static = gethostbyname(host);
|
|
- #endif
|
|
- if (hp_static)
|
|
- {
|
|
- hp = xmalloc(sizeof(struct hostent));
|
|
- memcpy(hp, hp_static, sizeof(struct hostent));
|
|
-
|
|
- /* Copy list of addresses, not just pointers.
|
|
- We don't use h_name & h_aliases so leave them as is */
|
|
- for (i = 0; hp_static->h_addr_list[i]; i++)
|
|
- ; /* count them */
|
|
- hp->h_addr_list = xmalloc((i + 1) *
|
|
- sizeof(hp_static->h_addr_list[0]));
|
|
- for (i = 0; hp_static->h_addr_list[i]; i++)
|
|
- {
|
|
- hp->h_addr_list[i] = xmalloc(hp->h_length);
|
|
- memcpy(hp->h_addr_list[i], hp_static->h_addr_list[i],
|
|
- hp->h_length);
|
|
- }
|
|
- hp->h_addr_list[i] = NULL; /* last one */
|
|
- }
|
|
- }
|
|
- if (!hp)
|
|
- fatal("Bad host name: %.100s", host);
|
|
- if (!hp->h_addr_list[0])
|
|
- fatal("Host does not have an IP address: %.100s", host);
|
|
-
|
|
/* Loop through addresses for this host, and try each one in
|
|
sequence until the connection succeeds. */
|
|
! for (i = 0; hp->h_addr_list[i]; i++)
|
|
{
|
|
! /* Set the address to connect to. */
|
|
! hostaddr.sin_family = hp->h_addrtype;
|
|
! memcpy(&hostaddr.sin_addr, hp->h_addr_list[i],
|
|
! sizeof(hostaddr.sin_addr));
|
|
|
|
! debug("Connecting to %.200s [%.100s] port %d.",
|
|
! host, inet_ntoa(hostaddr.sin_addr), port);
|
|
|
|
/* Create a socket for connecting. */
|
|
sock = ssh_create_socket(original_real_uid,
|
|
! !anonymous && geteuid() == UID_ROOT);
|
|
|
|
/* Connect to the host. */
|
|
#if defined(SOCKS)
|
|
! if (Rconnect(sock, (struct sockaddr *)&hostaddr,
|
|
! sizeof(hostaddr)) >= 0)
|
|
#else /* SOCKS */
|
|
! if (connect(sock, (struct sockaddr *)&hostaddr,
|
|
! sizeof(hostaddr)) >= 0)
|
|
#endif /* SOCKS */
|
|
{
|
|
/* Successful connection. */
|
|
--- 498,526 ----
|
|
if (attempt > 0)
|
|
debug("Trying again...");
|
|
|
|
/* Loop through addresses for this host, and try each one in
|
|
sequence until the connection succeeds. */
|
|
! for (ai = aitop; ai; ai = ai->ai_next)
|
|
{
|
|
! getnameinfo(ai->ai_addr, ai->ai_addrlen,
|
|
! ntop, sizeof(ntop), strport, sizeof(strport),
|
|
! NI_NUMERICHOST|NI_NUMERICSERV);
|
|
|
|
! debug("Connecting to %.200s [%.100s] port %s.",
|
|
! host, ntop, strport);
|
|
|
|
/* Create a socket for connecting. */
|
|
sock = ssh_create_socket(original_real_uid,
|
|
! !anonymous && geteuid() == UID_ROOT,
|
|
! ai->ai_family);
|
|
! if (sock < 0)
|
|
! continue;
|
|
|
|
/* Connect to the host. */
|
|
#if defined(SOCKS)
|
|
! if (Rconnect(sock, ai->ai_addr, ai->ai_addrlen) >= 0)
|
|
#else /* SOCKS */
|
|
! if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0)
|
|
#endif /* SOCKS */
|
|
{
|
|
/* Successful connection. */
|
|
***************
|
|
*** 552,573 ****
|
|
returned an error. */
|
|
shutdown(sock, 2);
|
|
close(sock);
|
|
! }
|
|
! if (hp->h_addr_list[i])
|
|
break; /* Successful connection. */
|
|
- }
|
|
|
|
/* Sleep a moment before retrying. */
|
|
sleep(1);
|
|
}
|
|
|
|
! if (hp)
|
|
! {
|
|
! for (i = 0; hp->h_addr_list[i]; i++)
|
|
! xfree(hp->h_addr_list[i]);
|
|
! xfree(hp->h_addr_list);
|
|
! xfree(hp);
|
|
! }
|
|
|
|
/* Return failure if we didn't get a successful connection. */
|
|
if (attempt >= connection_attempts)
|
|
--- 533,547 ----
|
|
returned an error. */
|
|
shutdown(sock, 2);
|
|
close(sock);
|
|
! } /* for (ai = aitop; ai; ai = ai->ai_next) */
|
|
! if (ai)
|
|
break; /* Successful connection. */
|
|
|
|
/* Sleep a moment before retrying. */
|
|
sleep(1);
|
|
}
|
|
|
|
! freeaddrinfo(aitop);
|
|
|
|
/* Return failure if we didn't get a successful connection. */
|
|
if (attempt >= connection_attempts)
|
|
***************
|
|
*** 946,952 ****
|
|
int ap_opts, ret_stat = 0;
|
|
krb5_keyblock *session_key = 0;
|
|
krb5_ap_rep_enc_part *repl = 0;
|
|
! struct sockaddr_in local, foreign;
|
|
|
|
memset(&auth, 0 , sizeof(auth));
|
|
remotehost = (char *) get_canonical_hostname();
|
|
--- 920,926 ----
|
|
int ap_opts, ret_stat = 0;
|
|
krb5_keyblock *session_key = 0;
|
|
krb5_ap_rep_enc_part *repl = 0;
|
|
! struct sockaddr_storage local, foreign;
|
|
|
|
memset(&auth, 0 , sizeof(auth));
|
|
remotehost = (char *) get_canonical_hostname();
|