[or-cvs] r8451: Specify and implement SOCKS5 interface for reverse hostname (in tor/trunk: . contrib doc src/or)

nickm at seul.org nickm at seul.org
Fri Sep 22 00:44:02 UTC 2006


Author: nickm
Date: 2006-09-21 20:43:55 -0400 (Thu, 21 Sep 2006)
New Revision: 8451

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/contrib/tor-resolve.py
   tor/trunk/doc/TODO
   tor/trunk/doc/socks-extensions.txt
   tor/trunk/src/or/buffers.c
   tor/trunk/src/or/connection_edge.c
   tor/trunk/src/or/or.h
Log:
 r8894 at Kushana:  nickm | 2006-09-21 18:30:42 -0400
 Specify and implement SOCKS5 interface for reverse hostname lookup.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/branches/eventdns [r8894] on c95137ef-5f19-0410-b913-86e773d04f59

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2006-09-22 00:24:27 UTC (rev 8450)
+++ tor/trunk/ChangeLog	2006-09-22 00:43:55 UTC (rev 8451)
@@ -6,6 +6,8 @@
       previously never implemented.  This is only supported by eventdns;
       servers now announce in their descriptors whether they support
       eventdns.
+    - Specify and implement client-side SOCKS5 interface for reverse DNS
+      lookups; see doc/socks-extensions.txt for full information.
 
   o Minor features:
     - Check for name servers (like Earthlink's) that hijack failing DNS

Modified: tor/trunk/contrib/tor-resolve.py
===================================================================
--- tor/trunk/contrib/tor-resolve.py	2006-09-22 00:24:27 UTC (rev 8450)
+++ tor/trunk/contrib/tor-resolve.py	2006-09-22 00:43:55 UTC (rev 8451)
@@ -32,15 +32,14 @@
 def socks5ParseHello(response):
     if response != "\x05\x00":
         raise ValueError("Bizarre socks5 response")
-def socks5ResolveRequest(hostname):
+def socks5ResolveRequest(hostname, atype=0x03, command=0xF0):
     version = 5
-    command = 0xF0
     rsv = 0
     port = 0
-    atype = 0x03
     reqheader = struct.pack("!BBBBB",version, command, rsv, atype, len(hostname))
     portstr = struct.pack("!H",port)
     return "%s%s%s"%(reqheader,hostname,portstr)
+
 def socks5ParseResponse(r):
     if len(r)<8:
         return None
@@ -49,19 +48,28 @@
     assert rsv==0
     if reply != 0x00:
         return "ERROR",reply
-    assert atype in (0x01,0x04)
-    expected_len = 4 + ({1:4,4:16}[atype]) + 2
-    if len(r) < expected_len:
-        return None
-    elif len(r) > expected_len:
-        raise ValueError("Overlong socks5 reply!")
-    addr = r[4:-2]
-    if atype == 0x01:
-        return "%d.%d.%d.%d"%tuple(map(ord,addr))
+    assert atype in (0x01,0x03,0x04)
+    if atype != 0x03:
+        expected_len = 4 + ({1:4,4:16}[atype]) + 2
+        if len(r) < expected_len:
+            return None
+        elif len(r) > expected_len:
+            raise ValueError("Overlong socks5 reply!")
+        addr = r[4:-2]
+        if atype == 0x01:
+            return "%d.%d.%d.%d"%tuple(map(ord,addr))
+        else:
+            # not really the right way to format IPv6
+            return "IPv6: %s"%(":".join([hex(ord(c)) for c in addr]))
     else:
-        # not really the right way to format IPv6
-        return "IPv6: %s"%(":".join([hex(ord(c)) for c in addr]))
+        nul = r.index('\0',4)
+        return r[4:nul]
 
+def socks5ResolvePTRRequest(hostname):
+    return socks5ResolveRequest(socket.inet_aton(hostname),
+                                atype=1, command = 0xF1)
+
+
 def parseHostAndPort(h):
     host, port = "localhost", 9050
     if ":" in h:
@@ -80,14 +88,18 @@
 
     return host, port
 
-def resolve(hostname, sockshost, socksport, socksver=4):
+def resolve(hostname, sockshost, socksport, socksver=4, reverse=0):
     assert socksver in (4,5)
     if socksver == 4:
         fmt = socks4AResolveRequest
         parse = socks4AParseResponse
-    else:
+    elif not reverse:
         fmt = socks5ResolveRequest
         parse = socks5ParseResponse
+    else:
+        fmt = socks5ResolvePTRRequest
+        parse = socks5ParseResponse
+
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     s.connect((sockshost,socksport))
     if socksver == 5:
@@ -114,14 +126,25 @@
         print "Syntax: resolve.py [-4|-5] hostname [sockshost:socksport]"
         sys.exit(0)
     socksver = 4
-    if sys.argv[1] in ("-4", "-5"):
-        socksver = int(sys.argv[1][1])
-        del sys.argv[1]
-    if len(sys.argv) == 4:
+    reverse = 0
+    while sys.argv[1] == '-':
+        if sys.argv[1] in ("-4", "-5"):
+            socksver = int(sys.argv[1][1])
+            del sys.argv[1]
+        elif sys.argv[1] == '-x':
+            reverse = 1
+            del sys.argv[1]
+        elif sys.argv[1] == '--':
+            break
+
+    if len(sys.argv) >= 4:
         print "Syntax: resolve.py [-4|-5] hostname [sockshost:socksport]"
         sys.exit(0)
     if len(sys.argv) == 3:
         sh,sp = parseHostAndPort(sys.argv[2])
     else:
         sh,sp = parseHostAndPort("")
-    resolve(sys.argv[1], sh, sp, socksver)
+
+    if reverse and socksver == 4:
+        socksver = 5
+    resolve(sys.argv[1], sh, sp, socksver, reverse)

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2006-09-22 00:24:27 UTC (rev 8450)
+++ tor/trunk/doc/TODO	2006-09-22 00:43:55 UTC (rev 8451)
@@ -109,7 +109,12 @@
       o Connect to resolve cells, server-side.
       o Add element to routerinfo to note routers that aren't using eventdns,
         so we can avoid sending them reverse DNS etc.
-      - Add client-side interface
+      . Add client-side interface
+        o SOCKS interface: specify
+        o SOCKS interface: implement
+        - Cache answers client-side
+        o Add to Tor-resolve.py
+        - Add to tor-resolve
 
   - Performance improvements
 

Modified: tor/trunk/doc/socks-extensions.txt
===================================================================
--- tor/trunk/doc/socks-extensions.txt	2006-09-22 00:24:27 UTC (rev 8450)
+++ tor/trunk/doc/socks-extensions.txt	2006-09-22 00:43:55 UTC (rev 8451)
@@ -46,6 +46,12 @@
 
   (We support RESOLVE in SOCKS4 too, even though it is unnecessary.)
 
+  For SOCKS5 only, we support reverse resolution with a new command value,
+  "RESOLVE_PTR".  In response to a "RESOLVE_PTR" SOCKS5 command with an IPv4
+  address as its target, Tor attempts to find the canonical hostname for that
+  IPv4 record, and returns it in the "server bound address" portion of the
+  reply.  (This was not supported before Tor 0.1.2.2-alpha)
+
 3. HTTP-resistance
 
   Tor checks the first byte of each SOCKS request to see whether it looks

Modified: tor/trunk/src/or/buffers.c
===================================================================
--- tor/trunk/src/or/buffers.c	2006-09-22 00:24:27 UTC (rev 8450)
+++ tor/trunk/src/or/buffers.c	2006-09-22 00:43:55 UTC (rev 8451)
@@ -974,8 +974,9 @@
         return 0; /* not yet */
       req->command = (unsigned char) *(buf->cur+1);
       if (req->command != SOCKS_COMMAND_CONNECT &&
-          req->command != SOCKS_COMMAND_RESOLVE) {
-        /* not a connect or resolve? we don't support it. */
+          req->command != SOCKS_COMMAND_RESOLVE &&
+          req->command != SOCKS_COMMAND_RESOLVE_PTR) {
+        /* not a connect or resolve or a resolve_ptr? we don't support it. */
         log_warn(LD_APP,"socks5: command %d not recognized. Rejecting.",
                  req->command);
         return -1;
@@ -999,7 +1000,8 @@
           strlcpy(req->address,tmpbuf,sizeof(req->address));
           req->port = ntohs(*(uint16_t*)(buf->cur+8));
           buf_remove_from_front(buf, 10);
-          if (!addressmap_have_mapping(req->address) &&
+          if (req->command != SOCKS_COMMAND_RESOLVE_PTR &&
+              !addressmap_have_mapping(req->address) &&
               !have_warned_about_unsafe_socks) {
             log_warn(LD_APP,
                 "Your application (using socks5 on port %d) is giving "
@@ -1025,6 +1027,11 @@
                      "%d. Rejecting.", len+1,MAX_SOCKS_ADDR_LEN);
             return -1;
           }
+          if (req->command == SOCKS_COMMAND_RESOLVE_PTR) {
+            log_warn(LD_APP, "socks5 received RESOLVE_PTR command with "
+                     "hostname type. Rejecting.");
+            return -1;
+          }
           memcpy(req->address,buf->cur+5,len);
           req->address[len] = 0;
           req->port = ntohs(get_uint16(buf->cur+5+len));
@@ -1059,7 +1066,8 @@
       req->command = (unsigned char) *(buf->cur+1);
       if (req->command != SOCKS_COMMAND_CONNECT &&
           req->command != SOCKS_COMMAND_RESOLVE) {
-        /* not a connect or resolve? we don't support it. */
+        /* not a connect or resolve? we don't support it. (No resolve_ptr with
+         * socks4.) */
         log_warn(LD_APP,"socks4: command %d not recognized. Rejecting.",
                  req->command);
         return -1;

Modified: tor/trunk/src/or/connection_edge.c
===================================================================
--- tor/trunk/src/or/connection_edge.c	2006-09-22 00:24:27 UTC (rev 8450)
+++ tor/trunk/src/or/connection_edge.c	2006-09-22 00:43:55 UTC (rev 8451)
@@ -1120,7 +1120,7 @@
       return -1;
     }
 
-    if (socks->command == SOCKS_COMMAND_RESOLVE) {
+    if (socks->command == SOCKS_COMMAND_RESOLVE) { // resolve_ptr XXXX NM
       uint32_t answer;
       struct in_addr in;
       /* Reply to resolves immediately if we can. */
@@ -1181,7 +1181,7 @@
     rend_cache_entry_t *entry;
     int r;
 
-    if (socks->command == SOCKS_COMMAND_RESOLVE) {
+    if (socks->command != SOCKS_COMMAND_CONNECT) {
       /* if it's a resolve request, fail it right now, rather than
        * building all the circuits and then realizing it won't work. */
       log_warn(LD_APP,
@@ -1524,13 +1524,17 @@
 connection_ap_handshake_send_resolve(edge_connection_t *ap_conn,
                                      origin_circuit_t *circ)
 {
-  int payload_len;
+  int payload_len, command;
   const char *string_addr;
+  char inaddr_buf[32];
 
+  command = ap_conn->socks_request->command;
+
   tor_assert(ap_conn->_base.type == CONN_TYPE_AP);
   tor_assert(ap_conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT);
   tor_assert(ap_conn->socks_request);
-  tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
+  tor_assert(command == SOCKS_COMMAND_RESOLVE ||
+             command == SOCKS_COMMAND_RESOLVE_PTR);
   tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL);
 
   ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
@@ -1540,9 +1544,27 @@
     return -1;
   }
 
-  string_addr = ap_conn->socks_request->address;
-  payload_len = strlen(string_addr)+1;
-  tor_assert(payload_len <= RELAY_PAYLOAD_SIZE);
+  if (command == SOCKS_COMMAND_RESOLVE) {
+    string_addr = ap_conn->socks_request->address;
+    payload_len = strlen(string_addr)+1;
+    tor_assert(payload_len <= RELAY_PAYLOAD_SIZE);
+  } else {
+    struct in_addr in;
+    uint32_t a;
+    if (tor_inet_aton(ap_conn->socks_request->address, &in) == 0) {
+      connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
+      return -1;
+    }
+    a = ntohl(in.s_addr);
+    tor_snprintf(inaddr_buf, sizeof(inaddr_buf), "%d.%d.%d.%d.in-addr.arpa",
+                 (int)(uint8_t)((a    )&0xff),
+                 (int)(uint8_t)((a>>8 )&0xff),
+                 (int)(uint8_t)((a>>16)&0xff),
+                 (int)(uint8_t)((a>>24)&0xff));
+    string_addr = inaddr_buf;
+    payload_len = strlen(inaddr_buf)+1;
+    tor_assert(payload_len <= RELAY_PAYLOAD_SIZE);
+  }
 
   log_debug(LD_APP,
             "Sending relay cell to begin stream %d.", ap_conn->stream_id);
@@ -1625,7 +1647,7 @@
 }
 
 /** Send an answer to an AP connection that has requested a DNS lookup
- * via SOCKS.  The type should be one of RESOLVED_TYPE_(IPV4|IPV6) or
+ * via SOCKS.  The type should be one of RESOLVED_TYPE_(IPV4|IPV6|HOSTNAME) or
  * -1 for unreachable; the answer should be in the format specified
  * in the socks extensions document.
  **/
@@ -1636,7 +1658,7 @@
                                        const char *answer,
                                        int ttl)
 {
-  char buf[256];
+  char buf[384];
   size_t replylen;
 
   if (answer_type == RESOLVED_TYPE_IPV4) {
@@ -1675,6 +1697,14 @@
       memcpy(buf+4, answer, 16); /* address */
       set_uint16(buf+20, 0); /* port == 0. */
       replylen = 22;
+    } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
+      buf[1] = SOCKS5_SUCCEEDED;
+      buf[2] = 0; /* reserved */
+      buf[3] = 0x03; /* Domainname address type */
+      memcpy(buf+4, answer, answer_len); /* address */
+      buf[4+answer_len] = '\0';
+      set_uint16(buf+4+answer_len+1, 0); /* port == 0. */
+      replylen = 4+answer_len+1+2;
     } else {
       buf[1] = SOCKS5_HOST_UNREACHABLE;
       memset(buf+2, 0, 8);
@@ -1699,7 +1729,8 @@
 void
 connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply,
                                     size_t replylen,
-                                    socks5_reply_status_t status) {
+                                    socks5_reply_status_t status)
+{
   char buf[256];
   tor_assert(conn->socks_request); /* make sure it's an AP stream */
 
@@ -2072,7 +2103,7 @@
     }
   }
 
-  if (conn->socks_request->command != SOCKS_COMMAND_RESOLVE) {
+  if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
     struct in_addr in;
     uint32_t addr = 0;
     addr_policy_result_t r;
@@ -2082,7 +2113,13 @@
                                     exit->exit_policy);
     if (r == ADDR_POLICY_REJECTED || r == ADDR_POLICY_PROBABLY_REJECTED)
       return 0;
-  } else {
+  } else { /* Some kind of a resolve. */
+
+    /* Can't support reverse lookups without eventdns. */
+    if (conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR &&
+        exit->has_old_dnsworkers)
+      return 0;
+
     /* Don't send DNS requests to non-exit servers by default. */
     if (policy_is_reject_star(exit->exit_policy))
       return 0;

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2006-09-22 00:24:27 UTC (rev 8450)
+++ tor/trunk/src/or/or.h	2006-09-22 00:43:55 UTC (rev 8451)
@@ -1612,6 +1612,7 @@
 #define MAX_SOCKS_ADDR_LEN 256
 #define SOCKS_COMMAND_CONNECT 0x01
 #define SOCKS_COMMAND_RESOLVE 0xF0
+#define SOCKS_COMMAND_RESOLVE_PTR 0xF1
 /** State of a SOCKS request from a user to an OP */
 struct socks_request_t {
   char socks_version; /**< Which version of SOCKS did the client use? */



More information about the tor-commits mailing list