connection_or.c 8.8 KB

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