[BACK]Return to sshconnect.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/sshconnect.c between version 1.294 and 1.295

version 1.294, 2018/02/10 09:25:35 version 1.295, 2018/02/23 02:34:33
Line 19 
Line 19 
 #include <sys/socket.h>  #include <sys/socket.h>
 #include <sys/time.h>  #include <sys/time.h>
   
   #include <net/if.h>
 #include <netinet/in.h>  #include <netinet/in.h>
   
 #include <ctype.h>  #include <ctype.h>
Line 33 
Line 34 
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
   #include <ifaddrs.h>
   
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "ssh.h"  #include "ssh.h"
Line 259 
Line 261 
 }  }
   
 /*  /*
    * Search a interface address list (returned from getifaddrs(3)) for an
    * address that matches the desired address family on the specifed interface.
    * Returns 0 and fills in *resultp and *rlenp on success. Returns -1 on failure.
    */
   static int
   check_ifaddrs(const char *ifname, int af, const struct ifaddrs *ifaddrs,
       struct sockaddr_storage *resultp, socklen_t *rlenp)
   {
           struct sockaddr_in6 *sa6;
           struct sockaddr_in *sa;
           struct in6_addr *v6addr;
           const struct ifaddrs *ifa;
           int allow_local;
   
           /*
            * Prefer addresses that are not loopback or linklocal, but use them
            * if nothing else matches.
            */
           for (allow_local = 0; allow_local < 2; allow_local++) {
                   for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
                           if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL ||
                               (ifa->ifa_flags & IFF_UP) == 0 ||
                               ifa->ifa_addr->sa_family != af ||
                               strcmp(ifa->ifa_name, options.bind_interface) != 0)
                                   continue;
                           switch (ifa->ifa_addr->sa_family) {
                           case AF_INET:
                                   sa = (struct sockaddr_in *)ifa->ifa_addr;
                                   if (!allow_local && sa->sin_addr.s_addr ==
                                       htonl(INADDR_LOOPBACK))
                                           continue;
                                   if (*rlenp < sizeof(struct sockaddr_in)) {
                                           error("%s: v4 addr doesn't fit",
                                               __func__);
                                           return -1;
                                   }
                                   *rlenp = sizeof(struct sockaddr_in);
                                   memcpy(resultp, sa, *rlenp);
                                   return 0;
                           case AF_INET6:
                                   sa6 = (struct sockaddr_in6 *)ifa->ifa_addr;
                                   v6addr = &sa6->sin6_addr;
                                   if (!allow_local &&
                                       (IN6_IS_ADDR_LINKLOCAL(v6addr) ||
                                       IN6_IS_ADDR_LOOPBACK(v6addr)))
                                           continue;
                                   if (*rlenp < sizeof(struct sockaddr_in6)) {
                                           error("%s: v6 addr doesn't fit",
                                               __func__);
                                           return -1;
                                   }
                                   *rlenp = sizeof(struct sockaddr_in6);
                                   memcpy(resultp, sa6, *rlenp);
                                   return 0;
                           }
                   }
           }
           return -1;
   }
   
   /*
  * Creates a (possibly privileged) socket for use as the ssh connection.   * Creates a (possibly privileged) socket for use as the ssh connection.
  */   */
 static int  static int
 ssh_create_socket(int privileged, struct addrinfo *ai)  ssh_create_socket(int privileged, struct addrinfo *ai)
 {  {
         int sock, r, gaierr;          int sock, r, oerrno;
           struct sockaddr_storage bindaddr;
           socklen_t bindaddrlen = 0;
         struct addrinfo hints, *res = NULL;          struct addrinfo hints, *res = NULL;
           struct ifaddrs *ifaddrs = NULL;
           char ntop[NI_MAXHOST];
   
         sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);          sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
         if (sock < 0) {          if (sock < 0) {
Line 275 
Line 342 
         fcntl(sock, F_SETFD, FD_CLOEXEC);          fcntl(sock, F_SETFD, FD_CLOEXEC);
   
         /* Bind the socket to an alternative local IP address */          /* Bind the socket to an alternative local IP address */
         if (options.bind_address == NULL && !privileged)          if (options.bind_address == NULL && options.bind_interface == NULL &&
               !privileged)
                 return sock;                  return sock;
   
         if (options.bind_address) {          if (options.bind_address != NULL) {
                 memset(&hints, 0, sizeof(hints));                  memset(&hints, 0, sizeof(hints));
                 hints.ai_family = ai->ai_family;                  hints.ai_family = ai->ai_family;
                 hints.ai_socktype = ai->ai_socktype;                  hints.ai_socktype = ai->ai_socktype;
                 hints.ai_protocol = ai->ai_protocol;                  hints.ai_protocol = ai->ai_protocol;
                 hints.ai_flags = AI_PASSIVE;                  hints.ai_flags = AI_PASSIVE;
                 gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res);                  if ((r = getaddrinfo(options.bind_address, NULL,
                 if (gaierr) {                      &hints, &res)) != 0) {
                         error("getaddrinfo: %s: %s", options.bind_address,                          error("getaddrinfo: %s: %s", options.bind_address,
                             ssh_gai_strerror(gaierr));                              ssh_gai_strerror(r));
                         close(sock);                          goto fail;
                         return -1;  
                 }                  }
                   if (res == NULL)
                           error("getaddrinfo: no addrs");
                           goto fail;
                   if (res->ai_addrlen > sizeof(bindaddr)) {
                           error("%s: addr doesn't fit", __func__);
                           goto fail;
                   }
                   memcpy(&bindaddr, res->ai_addr, res->ai_addrlen);
                   bindaddrlen = res->ai_addrlen;
           } else if (options.bind_interface != NULL) {
                   if ((r = getifaddrs(&ifaddrs)) != 0) {
                           error("getifaddrs: %s: %s", options.bind_interface,
                                 strerror(errno));
                           goto fail;
                   }
                   bindaddrlen = sizeof(bindaddr);
                   if (check_ifaddrs(options.bind_interface, ai->ai_family,
                       ifaddrs, &bindaddr, &bindaddrlen) != 0) {
                           logit("getifaddrs: %s: no suitable addresses",
                                 options.bind_interface);
                           goto fail;
                   }
         }          }
           if ((r = getnameinfo((struct sockaddr *)&bindaddr, bindaddrlen,
               ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST)) != 0) {
                   error("%s: getnameinfo failed: %s", __func__,
                       ssh_gai_strerror(r));
                   goto fail;
           }
         /*          /*
          * If we are running as root and want to connect to a privileged           * If we are running as root and want to connect to a privileged
          * port, bind our own socket to a privileged port.           * port, bind our own socket to a privileged port.
          */           */
         if (privileged) {          if (privileged) {
                 PRIV_START;                  PRIV_START;
                 r = bindresvport_sa(sock, res ? res->ai_addr : NULL);                  r = bindresvport_sa(sock,
                           bindaddrlen == 0 ? NULL : (struct sockaddr *)&bindaddr);
                   oerrno = errno;
                 PRIV_END;                  PRIV_END;
                 if (r < 0) {                  if (r < 0) {
                         error("bindresvport_sa: af=%d %s", ai->ai_family,                          error("bindresvport_sa %s: %s", ntop,
                             strerror(errno));                              strerror(oerrno));
                         goto fail;                          goto fail;
                 }                  }
         } else {          } else if (bind(sock, (struct sockaddr *)&bindaddr, bindaddrlen) != 0) {
                 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {                  error("bind %s: %s", ntop, strerror(errno));
                         error("bind: %s: %s", options.bind_address,                  goto fail;
                             strerror(errno));  
  fail:  
                         close(sock);  
                         freeaddrinfo(res);  
                         return -1;  
                 }  
         }          }
           debug("%s: bound to %s", __func__, ntop);
           /* success */
           goto out;
   fail:
           close(sock);
           sock = -1;
    out:
         if (res != NULL)          if (res != NULL)
                 freeaddrinfo(res);                  freeaddrinfo(res);
           if (ifaddrs != NULL)
                   freeifaddrs(ifaddrs);
         return sock;          return sock;
 }  }
   

Legend:
Removed from v.1.294  
changed lines
  Added in v.1.295