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

Diff for /src/usr.bin/nc/socks.c between version 1.13 and 1.14

version 1.13, 2005/05/20 11:06:58 version 1.14, 2005/05/20 22:46:08
Line 2 
Line 2 
   
 /*  /*
  * Copyright (c) 1999 Niklas Hallqvist.  All rights reserved.   * Copyright (c) 1999 Niklas Hallqvist.  All rights reserved.
    * Copyright (c) 2004, 2005 Damien Miller.  All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 46 
Line 47 
 #define SOCKS_NOMETHOD  0xff  #define SOCKS_NOMETHOD  0xff
 #define SOCKS_CONNECT   1  #define SOCKS_CONNECT   1
 #define SOCKS_IPV4      1  #define SOCKS_IPV4      1
   #define SOCKS_DOMAIN    3
   #define SOCKS_IPV6      4
   
   ssize_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
 int     remote_connect(const char *, const char *, struct addrinfo);  int     remote_connect(const char *, const char *, struct addrinfo);
 int     socks_connect(const char *host, const char *port, struct addrinfo hints,  int     socks_connect(const char *host, const char *port, struct addrinfo hints,
             const char *proxyhost, const char *proxyport, struct addrinfo proxyhints,              const char *proxyhost, const char *proxyport, struct addrinfo proxyhints,
             int socksv);              int socksv);
   
 static in_addr_t  static int
 decode_addr(const char *s)  decode_addrport(const char *h, const char *p, struct sockaddr *addr,
       socklen_t addrlen, int v4only, int numeric)
 {  {
         struct hostent *hp = gethostbyname(s);          int r;
         struct in_addr retval;          struct addrinfo hints, *res;
   
         if (hp)          bzero(&hints, sizeof(hints));
                 return (*(in_addr_t *)hp->h_addr_list[0]);          hints.ai_family = v4only ? PF_INET : PF_UNSPEC;
         if (inet_aton(s, &retval))          hints.ai_flags = numeric ? AI_NUMERICHOST : 0;
                 return (retval.s_addr);          hints.ai_socktype = SOCK_STREAM;
         errx(1, "cannot decode address \"%s\"", s);          r = getaddrinfo(h, p, &hints, &res);
 }          /* Don't fatal when attempting to convert a numeric address */
           if (r != 0) {
 static in_port_t                  if (!numeric) {
 decode_port(const char *s)                          errx(1, "getaddrinfo(\"%.64s\", \"%.64s\"): %s", h, p,
 {                              gai_strerror(r));
         struct servent *sp;                  }
         in_port_t port;                  return (-1);
         char *p;  
   
         port = strtol(s, &p, 10);  
         if (s == p) {  
                 sp = getservbyname(s, "tcp");  
                 if (sp)  
                         return (sp->s_port);  
         }          }
         if (*s != '\0' && *p == '\0')          if (addrlen < res->ai_addrlen) {
                 return (htons(port));                  freeaddrinfo(res);
         errx (1, "cannot decode port \"%s\"", s);                  errx(1, "internal error: addrlen < res->ai_addrlen");
           }
           memcpy(addr, res->ai_addr, res->ai_addrlen);
           freeaddrinfo(res);
           return (0);
 }  }
   
 static int  static int
Line 116 
Line 117 
     int socksv)      int socksv)
 {  {
         int proxyfd, r;          int proxyfd, r;
           size_t hlen, wlen;
         unsigned char buf[1024];          unsigned char buf[1024];
         ssize_t cnt;          ssize_t cnt;
         in_addr_t serveraddr;          struct sockaddr_storage addr;
           struct sockaddr_in *in4 = (struct sockaddr_in *)&addr;
           struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr;
         in_port_t serverport;          in_port_t serverport;
   
         if (proxyport == NULL)          if (proxyport == NULL)
Line 129 
Line 133 
         if (proxyfd < 0)          if (proxyfd < 0)
                 return (-1);                  return (-1);
   
         /* HTTP proxies should use hostnames. (XXX so can SOCKS5) */          /* Abuse API to lookup port */
         if (socksv != -1)          if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr,
                 serveraddr = decode_addr(host);              sizeof(addr), 1, 1) == -1)
         serverport = decode_port(port);                  errx(1, "unknown port \"%.64s\"", port);
           serverport = in4->sin_port;
   
         if (socksv == 5) {          if (socksv == 5) {
                   if (decode_addrport(host, port, (struct sockaddr *)&addr,
                       sizeof(addr), 0, 1) == -1)
                           addr.ss_family = 0; /* used in switch below */
   
                 /* Version 5, one method: no authentication */                  /* Version 5, one method: no authentication */
                 buf[0] = SOCKS_V5;                  buf[0] = SOCKS_V5;
                 buf[1] = 1;                  buf[1] = 1;
Line 149 
Line 158 
                 if (buf[1] == SOCKS_NOMETHOD)                  if (buf[1] == SOCKS_NOMETHOD)
                         errx(1, "authentication method negotiation failed");                          errx(1, "authentication method negotiation failed");
   
                 /* Version 5, connect: IPv4 address */                  switch (addr.ss_family) {
                 buf[0] = SOCKS_V5;                  case 0:
                 buf[1] = SOCKS_CONNECT;                          /* Version 5, connect: domain name */
                 buf[2] = 0;  
                 buf[3] = SOCKS_IPV4;  
                 memcpy(buf + 4, &serveraddr, sizeof serveraddr);  
                 memcpy(buf + 8, &serverport, sizeof serverport);  
   
                 /* XXX Handle short writes better */                          /* Max domain name length is 255 bytes */
                 cnt = write(proxyfd, buf, 10);                          hlen = strlen(host);
                           if (hlen > 255)
                                   errx(1, "host name too long for SOCKS5");
                           buf[0] = SOCKS_V5;
                           buf[1] = SOCKS_CONNECT;
                           buf[2] = 0;
                           buf[3] = SOCKS_DOMAIN;
                           buf[4] = hlen;
                           memcpy(buf + 5, host, hlen);
                           memcpy(buf + 5 + hlen, &serverport, sizeof serverport);
                           wlen = 7 + hlen;
                           break;
                   case AF_INET:
                           /* Version 5, connect: IPv4 address */
                           buf[0] = SOCKS_V5;
                           buf[1] = SOCKS_CONNECT;
                           buf[2] = 0;
                           buf[3] = SOCKS_IPV4;
                           memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
                           memcpy(buf + 8, &in4->sin_port, sizeof in4->sin_port);
                           wlen = 10;
                           break;
                   case AF_INET6:
                           /* Version 5, connect: IPv6 address */
                           buf[0] = SOCKS_V5;
                           buf[1] = SOCKS_CONNECT;
                           buf[2] = 0;
                           buf[3] = SOCKS_IPV6;
                           memcpy(buf + 4, &in6->sin6_addr, sizeof in6->sin6_addr);
                           memcpy(buf + 20, &in6->sin6_port,
                               sizeof in6->sin6_port);
                           wlen = 22;
                           break;
                   default:
                           errx(1, "internal error: silly AF");
                   }
   
                   cnt = atomicio((ssize_t (*)(int, void *, size_t))write,
                       proxyfd, buf, wlen);
                 if (cnt == -1)                  if (cnt == -1)
                         err(1, "write failed");                          err(1, "write failed");
                 if (cnt != 10)                  if (cnt != wlen)
                         errx(1, "short write, %d (expected 10)", cnt);                          errx(1, "short write, %d (expected %d)", cnt, wlen);
   
                 /* XXX Handle short reads better */                  cnt = atomicio(read, proxyfd, buf, 10);
                 cnt = read(proxyfd, buf, 10);  
                 if (cnt == -1)                  if (cnt == -1)
                         err(1, "read failed");                          err(1, "read failed");
                 if (cnt != 10)                  if (cnt != 10)
Line 173 
Line 215 
                 if (buf[1] != 0)                  if (buf[1] != 0)
                         errx(1, "connection failed, SOCKS error %d", buf[1]);                          errx(1, "connection failed, SOCKS error %d", buf[1]);
         } else if (socksv == 4) {          } else if (socksv == 4) {
                   /* This will exit on lookup failure */
                   decode_addrport(host, port, (struct sockaddr *)&addr,
                       sizeof(addr), 1, 0);
   
                 /* Version 4 */                  /* Version 4 */
                 buf[0] = SOCKS_V4;                  buf[0] = SOCKS_V4;
                 buf[1] = SOCKS_CONNECT; /* connect */                  buf[1] = SOCKS_CONNECT; /* connect */
                 memcpy(buf + 2, &serverport, sizeof serverport);                  memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port);
                 memcpy(buf + 4, &serveraddr, sizeof serveraddr);                  memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
                 buf[8] = 0;     /* empty username */                  buf[8] = 0;     /* empty username */
                   wlen = 9;
   
                 cnt = write(proxyfd, buf, 9);                  cnt = write(proxyfd, buf, wlen);
                 if (cnt == -1)                  if (cnt == -1)
                         err(1, "write failed");                          err(1, "write failed");
                 if (cnt != 9)                  if (cnt != wlen)
                         errx(1, "short write, %d (expected 9)", cnt);                          errx(1, "short write, %d (expected %d)", cnt, wlen);
   
                 /* XXX Handle short reads better */                  cnt = atomicio(read, proxyfd, buf, 8);
                 cnt = read(proxyfd, buf, 8);  
                 if (cnt == -1)                  if (cnt == -1)
                         err(1, "read failed");                          err(1, "read failed");
                 if (cnt != 8)                  if (cnt != 8)
Line 215 
Line 261 
                         errx(1, "hostname too long");                          errx(1, "hostname too long");
                 r = strlen(buf);                  r = strlen(buf);
   
                 /* XXX atomicio */                  cnt = atomicio((ssize_t (*)(int, void *, size_t))write,
                 cnt = write(proxyfd, buf, r);                      proxyfd, buf, r);
                 if (cnt == -1)                  if (cnt == -1)
                         err(1, "write failed");                          err(1, "write failed");
                 if (cnt != r)                  if (cnt != r)

Legend:
Removed from v.1.13  
changed lines
  Added in v.1.14