connection_or.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. extern or_options_t options; /* command-line and config-file options */
  6. static int connection_tls_finish_handshake(connection_t *conn);
  7. /**************************************************************/
  8. static void cell_pack(char *dest, const cell_t *src) {
  9. *(uint16_t*)dest = htons(src->aci);
  10. *(uint8_t*)(dest+2) = src->command;
  11. *(uint8_t*)(dest+3) = src->length;
  12. *(uint32_t*)(dest+4) = 0; /* Reserved */
  13. memcpy(dest+8, src->payload, CELL_PAYLOAD_SIZE);
  14. }
  15. static void cell_unpack(cell_t *dest, const char *src) {
  16. dest->aci = ntohs(*(uint16_t*)(src));
  17. dest->command = *(uint8_t*)(src+2);
  18. dest->length = *(uint8_t*)(src+3);
  19. dest->seq = ntohl(*(uint32_t*)(src+4));
  20. memcpy(dest->payload, src+8, CELL_PAYLOAD_SIZE);
  21. }
  22. /**************************************************************/
  23. int connection_or_process_inbuf(connection_t *conn) {
  24. assert(conn && conn->type == CONN_TYPE_OR);
  25. if(conn->inbuf_reached_eof) {
  26. log_fn(LOG_INFO,"conn reached eof. Closing.");
  27. return -1;
  28. }
  29. if(conn->state != OR_CONN_STATE_OPEN)
  30. return 0; /* don't do anything */
  31. return connection_process_cell_from_inbuf(conn);
  32. }
  33. int connection_or_finished_flushing(connection_t *conn) {
  34. int e, len=sizeof(e);
  35. assert(conn && conn->type == CONN_TYPE_OR);
  36. switch(conn->state) {
  37. case OR_CONN_STATE_CONNECTING:
  38. if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
  39. if(!ERRNO_CONN_EINPROGRESS(errno)){
  40. log_fn(LOG_DEBUG,"in-progress connect failed. Removing.");
  41. return -1;
  42. } else {
  43. return 0; /* no change, see if next time is better */
  44. }
  45. }
  46. /* the connect has finished. */
  47. log_fn(LOG_INFO,"OR connect() to router %s:%u finished.",
  48. conn->address,conn->port);
  49. if(connection_tls_start_handshake(conn, 0) < 0)
  50. return -1;
  51. return 0;
  52. case OR_CONN_STATE_OPEN:
  53. connection_stop_writing(conn);
  54. return 0;
  55. default:
  56. log_fn(LOG_WARNING,"BUG: called in unexpected state.");
  57. return 0;
  58. }
  59. }
  60. /*********************/
  61. void connection_or_init_conn_from_router(connection_t *conn, routerinfo_t *router) {
  62. conn->addr = router->addr;
  63. conn->port = router->or_port;
  64. conn->receiver_bucket = conn->bandwidth = router->bandwidth;
  65. conn->onion_pkey = crypto_pk_dup_key(router->onion_pkey);
  66. conn->link_pkey = crypto_pk_dup_key(router->link_pkey);
  67. conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
  68. conn->nickname = strdup(router->nickname);
  69. if(conn->address)
  70. free(conn->address);
  71. conn->address = strdup(router->address);
  72. }
  73. connection_t *connection_or_connect(routerinfo_t *router) {
  74. connection_t *conn;
  75. assert(router);
  76. if(options.Nickname && !strcmp(router->nickname,options.Nickname)) {
  77. log_fn(LOG_WARNING,"You asked me to connect to myself! Failing.");
  78. return NULL;
  79. }
  80. /* this function should never be called if we're already connected to router, but */
  81. /* check first to be sure */
  82. conn = connection_exact_get_by_addr_port(router->addr,router->or_port);
  83. if(conn)
  84. return conn;
  85. conn = connection_new(CONN_TYPE_OR);
  86. /* set up conn so it's got all the data we need to remember */
  87. connection_or_init_conn_from_router(conn, router);
  88. if(connection_add(conn) < 0) { /* no space, forget it */
  89. connection_free(conn);
  90. return NULL;
  91. }
  92. switch(connection_connect(conn, router->address, router->addr, router->or_port)) {
  93. case -1:
  94. connection_remove(conn);
  95. connection_free(conn);
  96. return NULL;
  97. case 0:
  98. connection_set_poll_socket(conn);
  99. connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
  100. /* writable indicates finish, readable indicates broken link,
  101. error indicates broken link on windows */
  102. conn->state = OR_CONN_STATE_CONNECTING;
  103. return conn;
  104. /* case 1: fall through */
  105. }
  106. connection_set_poll_socket(conn);
  107. if(connection_tls_start_handshake(conn, 0) >= 0)
  108. return conn;
  109. /* failure */
  110. connection_remove(conn);
  111. connection_free(conn);
  112. return NULL;
  113. }
  114. /* ********************************** */
  115. int connection_tls_start_handshake(connection_t *conn, int receiving) {
  116. conn->state = OR_CONN_STATE_HANDSHAKING;
  117. conn->tls = tor_tls_new(conn->s, receiving);
  118. if(!conn->tls) {
  119. log_fn(LOG_WARNING,"tor_tls_new failed. Closing.");
  120. return -1;
  121. }
  122. connection_start_reading(conn);
  123. log_fn(LOG_DEBUG,"starting the handshake");
  124. if(connection_tls_continue_handshake(conn) < 0)
  125. return -1;
  126. return 0;
  127. }
  128. int connection_tls_continue_handshake(connection_t *conn) {
  129. switch(tor_tls_handshake(conn->tls)) {
  130. case TOR_TLS_ERROR:
  131. case TOR_TLS_CLOSE:
  132. log_fn(LOG_INFO,"tls error. breaking.");
  133. return -1;
  134. case TOR_TLS_DONE:
  135. return connection_tls_finish_handshake(conn);
  136. case TOR_TLS_WANTWRITE:
  137. connection_start_writing(conn);
  138. log_fn(LOG_DEBUG,"wanted write");
  139. return 0;
  140. case TOR_TLS_WANTREAD: /* handshaking conns are *always* reading */
  141. log_fn(LOG_DEBUG,"wanted read");
  142. return 0;
  143. }
  144. return 0;
  145. }
  146. static int connection_tls_finish_handshake(connection_t *conn) {
  147. crypto_pk_env_t *pk;
  148. routerinfo_t *router;
  149. conn->state = OR_CONN_STATE_OPEN;
  150. directory_set_dirty();
  151. connection_watch_events(conn, POLLIN);
  152. log_fn(LOG_DEBUG,"tls handshake done. verifying.");
  153. if(options.OnionRouter) { /* I'm an OR */
  154. if(tor_tls_peer_has_cert(conn->tls)) { /* it's another OR */
  155. pk = tor_tls_verify(conn->tls);
  156. if(!pk) {
  157. log_fn(LOG_WARNING,"Other side has a cert but it's invalid. Closing.");
  158. return -1;
  159. }
  160. router = router_get_by_link_pk(pk);
  161. if (!router) {
  162. log_fn(LOG_WARNING,"Unrecognized public key from peer. Closing.");
  163. crypto_free_pk_env(pk);
  164. return -1;
  165. }
  166. if(conn->link_pkey) { /* I initiated this connection. */
  167. if(crypto_pk_cmp_keys(conn->link_pkey, pk)) {
  168. log_fn(LOG_WARNING,"We connected to '%s' but he gave us a different key. Closing.",
  169. router->nickname);
  170. crypto_free_pk_env(pk);
  171. return -1;
  172. }
  173. log_fn(LOG_DEBUG,"The router's pk matches the one we meant to connect to. Good.");
  174. } else {
  175. if(connection_exact_get_by_addr_port(router->addr,router->or_port)) {
  176. log_fn(LOG_INFO,"Router %s is already connected. Dropping.", router->nickname);
  177. return -1;
  178. }
  179. connection_or_init_conn_from_router(conn, router);
  180. }
  181. crypto_free_pk_env(pk);
  182. } else { /* it's an OP */
  183. conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP;
  184. }
  185. } else { /* I'm a client */
  186. if(!tor_tls_peer_has_cert(conn->tls)) { /* it's a client too?! */
  187. log_fn(LOG_WARNING,"Neither peer sent a cert! Closing.");
  188. return -1;
  189. }
  190. pk = tor_tls_verify(conn->tls);
  191. if(!pk) {
  192. log_fn(LOG_WARNING,"Other side has a cert but it's invalid. Closing.");
  193. return -1;
  194. }
  195. router = router_get_by_link_pk(pk);
  196. if (!router) {
  197. log_fn(LOG_WARNING,"Unrecognized public key from peer. Closing.");
  198. crypto_free_pk_env(pk);
  199. return -1;
  200. }
  201. if(crypto_pk_cmp_keys(conn->link_pkey, pk)) {
  202. log_fn(LOG_WARNING,"We connected to '%s' but he gave us a different key. Closing.",
  203. router->nickname);
  204. crypto_free_pk_env(pk);
  205. return -1;
  206. }
  207. log_fn(LOG_DEBUG,"The router's pk matches the one we meant to connect to. Good.");
  208. crypto_free_pk_env(pk);
  209. conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP;
  210. circuit_n_conn_open(conn); /* send the pending create */
  211. }
  212. return 0;
  213. }
  214. /* ********************************** */
  215. void connection_write_cell_to_buf(const cell_t *cellp, connection_t *conn) {
  216. char networkcell[CELL_NETWORK_SIZE];
  217. char *n = networkcell;
  218. cell_pack(n, cellp);
  219. connection_write_to_buf(n, CELL_NETWORK_SIZE, conn);
  220. }
  221. /* if there's a whole cell there, pull it off and process it. */
  222. int connection_process_cell_from_inbuf(connection_t *conn) {
  223. char buf[CELL_NETWORK_SIZE];
  224. cell_t cell;
  225. log_fn(LOG_DEBUG,"%d: starting, inbuf_datalen %d (%d pending in tls object).",
  226. conn->s,buf_datalen(conn->inbuf),tor_tls_get_pending_bytes(conn->tls));
  227. if(buf_datalen(conn->inbuf) < CELL_NETWORK_SIZE) /* entire response available? */
  228. return 0; /* not yet */
  229. connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, conn);
  230. /* retrieve cell info from buf (create the host-order struct from the network-order string) */
  231. cell_unpack(&cell, buf);
  232. command_process_cell(&cell, conn);
  233. return connection_process_inbuf(conn); /* process the remainder of the buffer */
  234. }
  235. /*
  236. Local Variables:
  237. mode:c
  238. indent-tabs-mode:nil
  239. c-basic-offset:2
  240. End:
  241. */