|
@@ -186,6 +186,8 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose,
|
|
|
case DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2:
|
|
|
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
|
|
case DIR_PURPOSE_FETCH_RENDDESC_V2:
|
|
|
+ case DIR_PURPOSE_FETCH_HSDESC:
|
|
|
+ case DIR_PURPOSE_UPLOAD_HSDESC:
|
|
|
return 1;
|
|
|
case DIR_PURPOSE_SERVER:
|
|
|
default:
|
|
@@ -244,6 +246,10 @@ dir_conn_purpose_to_string(int purpose)
|
|
|
return "hidden-service v2 descriptor fetch";
|
|
|
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
|
|
return "hidden-service v2 descriptor upload";
|
|
|
+ case DIR_PURPOSE_FETCH_HSDESC:
|
|
|
+ return "hidden-service descriptor fetch";
|
|
|
+ case DIR_PURPOSE_UPLOAD_HSDESC:
|
|
|
+ return "hidden-service descriptor upload";
|
|
|
case DIR_PURPOSE_FETCH_MICRODESC:
|
|
|
return "microdescriptor fetch";
|
|
|
}
|
|
@@ -1034,11 +1040,12 @@ struct directory_request_t {
|
|
|
size_t payload_len;
|
|
|
/** Value to send in an if-modified-since header, or 0 for none. */
|
|
|
time_t if_modified_since;
|
|
|
- /** Hidden-service-specific information */
|
|
|
+ /** Hidden-service-specific information v2. */
|
|
|
const rend_data_t *rend_query;
|
|
|
/** Extra headers to append to the request */
|
|
|
config_line_t *additional_headers;
|
|
|
- /** */
|
|
|
+ /** Hidden-service-specific information for v3+. */
|
|
|
+ const hs_ident_dir_conn_t *hs_ident;
|
|
|
/** Used internally to directory.c: gets informed when the attempt to
|
|
|
* connect to the directory succeeds or fails, if that attempt bears on the
|
|
|
* directory's usability as a directory guard. */
|
|
@@ -1268,6 +1275,21 @@ directory_request_set_rend_query(directory_request_t *req,
|
|
|
}
|
|
|
req->rend_query = query;
|
|
|
}
|
|
|
+/**
|
|
|
+ * Set an object containing HS connection identifier to be associated with
|
|
|
+ * this request. Note that only an alias to <b>ident</b> is stored, so the
|
|
|
+ * <b>ident</b> object must outlive the request.
|
|
|
+ */
|
|
|
+void
|
|
|
+directory_request_set_hs_ident(directory_request_t *req,
|
|
|
+ const hs_ident_dir_conn_t *ident)
|
|
|
+{
|
|
|
+ if (ident) {
|
|
|
+ tor_assert(req->dir_purpose == DIR_PURPOSE_FETCH_HSDESC ||
|
|
|
+ req->dir_purpose == DIR_PURPOSE_UPLOAD_HSDESC);
|
|
|
+ }
|
|
|
+ req->hs_ident = ident;
|
|
|
+}
|
|
|
/** Set a static circuit_guard_state_t object to affliate with the request in
|
|
|
* <b>req</b>. This object will receive notification when the attempt to
|
|
|
* connect to the guard either succeeds or fails. */
|
|
@@ -1389,6 +1411,7 @@ directory_initiate_request,(directory_request_t *request))
|
|
|
const dir_indirection_t indirection = request->indirection;
|
|
|
const char *resource = request->resource;
|
|
|
const rend_data_t *rend_query = request->rend_query;
|
|
|
+ const hs_ident_dir_conn_t *hs_ident = request->hs_ident;
|
|
|
circuit_guard_state_t *guard_state = request->guard_state;
|
|
|
|
|
|
tor_assert(or_addr_port->port || dir_addr_port->port);
|
|
@@ -1476,8 +1499,16 @@ directory_initiate_request,(directory_request_t *request))
|
|
|
conn->dirconn_direct = !anonymized_connection;
|
|
|
|
|
|
/* copy rendezvous data, if any */
|
|
|
- if (rend_query)
|
|
|
+ if (rend_query) {
|
|
|
+ /* We can't have both v2 and v3+ identifier. */
|
|
|
+ tor_assert_nonfatal(!hs_ident);
|
|
|
conn->rend_data = rend_data_dup(rend_query);
|
|
|
+ }
|
|
|
+ if (hs_ident) {
|
|
|
+ /* We can't have both v2 and v3+ identifier. */
|
|
|
+ tor_assert_nonfatal(!rend_query);
|
|
|
+ conn->hs_ident = hs_ident_dir_conn_dup(hs_ident);
|
|
|
+ }
|
|
|
|
|
|
if (!anonymized_connection && !use_begindir) {
|
|
|
/* then we want to connect to dirport directly */
|
|
@@ -1835,6 +1866,12 @@ directory_send_command(dir_connection_t *conn,
|
|
|
httpcommand = "POST";
|
|
|
url = tor_strdup("/tor/rendezvous2/publish");
|
|
|
break;
|
|
|
+ case DIR_PURPOSE_UPLOAD_HSDESC:
|
|
|
+ tor_assert(resource);
|
|
|
+ tor_assert(payload);
|
|
|
+ httpcommand = "POST";
|
|
|
+ tor_asprintf(&url, "/tor/hs/%s/publish", resource);
|
|
|
+ break;
|
|
|
default:
|
|
|
tor_assert(0);
|
|
|
return;
|
|
@@ -2189,6 +2226,8 @@ static int handle_response_fetch_renddesc_v2(dir_connection_t *,
|
|
|
const response_handler_args_t *);
|
|
|
static int handle_response_upload_renddesc_v2(dir_connection_t *,
|
|
|
const response_handler_args_t *);
|
|
|
+static int handle_response_upload_hsdesc(dir_connection_t *,
|
|
|
+ const response_handler_args_t *);
|
|
|
|
|
|
static int
|
|
|
dir_client_decompress_response_body(char **bodyp, size_t *bodylenp,
|
|
@@ -2489,6 +2528,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
|
|
case DIR_PURPOSE_UPLOAD_RENDDESC_V2:
|
|
|
rv = handle_response_upload_renddesc_v2(conn, &args);
|
|
|
break;
|
|
|
+ case DIR_PURPOSE_UPLOAD_HSDESC:
|
|
|
+ rv = handle_response_upload_hsdesc(conn, &args);
|
|
|
+ break;
|
|
|
default:
|
|
|
tor_assert_nonfatal_unreached();
|
|
|
rv = -1;
|
|
@@ -3180,6 +3222,52 @@ handle_response_upload_renddesc_v2(dir_connection_t *conn,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Handler function: processes a response to a POST request to upload an
|
|
|
+ * hidden service descriptor.
|
|
|
+ **/
|
|
|
+static int
|
|
|
+handle_response_upload_hsdesc(dir_connection_t *conn,
|
|
|
+ const response_handler_args_t *args)
|
|
|
+{
|
|
|
+ const int status_code = args->status_code;
|
|
|
+ const char *reason = args->reason;
|
|
|
+
|
|
|
+ tor_assert(conn);
|
|
|
+ tor_assert(conn->base_.purpose == DIR_PURPOSE_UPLOAD_HSDESC);
|
|
|
+
|
|
|
+ log_info(LD_REND, "Uploaded hidden service descriptor (status %d "
|
|
|
+ "(%s))",
|
|
|
+ status_code, escaped(reason));
|
|
|
+ /* For this directory response, it MUST have an hidden service identifier on
|
|
|
+ * this connection. */
|
|
|
+ tor_assert(conn->hs_ident);
|
|
|
+ switch (status_code) {
|
|
|
+ case 200:
|
|
|
+ log_info(LD_REND, "Uploading hidden service descriptor: "
|
|
|
+ "finished with status 200 (%s)", escaped(reason));
|
|
|
+ /* XXX: Trigger control event. */
|
|
|
+ break;
|
|
|
+ case 400:
|
|
|
+ log_warn(LD_REND, "Uploading hidden service descriptor: http "
|
|
|
+ "status 400 (%s) response from dirserver "
|
|
|
+ "'%s:%d'. Malformed hidden service descriptor?",
|
|
|
+ escaped(reason), conn->base_.address, conn->base_.port);
|
|
|
+ /* XXX: Trigger control event. */
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ log_warn(LD_REND, "Uploading hidden service descriptor: http "
|
|
|
+ "status %d (%s) response unexpected (server "
|
|
|
+ "'%s:%d').",
|
|
|
+ status_code, escaped(reason), conn->base_.address,
|
|
|
+ conn->base_.port);
|
|
|
+ /* XXX: Trigger control event. */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/** Called when a directory connection reaches EOF. */
|
|
|
int
|
|
|
connection_dir_reached_eof(dir_connection_t *conn)
|