[or-cvs] r8946: Add support for (Free?)BSD's natd, which was an old way to l (in tor/trunk: . src/or)

nickm at seul.org nickm at seul.org
Tue Nov 14 00:06:32 UTC 2006


Author: nickm
Date: 2006-11-13 19:06:31 -0500 (Mon, 13 Nov 2006)
New Revision: 8946

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/src/or/buffers.c
   tor/trunk/src/or/config.c
   tor/trunk/src/or/connection.c
   tor/trunk/src/or/connection_edge.c
   tor/trunk/src/or/control.c
   tor/trunk/src/or/hibernate.c
   tor/trunk/src/or/or.h
Log:
 r9308 at totoro:  nickm | 2006-11-13 18:41:23 -0500
 Add support for (Free?)BSD's natd, which was an old way to let you
 have your firewall automatically redirect traffic.  (Original patch
 from Zajcev Evgeny, updated for 0.1.2.x by tup.)
 



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r9308] on 96637b51-b116-0410-a10e-9941ebb49b64

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2006-11-14 00:06:02 UTC (rev 8945)
+++ tor/trunk/ChangeLog	2006-11-14 00:06:31 UTC (rev 8946)
@@ -1,4 +1,9 @@
 Changes in version 0.1.2.4-alpha - 2006-11-??
+  o Major features
+    - Add support for using natd; this allows FreeBSDs earlier than 5.1.2 to
+      have ipfw send connections through Tor without using SOCKS. (Patch from
+      Zajcev Evgeny with tweaks from tup.)
+
   o Minor features
     - Add breakdown of public key operations to dumped statistics.
 

Modified: tor/trunk/src/or/buffers.c
===================================================================
--- tor/trunk/src/or/buffers.c	2006-11-14 00:06:02 UTC (rev 8945)
+++ tor/trunk/src/or/buffers.c	2006-11-14 00:06:31 UTC (rev 8946)
@@ -1304,6 +1304,34 @@
   return 1;
 }
 
+/** Try to read a single LF-terminated line from <b>buf</b>, and write it,
+ * NUL-terminated, into the *<b>data_len</b> byte buffer at <b>data_out</b>.
+ * Set *<b>data_len</b> to the number of bytes in the line, not counting the
+ * terminating NUL.  Return 1 if we read a whole line, return 0 if we don't
+ * have a whole line yet, and return -1 if the line length exceeds
+ *<b>data_len</b>.
+ */
+int
+fetch_from_buf_line_lf(buf_t *buf, char *data_out, size_t *data_len)
+{
+  char *cp;
+  size_t sz;
+
+  size_t remaining = buf->datalen - _buf_offset(buf,buf->cur);
+  cp = find_char_on_buf(buf, buf->cur, remaining, '\n');
+  if (!cp)
+    return 0;
+  sz = _buf_offset(buf, cp);
+  if (sz+2 > *data_len) {
+    *data_len = sz+2;
+    return -1;
+  }
+  fetch_from_buf(data_out, sz+1, buf);
+  data_out[sz+1] = '\0';
+  *data_len = sz+1;
+  return 1;
+}
+
 /** Compress on uncompress the <b>data_len</b> bytes in <b>data</b> using the
  * zlib state <b>state</b>, appending the result to <b>buf</b>.  If
  * <b>done</b> is true, flush the data in the state and finish the

Modified: tor/trunk/src/or/config.c
===================================================================
--- tor/trunk/src/or/config.c	2006-11-14 00:06:02 UTC (rev 8945)
+++ tor/trunk/src/or/config.c	2006-11-14 00:06:31 UTC (rev 8946)
@@ -195,6 +195,8 @@
   VAR("MyFamily",            STRING,   MyFamily,             NULL),
   VAR("NewCircuitPeriod",    INTERVAL, NewCircuitPeriod,     "30 seconds"),
   VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
+  VAR("NatdListenAddress",   LINELIST, NatdListenAddress,    NULL),
+  VAR("NatdPort",            UINT,     NatdPort,             "0"),
   VAR("Nickname",            STRING,   Nickname,             NULL),
   VAR("NoPublish",           BOOL,     NoPublish,            "0"),
   VAR("NodeFamily",          LINELIST, NodeFamilies,         NULL),
@@ -2086,21 +2088,30 @@
   if (options->TransPort == 0 && options->TransListenAddress != NULL)
     REJECT("TransPort must be defined if TransListenAddress is defined.");
 
+  if (options->NatdPort == 0 && options->NatdListenAddress != NULL)
+    REJECT("NatdPort must be defined if NatdListenAddress is defined.");
+
 #if 0 /* don't complain, since a standard configuration does this! */
   if (options->SocksPort == 0 && options->SocksListenAddress != NULL)
     REJECT("SocksPort must be defined if SocksListenAddress is defined.");
 #endif
 
-  for (i = 0; i < 2; ++i) {
+  for (i = 0; i < 3; ++i) {
     int is_socks = i==0;
+    int is_trans = i==1;
     config_line_t *line, *opt, *old;
-    const char *tp = is_socks ? "SOCKS proxy" : "transparent proxy";
+    const char *tp = is_socks ? "SOCKS proxy" :
+                     is_trans ? "transparent proxy"
+                              : "natd proxy";
     if (is_socks) {
       opt = options->SocksListenAddress;
       old = old_options ? old_options->SocksListenAddress : NULL;
-    } else {
+    } else if (is_trans) {
       opt = options->TransListenAddress;
       old = old_options ? old_options->TransListenAddress : NULL;
+    } else {
+      opt = options->NatdListenAddress;
+      old = old_options ? old_options->NatdListenAddress : NULL;
     }
 
     for (line = opt; line; line = line->next) {
@@ -2184,9 +2195,13 @@
   if (options->TransPort < 0 || options->TransPort > 65535)
     REJECT("TransPort option out of bounds.");
 
+  if (options->NatdPort < 0 || options->NatdPort > 65535)
+    REJECT("NatdPort option out of bounds.");
+
   if (options->SocksPort == 0 && options->TransPort == 0 &&
-      options->ORPort == 0)
-    REJECT("SocksPort, TransPort, and ORPort are all undefined? Quitting.");
+      options->NatdPort == 0 && options->ORPort == 0)
+    REJECT("SocksPort, TransPort, NatdPort, and ORPort are all undefined? "
+           "Quitting.");
 
   if (options->ControlPort < 0 || options->ControlPort > 65535)
     REJECT("ControlPort option out of bounds.");

Modified: tor/trunk/src/or/connection.c
===================================================================
--- tor/trunk/src/or/connection.c	2006-11-14 00:06:02 UTC (rev 8945)
+++ tor/trunk/src/or/connection.c	2006-11-14 00:06:31 UTC (rev 8946)
@@ -45,7 +45,9 @@
     case CONN_TYPE_OR: return "OR";
     case CONN_TYPE_EXIT: return "Exit";
     case CONN_TYPE_AP_LISTENER: return "Socks listener";
-    case CONN_TYPE_AP_TRANS_LISTENER: return "Transparent listener";
+    case CONN_TYPE_AP_TRANS_LISTENER:
+      return "Transparent pf/netfilter listener";
+    case CONN_TYPE_AP_NATD_LISTENER: return "Transparent natd listener";
     case CONN_TYPE_AP: return "Socks";
     case CONN_TYPE_DIR_LISTENER: return "Directory listener";
     case CONN_TYPE_DIR: return "Directory";
@@ -72,6 +74,7 @@
     case CONN_TYPE_OR_LISTENER:
     case CONN_TYPE_AP_LISTENER:
     case CONN_TYPE_AP_TRANS_LISTENER:
+    case CONN_TYPE_AP_NATD_LISTENER:
     case CONN_TYPE_DIR_LISTENER:
     case CONN_TYPE_CONTROL_LISTENER:
       if (state == LISTENER_STATE_READY)
@@ -97,6 +100,7 @@
     case CONN_TYPE_AP:
       switch (state) {
         case AP_CONN_STATE_SOCKS_WAIT: return "waiting for dest info";
+        case AP_CONN_STATE_NATD_WAIT: return "waiting for natd dest info";
         case AP_CONN_STATE_RENDDESC_WAIT: return "waiting for rendezvous desc";
         case AP_CONN_STATE_CONTROLLER_WAIT: return "waiting for controller";
         case AP_CONN_STATE_CIRCUIT_WAIT: return "waiting for safe circuit";
@@ -827,6 +831,9 @@
         case CONN_TYPE_AP_TRANS_LISTENER:
           conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
           return connection_ap_process_transparent(TO_EDGE_CONN(conn));
+        case CONN_TYPE_AP_NATD_LISTENER:
+          conn->state = AP_CONN_STATE_NATD_WAIT;
+          break;
       }
       break;
     case CONN_TYPE_DIR:
@@ -1071,6 +1078,10 @@
                       options->TransPort, "127.0.0.1", force,
                       replaced_conns, new_conns, 0)<0)
     return -1;
+  if (retry_listeners(CONN_TYPE_AP_NATD_LISTENER, options->NatdListenAddress,
+                      options->NatdPort, "127.0.0.1", force,
+                      replaced_conns, new_conns, 0)<0)
+    return -1;
   if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
                       options->ControlListenAddress,
                       options->ControlPort, "127.0.0.1", force,
@@ -1286,6 +1297,7 @@
       return connection_handle_listener_read(conn, CONN_TYPE_OR);
     case CONN_TYPE_AP_LISTENER:
     case CONN_TYPE_AP_TRANS_LISTENER:
+    case CONN_TYPE_AP_NATD_LISTENER:
       return connection_handle_listener_read(conn, CONN_TYPE_AP);
     case CONN_TYPE_DIR_LISTENER:
       return connection_handle_listener_read(conn, CONN_TYPE_DIR);
@@ -1922,6 +1934,7 @@
   if (conn->type == CONN_TYPE_OR_LISTENER ||
       conn->type == CONN_TYPE_AP_LISTENER ||
       conn->type == CONN_TYPE_AP_TRANS_LISTENER ||
+      conn->type == CONN_TYPE_AP_NATD_LISTENER ||
       conn->type == CONN_TYPE_DIR_LISTENER ||
       conn->type == CONN_TYPE_CONTROL_LISTENER)
     return 1;
@@ -2280,6 +2293,7 @@
     case CONN_TYPE_OR_LISTENER:
     case CONN_TYPE_AP_LISTENER:
     case CONN_TYPE_AP_TRANS_LISTENER:
+    case CONN_TYPE_AP_NATD_LISTENER:
     case CONN_TYPE_DIR_LISTENER:
     case CONN_TYPE_CONTROL_LISTENER:
       tor_assert(conn->state == LISTENER_STATE_READY);

Modified: tor/trunk/src/or/connection_edge.c
===================================================================
--- tor/trunk/src/or/connection_edge.c	2006-11-14 00:06:02 UTC (rev 8945)
+++ tor/trunk/src/or/connection_edge.c	2006-11-14 00:06:31 UTC (rev 8946)
@@ -28,6 +28,7 @@
 static smartlist_t *redirect_exit_list = NULL;
 
 static int connection_ap_handshake_process_socks(edge_connection_t *conn);
+static int connection_ap_process_natd(edge_connection_t *conn);
 static int connection_exit_connect_dir(edge_connection_t *exit_conn);
 
 /** An AP stream has failed/finished. If it hasn't already sent back
@@ -109,6 +110,12 @@
         return -1;
       }
       return 0;
+    case AP_CONN_STATE_NATD_WAIT:
+      if (connection_ap_process_natd(conn) < 0) {
+        /* already marked */
+        return -1;
+      }
+      return 0;
     case AP_CONN_STATE_OPEN:
     case EXIT_CONN_STATE_OPEN:
       if (connection_edge_package_raw_inbuf(conn, package_partial) < 0) {
@@ -247,6 +254,7 @@
       connection_edge_consider_sending_sendme(conn);
       return 0;
     case AP_CONN_STATE_SOCKS_WAIT:
+    case AP_CONN_STATE_NATD_WAIT:
     case AP_CONN_STATE_RENDDESC_WAIT:
     case AP_CONN_STATE_CIRCUIT_WAIT:
     case AP_CONN_STATE_CONNECT_WAIT:
@@ -1471,7 +1479,7 @@
 
   if (connection_ap_get_original_destination(conn, socks) < 0) {
     log_warn(LD_APP,"Fetching original destination failed. Closing.");
-    connection_mark_unattached_ap(conn, 0);
+    connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_FETCH_ORIG_DEST);
     return -1;
   }
   /* we have the original destination */
@@ -1485,6 +1493,77 @@
   return connection_ap_handshake_rewrite_and_attach(conn, NULL);
 }
 
+/** connection_edge_process_inbuf() found a conn in state
+ * natd_wait. See if conn->inbuf has the right bytes to proceed.
+ * See libalias(3) and ProxyEncodeTcpStream() in alias_proxy.c for
+ * the encoding form of the original destination.
+ *
+ * If the original destination is complete, send it to
+ * connection_ap_handshake_rewrite_and_attach().
+ *
+ * Return -1 if an unexpected error with conn (and it should be marked
+ * for close), else return 0.
+ */
+static int
+connection_ap_process_natd(edge_connection_t *conn)
+{
+  char tmp_buf[36], *tbuf, *daddr;
+  size_t tlen = 30;
+  int err;
+  socks_request_t *socks;
+  or_options_t *options = get_options();
+
+  tor_assert(conn);
+  tor_assert(conn->_base.type == CONN_TYPE_AP);
+  tor_assert(conn->_base.state == AP_CONN_STATE_NATD_WAIT);
+  tor_assert(conn->socks_request);
+  socks = conn->socks_request;
+
+  log_debug(LD_APP,"entered.");
+
+  /* look for LF-terminated "[DEST ip_addr port]"
+   * where ip_addr is a dotted-quad and port is in string form */
+  err = fetch_from_buf_line_lf(conn->_base.inbuf, tmp_buf, &tlen);
+  if (err == 0)
+    return 0;
+  if (err < 0) {
+    log_warn(LD_APP,"Natd handshake failed (DEST too long). Closing");
+    connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
+    return -1;
+  }
+
+  if (strncmp(tmp_buf, "[DEST ", 6)) {
+    log_warn(LD_APP,"Natd handshake failed. Closing. tmp_buf = '%s'", tmp_buf);
+    connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
+    return -1;
+  }
+
+  tbuf = &tmp_buf[0] + 6;
+  daddr = tbuf;
+  while (tbuf[0] != '\0' && tbuf[0] != ' ')
+    tbuf++;
+  tbuf[0] = '\0';
+  tbuf++;
+
+  /* pretend that a socks handshake completed so we don't try to
+   * send a socks reply down a natd conn */
+  socks->command = SOCKS_COMMAND_CONNECT;
+  socks->has_finished = 1;
+
+  strlcpy(socks->address, daddr, sizeof(socks->address));
+  socks->port = atoi(tbuf);
+
+  control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
+
+  if (options->LeaveStreamsUnattached) {
+    conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
+    return 0;
+  }
+  conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
+
+  return connection_ap_handshake_rewrite_and_attach(conn, NULL);
+}
+
 /** Iterate over the two bytes of stream_id until we get one that is not
  * already in use; return it. Return 0 if can't get a unique stream_id.
  */

Modified: tor/trunk/src/or/control.c
===================================================================
--- tor/trunk/src/or/control.c	2006-11-14 00:06:02 UTC (rev 8945)
+++ tor/trunk/src/or/control.c	2006-11-14 00:06:31 UTC (rev 8946)
@@ -1583,7 +1583,8 @@
       origin_circuit_t *origin_circ = NULL;
       if (conns[i]->type != CONN_TYPE_AP ||
           conns[i]->marked_for_close ||
-          conns[i]->state == AP_CONN_STATE_SOCKS_WAIT)
+          conns[i]->state == AP_CONN_STATE_SOCKS_WAIT ||
+          conns[i]->state == AP_CONN_STATE_NATD_WAIT)
         continue;
       conn = TO_EDGE_CONN(conns[i]);
       switch (conn->_base.state)

Modified: tor/trunk/src/or/hibernate.c
===================================================================
--- tor/trunk/src/or/hibernate.c	2006-11-14 00:06:02 UTC (rev 8945)
+++ tor/trunk/src/or/hibernate.c	2006-11-14 00:06:31 UTC (rev 8946)
@@ -713,6 +713,7 @@
   while ((conn = connection_get_by_type(CONN_TYPE_OR_LISTENER)) ||
          (conn = connection_get_by_type(CONN_TYPE_AP_LISTENER)) ||
          (conn = connection_get_by_type(CONN_TYPE_AP_TRANS_LISTENER)) ||
+         (conn = connection_get_by_type(CONN_TYPE_AP_NATD_LISTENER)) ||
          (conn = connection_get_by_type(CONN_TYPE_DIR_LISTENER))) {
     log_info(LD_NET,"Closing listener type %d", conn->type);
     connection_mark_for_close(conn);

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2006-11-14 00:06:02 UTC (rev 8945)
+++ tor/trunk/src/or/or.h	2006-11-14 00:06:31 UTC (rev 8946)
@@ -224,9 +224,13 @@
 #define CONN_TYPE_CONTROL_LISTENER 12
 /** Type for connections from user interface process. */
 #define CONN_TYPE_CONTROL 13
-/** Type for sockets listening for transparent proxy connections. */
+/** Type for sockets listening for transparent connections redirected by pf or
+ * netfilter. */
 #define CONN_TYPE_AP_TRANS_LISTENER 14
-#define _CONN_TYPE_MAX 14
+/** Type for sockets listening for transparent connections redirected by
+ * natd. */
+#define CONN_TYPE_AP_NATD_LISTENER 15
+#define _CONN_TYPE_MAX 15
 
 #define CONN_IS_EDGE(x) \
   ((x)->type == CONN_TYPE_EXIT || (x)->type == CONN_TYPE_AP)
@@ -294,7 +298,10 @@
 #define AP_CONN_STATE_RESOLVE_WAIT 10
 /** State for a SOCKS connection: ready to send and receive. */
 #define AP_CONN_STATE_OPEN 11
-#define _AP_CONN_STATE_MAX 11
+/** State for a transparent natd connection: waiting for original
+ * destination. */
+#define AP_CONN_STATE_NATD_WAIT 12
+#define _AP_CONN_STATE_MAX 12
 
 #define _DIR_CONN_STATE_MIN 1
 /** State for connection to directory server: waiting for connect(). */
@@ -489,6 +496,8 @@
 #define END_STREAM_REASON_CANT_ATTACH 257
 #define END_STREAM_REASON_NET_UNREACHABLE 258
 #define END_STREAM_REASON_SOCKSPROTOCOL 259
+#define END_STREAM_REASON_CANT_FETCH_ORIG_DEST 260
+#define END_STREAM_REASON_INVALID_NATD_DEST 261
 
 /* OR this with the argument to control_event_stream_status to indicate that
  * the reason came from an END cell. */
@@ -1450,8 +1459,11 @@
   config_line_t *DirPolicy; /**< Lists of dir policy components */
   /** Addresses to bind for listening for SOCKS connections. */
   config_line_t *SocksListenAddress;
-  /** Addresses to bind for listening for transparent connections. */
+  /** Addresses to bind for listening for transparent pf/nefilter
+   * connections. */
   config_line_t *TransListenAddress;
+  /** Addresses to bind for listening for transparent natd connections */
+  config_line_t *NatdListenAddress;
   /** Addresses to bind for listening for OR connections. */
   config_line_t *ORListenAddress;
   /** Addresses to bind for listening for directory connections. */
@@ -1473,7 +1485,9 @@
                              * length (alpha in geometric distribution). */
   int ORPort; /**< Port to listen on for OR connections. */
   int SocksPort; /**< Port to listen on for SOCKS connections. */
-  int TransPort; /**< Port to listen on for transparent connections. */
+  /** Port to listen on for transparent pf/netfilter connections. */
+  int TransPort;
+  int NatdPort; /**< Port to listen on for transparent natd connections. */
   int ControlPort; /**< Port to listen on for control connections. */
   int DirPort; /**< Port to listen on for directory connections. */
   int AssumeReachable; /**< Whether to publish our descriptor regardless. */
@@ -1715,6 +1729,7 @@
 int fetch_from_buf_control0(buf_t *buf, uint32_t *len_out, uint16_t *type_out,
                             char **body_out, int check_for_v1);
 int fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len);
+int fetch_from_buf_line_lf(buf_t *buf, char *data_out, size_t *data_len);
 
 void assert_buf_ok(buf_t *buf);
 



More information about the tor-commits mailing list