⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 connection_edge.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
      if (s[1] != '\0') {
        conn->chosen_exit_name = tor_strdup(s+1);
/* DOCDOC */
#define TRACKHOSTEXITS_RETRIES 5
        if (remapped_to_exit) /* 5 tries before it expires the addressmap */
          TO_CONN(conn)->chosen_exit_retries = TRACKHOSTEXITS_RETRIES;
        *s = 0;
      } else {
        log_warn(LD_APP,"Malformed exit address '%s.exit'. Refusing.",
                 safe_str(socks->address));
        control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
                                    escaped(socks->address));
        connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
        return -1;
      }
    } else {
      routerinfo_t *r;
      conn->chosen_exit_name = tor_strdup(socks->address);
      r = router_get_by_nickname(conn->chosen_exit_name, 1);
      *socks->address = 0;
      if (r) {
        strlcpy(socks->address, r->address, sizeof(socks->address));
      } else {
        log_warn(LD_APP,
                 "Unrecognized server in exit address '%s.exit'. Refusing.",
                 safe_str(socks->address));
        connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
        return -1;
      }
    }
  }

  if (addresstype != ONION_HOSTNAME) {
    /* not a hidden-service request (i.e. normal or .exit) */
    if (address_is_invalid_destination(socks->address, 1)) {
      control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
                                  escaped(socks->address));
      log_warn(LD_APP,
               "Destination '%s' seems to be an invalid hostname. Failing.",
               safe_str(socks->address));
      connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
      return -1;
    }

    if (socks->command == SOCKS_COMMAND_RESOLVE) {
      uint32_t answer;
      struct in_addr in;
      /* Reply to resolves immediately if we can. */
      if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
        log_warn(LD_APP,"Address to be resolved is too large. Failing.");
        control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
                                    escaped(socks->address));
        connection_ap_handshake_socks_resolved(conn,
                                               RESOLVED_TYPE_ERROR_TRANSIENT,
                                               0,NULL,-1,TIME_MAX);
        connection_mark_unattached_ap(conn,
                                END_STREAM_REASON_SOCKSPROTOCOL |
                                END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
        return -1;
      }
      if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
        /* leave it in network order */
        answer = in.s_addr;
        /* remember _what_ is supposed to have been resolved. */
        strlcpy(socks->address, orig_address, sizeof(socks->address));
        connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
                                               (char*)&answer,-1,map_expires);
        connection_mark_unattached_ap(conn,
                                END_STREAM_REASON_DONE |
                                END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
        return 0;
      }
      tor_assert(!automap);
      rep_hist_note_used_resolve(now); /* help predict this next time */
    } else if (socks->command == SOCKS_COMMAND_CONNECT) {
      tor_assert(!automap);
      if (socks->port == 0) {
        log_notice(LD_APP,"Application asked to connect to port 0. Refusing.");
        connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
        return -1;
      }

      if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
        /* see if we can find a suitable enclave exit */
        routerinfo_t *r =
          router_find_exact_exit_enclave(socks->address, socks->port);
        if (r) {
          log_info(LD_APP,
                   "Redirecting address %s to exit at enclave router %s",
                   safe_str(socks->address), r->nickname);
          /* use the hex digest, not nickname, in case there are two
             routers with this nickname */
          conn->chosen_exit_name =
            tor_strdup(hex_str(r->cache_info.identity_digest, DIGEST_LEN));
          conn->_base.chosen_exit_optional = 1;
        }
      }

      /* warn or reject if it's using a dangerous port */
      if (!conn->use_begindir && !conn->chosen_exit_name && !circ)
        if (consider_plaintext_ports(conn, socks->port) < 0)
          return -1;

      if (!conn->use_begindir) {
        /* help predict this next time */
        rep_hist_note_used_port(now, socks->port);
      }
    } else if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
      rep_hist_note_used_resolve(now); /* help predict this next time */
      /* no extra processing needed */
    } else {
      tor_fragile_assert();
    }
    conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
    if ((circ && connection_ap_handshake_attach_chosen_circuit(
                   conn, circ, cpath) < 0) ||
        (!circ &&
         connection_ap_handshake_attach_circuit(conn) < 0)) {
      if (!conn->_base.marked_for_close)
        connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
      return -1;
    }
    return 0;
  } else {
    /* it's a hidden-service request */
    rend_cache_entry_t *entry;
    int r;
    tor_assert(!automap);
    if (SOCKS_COMMAND_IS_RESOLVE(socks->command)) {
      /* 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,
               "Resolve requests to hidden services not allowed. Failing.");
      connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,
                                             0,NULL,-1,TIME_MAX);
      connection_mark_unattached_ap(conn,
                                END_STREAM_REASON_SOCKSPROTOCOL |
                                END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
      return -1;
    }

    if (circ) {
      log_warn(LD_CONTROL, "Attachstream to a circuit is not "
               "supported for .onion addresses currently. Failing.");
      connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
      return -1;
    }

    strlcpy(conn->rend_query, socks->address, sizeof(conn->rend_query));
    log_info(LD_REND,"Got a hidden service request for ID '%s'",
             safe_str(conn->rend_query));
    /* see if we already have it cached */
    r = rend_cache_lookup_entry(conn->rend_query, -1, &entry);
    if (r<0) {
      log_warn(LD_BUG,"Invalid service name '%s'",
               safe_str(conn->rend_query));
      connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
      return -1;
    }

    /* Help predict this next time. We're not sure if it will need
     * a stable circuit yet, but we know we'll need *something*. */
    rep_hist_note_used_internal(now, 0, 1);

    if (r==0) {
      conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
      log_info(LD_REND, "Unknown descriptor %s. Fetching.",
               safe_str(conn->rend_query));
      /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
       * arrives first. */
      rend_client_refetch_v2_renddesc(conn->rend_query);
      rend_client_refetch_renddesc(conn->rend_query);
    } else { /* r > 0 */
/** How long after we receive a hidden service descriptor do we consider
 * it valid? */
#define NUM_SECONDS_BEFORE_HS_REFETCH (60*15)
      if (now - entry->received < NUM_SECONDS_BEFORE_HS_REFETCH) {
        conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
        log_info(LD_REND, "Descriptor is here and fresh enough. Great.");
        if (connection_ap_handshake_attach_circuit(conn) < 0) {
          if (!conn->_base.marked_for_close)
            connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
          return -1;
        }
      } else {
        conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
        log_info(LD_REND, "Stale descriptor %s. Refetching.",
                 safe_str(conn->rend_query));
        /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
         * arrives first. */
        rend_client_refetch_v2_renddesc(conn->rend_query);
        rend_client_refetch_renddesc(conn->rend_query);
      }
    }
    return 0;
  }
  return 0; /* unreached but keeps the compiler happy */
}

#ifdef TRANS_PF
static int pf_socket = -1;
static int
get_pf_socket(void)
{
  int pf;
  /*  Ideally, this should be opened before dropping privs. */
  if (pf_socket >= 0)
    return pf_socket;

#ifdef OPENBSD
  /* only works on OpenBSD */
  pf = open("/dev/pf", O_RDONLY);
#else
  /* works on NetBSD and FreeBSD */
  pf = open("/dev/pf", O_RDWR);
#endif

  if (pf < 0) {
    log_warn(LD_NET, "open(\"/dev/pf\") failed: %s", strerror(errno));
    return -1;
  }

  pf_socket = pf;
  return pf_socket;
}
#endif

/** Fetch the original destination address and port from a
 * system-specific interface and put them into a
 * socks_request_t as if they came from a socks request.
 *
 * Return -1 if an error prevents fetching the destination,
 * else return 0.
 */
static int
connection_ap_get_original_destination(edge_connection_t *conn,
                                       socks_request_t *req)
{
#ifdef TRANS_NETFILTER
  /* Linux 2.4+ */
  struct sockaddr_in orig_dst;
  socklen_t orig_dst_len = sizeof(orig_dst);
  char tmpbuf[INET_NTOA_BUF_LEN];

  if (getsockopt(conn->_base.s, SOL_IP, SO_ORIGINAL_DST,
                 (struct sockaddr*)&orig_dst, &orig_dst_len) < 0) {
    int e = tor_socket_errno(conn->_base.s);
    log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e));
    return -1;
  }

  tor_inet_ntoa(&orig_dst.sin_addr, tmpbuf, sizeof(tmpbuf));
  strlcpy(req->address, tmpbuf, sizeof(req->address));
  req->port = ntohs(orig_dst.sin_port);

  return 0;
#elif defined(TRANS_PF)
  struct sockaddr_in proxy_addr;
  socklen_t proxy_addr_len = sizeof(proxy_addr);
  char tmpbuf[INET_NTOA_BUF_LEN];
  struct pfioc_natlook pnl;
  int pf = -1;

  if (getsockname(conn->_base.s, (struct sockaddr*)&proxy_addr,
                  &proxy_addr_len) < 0) {
    int e = tor_socket_errno(conn->_base.s);
    log_warn(LD_NET, "getsockname() to determine transocks destination "
             "failed: %s", tor_socket_strerror(e));
    return -1;
  }

  memset(&pnl, 0, sizeof(pnl));
  pnl.af              = AF_INET;
  pnl.proto           = IPPROTO_TCP;
  pnl.direction       = PF_OUT;
  pnl.saddr.v4.s_addr = htonl(conn->_base.addr);
  pnl.sport           = htons(conn->_base.port);
  pnl.daddr.v4.s_addr = proxy_addr.sin_addr.s_addr;
  pnl.dport           = proxy_addr.sin_port;

  pf = get_pf_socket();
  if (pf<0)
    return -1;

  if (ioctl(pf, DIOCNATLOOK, &pnl) < 0) {
    log_warn(LD_NET, "ioctl(DIOCNATLOOK) failed: %s", strerror(errno));
    return -1;
  }

  tor_inet_ntoa(&pnl.rdaddr.v4, tmpbuf, sizeof(tmpbuf));
  strlcpy(req->address, tmpbuf, sizeof(req->address));
  req->port = ntohs(pnl.rdport);

  return 0;
#else
  (void)conn;
  (void)req;
  log_warn(LD_BUG, "Called connection_ap_get_original_destination, but no "
           "transparent proxy method was configured.");
  return -1;
#endif
}

/** connection_edge_process_inbuf() found a conn in state
 * socks_wait. See if conn->inbuf has the right bytes to proceed with
 * the socks handshake.
 *
 * If the handshake is complete, send it to
 * connection_ap_handshake_rewrite_and_attach().
 *
 * Return -1 if an unexpected error with conn occurs (and mark it for close),
 * else return 0.
 */
static int
connection_ap_handshake_process_socks(edge_connection_t *conn)
{
  socks_request_t *socks;
  int sockshere;
  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_SOCKS_WAIT);
  tor_assert(conn->socks_request);
  socks = conn->socks_request;

  log_debug(LD_APP,"entered.");

  sockshere = fetch_from_buf_socks(conn->_base.inbuf, socks,
                                   options->TestSocks, options->SafeSocks);
  if (sockshere == 0) {
    if (socks->replylen) {
      connection_write_to_buf(socks->reply, socks->replylen, TO_CONN(conn));
      /* zero it out so we can do another round of negotiation */
      socks->replylen = 0;
    } else {
      log_debug(LD_APP,"socks handshake not all here yet.");
    }
    return 0;
  } else if (sockshere == -1) {
    if (socks->replylen) { /* we should send reply back */
      log_debug(LD_APP,"reply is already set for us. Using it.");
      connection_ap_handshake_socks_reply(conn, socks->reply, socks->replylen,
                                          END_STREAM_REASON_SOCKSPROTOCOL);

    } else {
      log_warn(LD_APP,"Fetching socks handshake failed. Closing.");
      connection_ap_handshake_socks_reply(conn, NULL, 0,
                                          END_STREAM_REASON_SOCKSPROTOCOL);
    }
    connection_mark_unattached_ap(conn,
                              END_STREAM_REASON_SOCKSPROTOCOL |
                              END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
    return -1;
  } /* else socks handshake is done, continue processing */

  if (hostname_is_noconnect_address(socks->addr

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -