|
@@ -48,8 +48,10 @@ const char control_c_id[] = "$Id$";
|
|
|
#define CONTROL_CMD_POSTDESCRIPTOR 0x000F
|
|
|
#define CONTROL_CMD_FRAGMENTHEADER 0x0010
|
|
|
#define CONTROL_CMD_FRAGMENT 0x0011
|
|
|
-#define CONTROL_CMD_REDIRECTSTREAM 0x0012
|
|
|
-#define _CONTROL_CMD_MAX_RECOGNIZED 0x0012
|
|
|
+#define CONTROL_CMD_REDIRECTSTREAM 0x0012
|
|
|
+#define CONTROL_CMD_CLOSESTREAM 0x0013
|
|
|
+#define CONTROL_CMD_CLOSECIRCUIT 0x0014
|
|
|
+#define _CONTROL_CMD_MAX_RECOGNIZED 0x0014
|
|
|
|
|
|
|
|
|
#define ERR_UNSPECIFIED 0x0000
|
|
@@ -152,6 +154,10 @@ static int handle_control_postdescriptor(connection_t *conn, uint32_t len,
|
|
|
const char *body);
|
|
|
static int handle_control_redirectstream(connection_t *conn, uint32_t len,
|
|
|
const char *body);
|
|
|
+static int handle_control_closestream(connection_t *conn, uint32_t len,
|
|
|
+ const char *body);
|
|
|
+static int handle_control_closecircuit(connection_t *conn, uint32_t len,
|
|
|
+ const char *body);
|
|
|
|
|
|
|
|
|
* human-readable string equivalent. */
|
|
@@ -772,7 +778,72 @@ handle_control_redirectstream(connection_t *conn, uint32_t len,
|
|
|
send_control_done(conn);
|
|
|
return 0;
|
|
|
}
|
|
|
+static int
|
|
|
+handle_control_closestream(connection_t *conn, uint32_t len,
|
|
|
+ const char *body)
|
|
|
+{
|
|
|
+ uint32_t conn_id;
|
|
|
+ connection_t *ap_conn;
|
|
|
+ uint8_t reason;
|
|
|
+ int hold_open;
|
|
|
+
|
|
|
+ if (len < 6) {
|
|
|
+ send_control_error(conn, ERR_SYNTAX, "closestream message too short");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ conn_id = ntohl(get_uint32(body));
|
|
|
+ reason = *(uint8_t*)(body+4);
|
|
|
+ hold_open = (*(uint8_t*)(body+5)) & 1;
|
|
|
+
|
|
|
+ if (!(ap_conn = connection_get_by_global_id(conn_id))
|
|
|
+ || ap_conn->state != CONN_TYPE_AP
|
|
|
+ || !ap_conn->socks_request) {
|
|
|
+ send_control_error(conn, ERR_NO_STREAM,
|
|
|
+ "No AP connection found with given ID");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ap_conn->socks_request->has_finished) {
|
|
|
+ socks5_reply_status_t status =
|
|
|
+ connection_edge_end_reason_socks5_response(reason);
|
|
|
+ connection_ap_handshake_socks_reply(ap_conn, NULL, 0, status);
|
|
|
+ }
|
|
|
+ if (hold_open)
|
|
|
+ ap_conn->hold_open_until_flushed = 1;
|
|
|
+ connection_mark_for_close(ap_conn);
|
|
|
+
|
|
|
+ send_control_done(conn);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+static int
|
|
|
+handle_control_closecircuit(connection_t *conn, uint32_t len,
|
|
|
+ const char *body)
|
|
|
+{
|
|
|
+ uint32_t circ_id;
|
|
|
+ circuit_t *circ;
|
|
|
+ int safe;
|
|
|
|
|
|
+ if (len < 5) {
|
|
|
+ send_control_error(conn, ERR_SYNTAX, "closecircuit message too short");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ circ_id = ntohl(get_uint32(body));
|
|
|
+ safe = (*(uint8_t*)(body+4)) & 1;
|
|
|
+
|
|
|
+ if (!(circ = circuit_get_by_global_id(circ_id))) {
|
|
|
+ send_control_error(conn, ERR_NO_CIRC,
|
|
|
+ "No circuit found with given ID");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!safe || !circ->p_streams) {
|
|
|
+ circuit_mark_for_close(circ);
|
|
|
+ }
|
|
|
+
|
|
|
+ send_control_done(conn);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
|
|
|
int
|
|
@@ -882,6 +953,14 @@ connection_control_process_inbuf(connection_t *conn) {
|
|
|
if (handle_control_redirectstream(conn, body_len, body))
|
|
|
return -1;
|
|
|
break;
|
|
|
+ case CONTROL_CMD_CLOSESTREAM:
|
|
|
+ if (handle_control_closestream(conn, body_len, body))
|
|
|
+ return -1;
|
|
|
+ break;
|
|
|
+ case CONTROL_CMD_CLOSECIRCUIT:
|
|
|
+ if (handle_control_closecircuit(conn, body_len, body))
|
|
|
+ return -1;
|
|
|
+ break;
|
|
|
case CONTROL_CMD_ERROR:
|
|
|
case CONTROL_CMD_DONE:
|
|
|
case CONTROL_CMD_CONFVALUE:
|