diff options
-rw-r--r-- | src/common/crypto.c | 101 | ||||
-rw-r--r-- | src/common/crypto.h | 14 | ||||
-rw-r--r-- | src/config/routers.or | 13 | ||||
-rw-r--r-- | src/or/circuit.c | 10 | ||||
-rw-r--r-- | src/or/connection.c | 11 | ||||
-rw-r--r-- | src/or/connection_ap.c | 51 | ||||
-rw-r--r-- | src/or/connection_or.c | 15 | ||||
-rw-r--r-- | src/or/main.c | 12 | ||||
-rw-r--r-- | src/or/onion.c | 4 | ||||
-rw-r--r-- | src/or/or.h | 18 | ||||
-rw-r--r-- | src/or/routers.c | 507 | ||||
-rw-r--r-- | src/orkeygen/orkeygen.c | 25 |
12 files changed, 415 insertions, 366 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index 0b1d3d2164..abb3344d2c 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -57,6 +57,7 @@ crypto_pk_env_t *crypto_new_pk_env(int type) return 0; env->type = type; + env->refs = 1; env->key = NULL; env->aux = NULL; @@ -80,6 +81,9 @@ crypto_pk_env_t *crypto_new_pk_env(int type) void crypto_free_pk_env(crypto_pk_env_t *env) { assert(env); + + if(--env->refs > 0) + return; switch(env->type) { case CRYPTO_PK_RSA: @@ -224,7 +228,7 @@ int crypto_pk_generate_key(crypto_pk_env_t *env) return 0; } -int crypto_pk_read_private_key(crypto_pk_env_t *env, FILE *src) +int crypto_pk_read_private_key_from_file(crypto_pk_env_t *env, FILE *src) { assert(env && src); @@ -244,7 +248,7 @@ int crypto_pk_read_private_key(crypto_pk_env_t *env, FILE *src) return 0; } -int crypto_pk_read_private_key_filename(crypto_pk_env_t *env, unsigned char *keyfile) +int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, unsigned char *keyfile) { FILE *f_pr; int retval = 0; @@ -259,7 +263,7 @@ int crypto_pk_read_private_key_filename(crypto_pk_env_t *env, unsigned char *key return -1; /* read the private key */ - retval = crypto_pk_read_private_key(env, f_pr); + retval = crypto_pk_read_private_key_from_file(env, f_pr); fclose(f_pr); if (retval == -1) { @@ -288,15 +292,12 @@ int crypto_pk_read_private_key_filename(crypto_pk_env_t *env, unsigned char *key return -1; /* report error */ } -int crypto_pk_read_public_key(crypto_pk_env_t *env, FILE *src) +int crypto_pk_read_public_key_from_file(crypto_pk_env_t *env, FILE *src) { assert(env && src); switch(env->type) { case CRYPTO_PK_RSA: - /* - if (env->key) - RSA_free((RSA *)env->key);*/ env->key = (unsigned char *)PEM_read_RSAPublicKey(src, (RSA **)&env->key, NULL, NULL); if (!env->key) return -1; @@ -308,7 +309,69 @@ int crypto_pk_read_public_key(crypto_pk_env_t *env, FILE *src) return 0; } -int crypto_pk_write_private_key(crypto_pk_env_t *env, FILE *dest) +int crypto_pk_write_public_key_to_string(crypto_pk_env_t *env, char **dest, int *len) { + BUF_MEM *buf; + BIO *b; + + assert(env && env->key && dest); + + switch(env->type) { + case CRYPTO_PK_RSA: + + b = BIO_new(BIO_s_mem()); /* Create a memory BIO */ + + /* Now you can treat b as if it were a file. Just use the + * * PEM_*_bio_* functions instead of the non-bio variants. + * */ + if(!PEM_write_bio_RSAPublicKey(b, (RSA *)env->key)) + return -1; + + BIO_get_mem_ptr(b, &buf); + BIO_set_close(b, BIO_NOCLOSE); /* so BIO_free doesn't free buf */ + BIO_free(b); + + *dest = malloc(buf->length+1); + if(!*dest) + return -1; + memcpy(*dest, buf->data, buf->length); + (*dest)[buf->length] = 0; /* null terminate it */ + *len = buf->length; + BUF_MEM_free(buf); + + break; + default: + return -1; + } + + return 0; +} + +int crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, char *src, int len) { + BIO *b; + + assert(env && src); + + switch(env->type) { + case CRYPTO_PK_RSA: + b = BIO_new(BIO_s_mem()); /* Create a memory BIO */ + + BIO_write(b, src, len); + + RSA_free((RSA *)env->key); + env->key = (unsigned char *)PEM_read_bio_RSAPublicKey(b, NULL, NULL, NULL); + if(!env->key) + return -1; + + BIO_free(b); + break; + default: + return -1; + } + + return 0; +} + +int crypto_pk_write_private_key_to_file(crypto_pk_env_t *env, FILE *dest) { assert(env && dest); @@ -325,7 +388,7 @@ int crypto_pk_write_private_key(crypto_pk_env_t *env, FILE *dest) return 0; } -int crypto_pk_write_public_key(crypto_pk_env_t *env, FILE *dest) +int crypto_pk_write_public_key_to_file(crypto_pk_env_t *env, FILE *dest) { assert(env && dest); @@ -349,9 +412,9 @@ int crypto_pk_check_key(crypto_pk_env_t *env) switch(env->type) { case CRYPTO_PK_RSA: - return RSA_check_key((RSA *)env->key); + return RSA_check_key((RSA *)env->key); default: - return -1; + return -1; } } @@ -364,6 +427,7 @@ int crypto_pk_set_key(crypto_pk_env_t *env, unsigned char *key) if (!env->key) return -1; memcpy((void *)env->key, (void *)key, sizeof(RSA)); + /* XXX BUG XXX you can't memcpy an RSA, it's got a bunch of subpointers */ break; default : return -1; @@ -402,6 +466,21 @@ int crypto_pk_keysize(crypto_pk_env_t *env) return RSA_size((RSA *)env->key); } + +crypto_pk_env_t *crypto_pk_dup_key(crypto_pk_env_t *env) { + assert(env && env->key); + + switch(env->type) { + case CRYPTO_PK_RSA: + env->refs++; + break; + default: + return NULL; + } + + return env; +} + int crypto_pk_public_encrypt(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to, int padding) { assert(env && from && to); diff --git a/src/common/crypto.h b/src/common/crypto.h index b58b300a4c..71a7a3cf4e 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -18,6 +18,7 @@ typedef struct { int type; + int refs; /* reference counting; so we don't have to copy keys */ unsigned char *key; /* auxiliary data structure(s) used by the underlying crypto library */ unsigned char *aux; @@ -46,15 +47,18 @@ void crypto_free_cipher_env(crypto_cipher_env_t *env); /* public key crypto */ int crypto_pk_generate_key(crypto_pk_env_t *env); -int crypto_pk_read_private_key(crypto_pk_env_t *env, FILE *src); -int crypto_pk_read_public_key(crypto_pk_env_t *env, FILE *src); -int crypto_pk_write_private_key(crypto_pk_env_t *env, FILE *dest); -int crypto_pk_write_public_key(crypto_pk_env_t *env, FILE *dest); +int crypto_pk_read_private_key_from_file(crypto_pk_env_t *env, FILE *src); +int crypto_pk_read_public_key_from_file(crypto_pk_env_t *env, FILE *src); +int crypto_pk_write_public_key_to_string(crypto_pk_env_t *env, char **dest, int *len); +int crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, char *src, int len); +int crypto_pk_write_private_key_to_file(crypto_pk_env_t *env, FILE *dest); +int crypto_pk_write_public_key_to_file(crypto_pk_env_t *env, FILE *dest); int crypto_pk_check_key(crypto_pk_env_t *env); -int crypto_pk_read_private_key_filename(crypto_pk_env_t *env, unsigned char *keyfile); +int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, unsigned char *keyfile); int crypto_pk_set_key(crypto_pk_env_t *env, unsigned char *key); int crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b); +crypto_pk_env_t *crypto_pk_dup_key(crypto_pk_env_t *orig); int crypto_pk_keysize(crypto_pk_env_t *env); int crypto_pk_public_encrypt(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to, int padding); diff --git a/src/config/routers.or b/src/config/routers.or index a9d8f3bda5..de30383db4 100644 --- a/src/config/routers.or +++ b/src/config/routers.or @@ -4,7 +4,7 @@ # router-port is where the router is accepting connections from other routers. # Router 1 -moria.mit.edu 9001 102400 10240 +moria.mit.edu 9001 9011 9021 9031 100000 -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAMBBuk1sYxEg5jLAJy86U3GGJ7EGMSV7yoA6mmcsEVU3pwTUrpbpCmwS 7BvovoY3z4zk63NZVBErgKQUDkn3pp8n83xZgEf4GI27gdWIIwaBjEimuJlEY+7K @@ -12,7 +12,7 @@ nZ7kVMRoiXCbjL6VAtNa4Zy1Af/GOm0iCIDpholeujQ95xew7rQnAgMA//8= -----END RSA PUBLIC KEY----- # Router 2 -moria.mit.edu 9002 102400 10240 +moria.mit.edu 9002 9012 9022 9032 100000 -----BEGIN RSA PUBLIC KEY----- MIGJAoGBANX/HHRuudz274MFSQ4manX8DhtsIuogNUyco9/0dr+XsfioTGd3RgMj aSWlD87arkZO4hHBPHe0q89Z3s1UtUsyQ/VmsxSv9g2OCnF/dU2Nz4h6+Al3iNJF @@ -20,30 +20,31 @@ aSWlD87arkZO4hHBPHe0q89Z3s1UtUsyQ/VmsxSv9g2OCnF/dU2Nz4h6+Al3iNJF -----END RSA PUBLIC KEY----- # Router 3 -moria.mit.edu 9003 102400 10240 +moria.mit.edu 9003 9013 9023 9033 100000 -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAJfkNWCaNkYIRwfHT06KBU6dz8W1xDpW5ezGJwAOoxCX3/ZNoUicb/1V oB3OzW6VxWIiht3da/3K0ywiBOOCcf6BabKoMdiPpH7NIeu6XRmBYK2uqW13gBgh xJbQBb58Nx8Fr05XkvLG6i+vTDY3MZOW3E2/DwSe/jFzuHSD5b3nAgMA//8= -----END RSA PUBLIC KEY----- -town-square.reputation.com 9004 102400 10240 +town-square.reputation.com 9004 9014 9024 9034 100000 -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAKD2BDZQpGq/aAbZ7t+/7qktZVEbhUGe097gIjWH9gXcIOIm0CJMe3rN MsBJsQMi5Uwqrz+Invb5n6bswrNlJp/bCKBhGTvUCfxg7c8xZy71PPSIPnTg1qXl p5fyAkgCYkZNgEEZzQDHv1GRvLCs92kURjSJE5y8QU0dXfbzms8PAgMA//8= -----END RSA PUBLIC KEY----- -moria.mit.edu 9004 102400 10240 +moria.mit.edu 9004 9014 9024 9034 100000 -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAKD2BDZQpGq/aAbZ7t+/7qktZVEbhUGe097gIjWH9gXcIOIm0CJMe3rN MsBJsQMi5Uwqrz+Invb5n6bswrNlJp/bCKBhGTvUCfxg7c8xZy71PPSIPnTg1qXl p5fyAkgCYkZNgEEZzQDHv1GRvLCs92kURjSJE5y8QU0dXfbzms8PAgMA//8= -----END RSA PUBLIC KEY----- -mosg.cl.cam.ac.uk 9005 102400 10240 +mosg.cl.cam.ac.uk 9005 9015 9025 9035 100000 -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAMMHEjhhawM6S14ETFVcvByU7D/baN2JMcCweKKJ7zcSurDnpgRH/Uo7 05+bZE3BCy4OkAqQbGlKd/ejBOuXjEtS0mJo5xwDX9StKguhgFRk60hhrF2OFJm4 VLItXA6U2NLOrc+FBCv/9laLpBrxOb8Wuct0l/lyZ2/OfE9yYhC3AgMA//8= -----END RSA PUBLIC KEY----- + diff --git a/src/or/circuit.c b/src/or/circuit.c index ceb841eb82..bc5bd108c6 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -241,10 +241,14 @@ int circuit_init(circuit_t *circ, int aci_type) { return 0; } -circuit_t *circuit_get_by_naddr_nport(uint32_t naddr, uint16_t nport) { - circuit_t *circ; +circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *circ, uint32_t naddr, uint16_t nport) { - for(circ=global_circuitlist;circ;circ = circ->next) { + if(!circ) /* use circ if it's defined, else start from the beginning */ + circ = global_circuitlist; + else + circ = circ->next; + + for( ;circ;circ = circ->next) { if(circ->n_addr == naddr && circ->n_port == nport) return circ; } diff --git a/src/or/connection.c b/src/or/connection.c index d8f7add2f8..4eeeae0208 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -125,6 +125,11 @@ void connection_free(connection_t *conn) { crypto_free_cipher_env(conn->b_crypto); } + if (conn->pkey) + crypto_free_pk_env(conn->pkey); + if (conn->prkey) + crypto_free_pk_env(conn->prkey); + if(conn->s > 0) { log(LOG_INFO,"connection_free(): closing fd %d.",conn->s); close(conn->s); @@ -175,7 +180,8 @@ int connection_create_listener(crypto_pk_env_t *prkey, struct sockaddr_in *local /* remember things so you can tell the baby sockets */ memcpy(&conn->local,local,sizeof(struct sockaddr_in)); - conn->prkey = prkey; + if(prkey) + conn->prkey = crypto_pk_dup_key(prkey); log(LOG_DEBUG,"connection_create_listener(): Listening on local port %u.",ntohs(local->sin_port)); @@ -214,7 +220,8 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st /* learn things from parent, so we can perform auth */ memcpy(&newconn->local,&conn->local,sizeof(struct sockaddr_in)); - newconn->prkey = conn->prkey; + if(conn->prkey) + newconn->prkey = crypto_pk_dup_key(conn->prkey); newconn->address = strdup(inet_ntoa(remote.sin_addr)); /* remember the remote address */ if(connection_add(newconn) < 0) { /* no space, forget it */ diff --git a/src/or/connection_ap.c b/src/or/connection_ap.c index 838fe737e5..a680f50256 100644 --- a/src/or/connection_ap.c +++ b/src/or/connection_ap.c @@ -191,7 +191,7 @@ int ap_handshake_establish_circuit(connection_t *conn, unsigned int *route, int log(LOG_DEBUG,"ap_handshake_establish_circuit(): Looking for firsthop '%s:%u'", firsthop->address,firsthop->or_port); n_conn = connection_twin_get_by_addr_port(firsthop->addr,firsthop->or_port); - if(!n_conn) { /* not currently connected */ + if(!n_conn || n_conn->state != OR_CONN_STATE_OPEN) { /* not currently connected */ circ->n_addr = firsthop->addr; circ->n_port = firsthop->or_port; if(global_role & ROLE_OR_CONNECT_ALL) { /* we would be connected if he were up. but he's not. */ @@ -199,14 +199,15 @@ int ap_handshake_establish_circuit(connection_t *conn, unsigned int *route, int circuit_close(circ); return -1; } - - /* ok, launch the connection */ - n_conn = connect_to_router_as_op(firsthop); - if(!n_conn) { /* connect failed, forget the whole thing */ - log(LOG_DEBUG,"ap_handshake_establish_circuit(): connect to firsthop failed. Closing."); - circuit_close(circ); - return -1; - } + + if(!n_conn) { /* launch the connection */ + n_conn = connect_to_router_as_op(firsthop); + if(!n_conn) { /* connect failed, forget the whole thing */ + log(LOG_DEBUG,"ap_handshake_establish_circuit(): connect to firsthop failed. Closing."); + circuit_close(circ); + return -1; + } + } conn->state = AP_CONN_STATE_OR_WAIT; connection_stop_reading(conn); /* Stop listening for input from the AP! */ return 0; /* return success. The onion/circuit/etc will be taken care of automatically @@ -219,21 +220,31 @@ int ap_handshake_establish_circuit(connection_t *conn, unsigned int *route, int } } -/* find the circ that's waiting on me, if any, and get it to send its onion */ -int ap_handshake_n_conn_open(connection_t *or_conn) { +/* find circuits that are waiting on me, if any, and get them to send the onion */ +void ap_handshake_n_conn_open(connection_t *or_conn) { circuit_t *circ; + connection_t *p_conn; log(LOG_DEBUG,"ap_handshake_n_conn_open(): Starting."); - circ = circuit_get_by_naddr_nport(or_conn->addr, or_conn->port); - if(!circ) - return 0; /* i'm ok with that. no need to close the connection or anything. */ - - if(circ->p_conn->state != AP_CONN_STATE_OR_WAIT) { - log(LOG_DEBUG,"Bug: ap_handshake_n_conn_open() got an ap_conn not in OR_WAIT state."); + circ = circuit_enumerate_by_naddr_nport(NULL, or_conn->addr, or_conn->port); + for(;;) { + if(!circ) + return; + + p_conn = circ->p_conn; + if(p_conn->state != AP_CONN_STATE_OR_WAIT) { + log(LOG_WARNING,"Bug: ap_handshake_n_conn_open() got an ap_conn not in OR_WAIT state."); + } + connection_start_reading(p_conn); /* resume listening for reads */ + log(LOG_DEBUG,"ap_handshake_n_conn_open(): Found circ, sending onion."); + if(ap_handshake_send_onion(p_conn, or_conn, circ)<0) { + log(LOG_DEBUG,"ap_handshake_n_conn_open(): circuit marked for closing."); + p_conn->marked_for_close = 1; + return; /* XXX will want to try the rest too */ + } else { + circ = circuit_enumerate_by_naddr_nport(circ, or_conn->addr, or_conn->port); + } } - connection_start_reading(circ->p_conn); /* resume listening for reads */ - log(LOG_DEBUG,"ap_handshake_n_conn_open(): Found circ, sending onion."); - return ap_handshake_send_onion(circ->p_conn, or_conn, circ); } int ap_handshake_send_onion(connection_t *ap_conn, connection_t *n_conn, circuit_t *circ) { diff --git a/src/or/connection_or.c b/src/or/connection_or.c index c16296a615..53bf38837b 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -154,9 +154,10 @@ connection_t *connection_or_connect(routerinfo_t *router, crypto_pk_env_t *prkey /* set up conn so it's got all the data we need to remember */ conn->addr = router->addr, conn->port = router->or_port; /* NOTE we store or_port here always */ - conn->prkey = prkey; - conn->bandwidth = router->min; /* kludge, should make a router->bandwidth and use that */ - conn->pkey = router->pkey; + if(prkey) + conn->prkey = crypto_pk_dup_key(prkey); + conn->bandwidth = router->bandwidth; + conn->pkey = crypto_pk_dup_key(router->pkey); conn->address = strdup(router->address); memcpy(&conn->local,local,sizeof(struct sockaddr_in)); @@ -331,8 +332,8 @@ int or_handshake_op_finished_sending_keys(connection_t *conn) { conn->state = OR_CONN_STATE_OPEN; connection_init_timeval(conn); connection_watch_events(conn, POLLIN); /* give it a default, tho the ap_handshake call may change it */ - return ap_handshake_n_conn_open(conn); /* send the pending onion */ - + ap_handshake_n_conn_open(conn); /* send the pending onions */ + return 0; } /* @@ -601,14 +602,14 @@ int or_handshake_server_process_auth(connection_t *conn) { /* update link info */ bandwidth = ntohl(*(uint32_t *)(buf+28)); - conn->bandwidth = router->min; /* FIXME, should make a router->bandwidth and use that */ + conn->bandwidth = router->bandwidth; if (conn->bandwidth > bandwidth) conn->bandwidth = bandwidth; /* copy all relevant info to conn */ conn->addr = router->addr, conn->port = router->or_port; - conn->pkey = router->pkey; + conn->pkey = crypto_pk_dup_key(router->pkey); conn->address = strdup(router->address); /* generate a nonce */ diff --git a/src/or/main.c b/src/or/main.c index ab3238a02d..ccf98f6551 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -87,12 +87,6 @@ int connection_remove(connection_t *conn) { return 0; } -int pkey_cmp(crypto_pk_env_t *a, crypto_pk_env_t *b) { - /* return 0 if a and b are "the same key". Return non-0 otherwise. */ - - return crypto_pk_cmp_keys(a, b); -} - connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port) { /* Find a connection to the router described by addr and port, * or alternately any router which knows its key. @@ -119,7 +113,7 @@ connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port) { for(i=0;i<nfds;i++) { conn = connection_array[i]; assert(conn); - if(connection_state_is_open(conn) && !pkey_cmp(conn->pkey, router->pkey)) { + if(connection_state_is_open(conn) && !crypto_pk_cmp_keys(conn->pkey, router->pkey)) { log(LOG_INFO,"connection_twin_get_by_addr_port(): Found twin (%s).",conn->address); return conn; } @@ -412,7 +406,7 @@ int do_main_loop(void) { int poll_result; /* load the routers file */ - router_array = getrouters(options.RouterFile,&rarray_len, options.ORPort); + router_array = router_get_list_from_file(options.RouterFile,&rarray_len, options.ORPort); if (!router_array) { log(LOG_ERR,"Error loading router list."); @@ -426,7 +420,7 @@ int do_main_loop(void) { log(LOG_ERR,"Error creating a crypto environment."); return -1; } - if (crypto_pk_read_private_key_filename(prkey, options.PrivateKeyFile)) + if (crypto_pk_read_private_key_from_filename(prkey, options.PrivateKeyFile)) { log(LOG_ERR,"Error loading private key."); return -1; diff --git a/src/or/onion.c b/src/or/onion.c index 52b785bb09..f1b6357590 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -118,7 +118,7 @@ unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *r goto next_i_loop; } for(j=0;j<i;j++) { - if(!pkey_cmp(rarray[i]->pkey, rarray[j]->pkey)) { + if(!crypto_pk_cmp_keys(rarray[i]->pkey, rarray[j]->pkey)) { /* these guys are twins. so we've already counted him. */ log(LOG_DEBUG,"Nope, %d is a twin of %d.",i,j); goto next_i_loop; @@ -158,7 +158,7 @@ unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *r choice = choice % (rarray_len); log(LOG_DEBUG,"new_route(): Contemplating router %u.",choice); if(choice == oldchoice || - (oldchoice < rarray_len && !pkey_cmp(rarray[choice]->pkey, rarray[oldchoice]->pkey)) || + (oldchoice < rarray_len && !crypto_pk_cmp_keys(rarray[choice]->pkey, rarray[oldchoice]->pkey)) || ((global_role & ROLE_OR_CONNECT_ALL) && !connection_twin_get_by_addr_port(rarray[choice]->addr, rarray[choice]->or_port))) { /* Same router as last choice, or router twin, * or no routers with that key are connected to us. diff --git a/src/or/or.h b/src/or/or.h index d6c051b3c7..dc39956c19 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -30,6 +30,7 @@ #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/stat.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> @@ -244,12 +245,13 @@ typedef struct uint16_t or_port; uint16_t op_port; uint16_t ap_port; + uint16_t dir_port; crypto_pk_env_t *pkey; /* public RSA key */ /* link info */ - uint32_t min; - uint32_t max; + uint32_t bandwidth; + // struct timeval min_interval; /* time when last data was sent to that router */ @@ -392,7 +394,7 @@ aci_t get_unique_aci_by_addr_port(uint32_t addr, uint16_t port, int aci_type); circuit_t *circuit_get_by_aci_conn(aci_t aci, connection_t *conn); circuit_t *circuit_get_by_conn(connection_t *conn); -circuit_t *circuit_get_by_naddr_nport(uint32_t naddr, uint16_t nport); +circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *start, uint32_t naddr, uint16_t nport); int circuit_deliver_data_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int crypt_type); int circuit_crypt(circuit_t *circ, char *in, int inlen, char crypt_type); @@ -487,8 +489,7 @@ int ap_handshake_create_onion(connection_t *conn); int ap_handshake_establish_circuit(connection_t *conn, unsigned int *route, int routelen, char *onion, int onionlen, crypt_path_t **cpath); -/* find the circ that's waiting on me, if any, and get it to send its onion */ -int ap_handshake_n_conn_open(connection_t *or_conn); +void ap_handshake_n_conn_open(connection_t *or_conn); int ap_handshake_send_onion(connection_t *ap_conn, connection_t *or_conn, circuit_t *circ); @@ -553,7 +554,6 @@ int connection_add(connection_t *conn); int connection_remove(connection_t *conn); void connection_set_poll_socket(connection_t *conn); -int pkey_cmp(crypto_pk_env_t *a, crypto_pk_env_t *b); connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port); connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port); @@ -625,10 +625,6 @@ tracked_onion_t *id_tracked_onion(unsigned char *onion, uint32_t onionlen, track /********************************* routers.c ***************************/ -routerinfo_t **getrouters(char *routerfile, int *listlenp, uint16_t or_listenport); -void delete_routerlist(routerinfo_t *list); -/* create an NULL-terminated array of pointers pointing to elements of a router list */ -routerinfo_t **make_rarray(routerinfo_t* list, int *len); - +routerinfo_t **router_get_list_from_file(char *routerfile, int *len, uint16_t or_listenport); #endif diff --git a/src/or/routers.c b/src/or/routers.c index 6838b13c7d..4f9b0846ea 100644 --- a/src/or/routers.c +++ b/src/or/routers.c @@ -9,13 +9,20 @@ * Matej Pfajfar <mp292@cam.ac.uk> */ -#define OR_ROUTERLIST_SEPCHARS " \t\n" -#define OR_PUBLICKEY_BEGIN_TAG "-----BEGIN RSA PUBLIC KEY-----\n" +#define OR_PUBLICKEY_END_TAG "-----END RSA PUBLIC KEY-----\n" #include "or.h" extern int global_role; /* from main.c */ +/* static function prototypes */ +static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport); +static void routerlist_free(routerinfo_t *list); +static routerinfo_t **make_rarray(routerinfo_t* list, int *len); +static char *eat_whitespace(char *s); +static char *find_whitespace(char *s); +static routerinfo_t *router_get_entry_from_string(char **s); + /* private function, to determine whether the current entry in the router list is actually us */ static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport) { @@ -35,12 +42,12 @@ static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my /* obtain local host information */ if (gethostname(localhostname,512) < 0) { - log(LOG_ERR,"Error obtaining local hostname."); + log(LOG_ERR,"router_is_me(): Error obtaining local hostname."); return -1; } localhost = gethostbyname(localhostname); if (!localhost) { - log(LOG_ERR,"Error obtaining local host info."); + log(LOG_ERR,"router_is_me(): Error obtaining local host info."); return -1; } @@ -71,7 +78,7 @@ static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my } /* delete a list of routers from memory */ -void delete_routerlist(routerinfo_t *list) +static void routerlist_free(routerinfo_t *list) { routerinfo_t *tmp = NULL; @@ -91,10 +98,17 @@ void delete_routerlist(routerinfo_t *list) return; } +void rarray_free(routerinfo_t **list) { + if(!list) + return; + routerlist_free(*list); + free(list); +} + /* create a NULL-terminated array of pointers pointing to elements of a router list */ /* this is done in two passes through the list - inefficient but irrelevant as this is * only done once when op/or start up */ -routerinfo_t **make_rarray(routerinfo_t* list, int *len) +static routerinfo_t **make_rarray(routerinfo_t* list, int *len) { routerinfo_t *tmp=NULL; int listlen = 0; @@ -135,303 +149,220 @@ routerinfo_t **make_rarray(routerinfo_t* list, int *len) return array; } + /* load the router list */ -routerinfo_t **getrouters(char *routerfile, int *len, uint16_t or_listenport) +routerinfo_t **router_get_list_from_file(char *routerfile, int *len, uint16_t or_listenport) { - int retval = 0; - char *retp = NULL; - routerinfo_t *router=NULL, *routerlist=NULL, *lastrouter=NULL; - FILE *rf; /* router file */ - fpos_t fpos; - char line[512]; - char *token; - char *errtest; /* detecting errors in strtoul() calls */ - struct hostent *rent; + routerinfo_t *routerlist=NULL; + routerinfo_t *router; + int fd; /* router file */ + struct stat statbuf; + char *string; + char *tmps; assert(routerfile && len); if (strcspn(routerfile,CONFIG_LEGAL_FILENAME_CHARACTERS) != 0) { - log(LOG_ERR,"Filename %s contains illegal characters.",routerfile); + log(LOG_ERR,"router_get_list_from_file(): Filename %s contains illegal characters.",routerfile); return NULL; } + if(stat(routerfile, &statbuf) < 0) { + log(LOG_ERR,"router_get_list_from_file(): Could not stat %s.",routerfile); + return NULL; + } + /* open the router list */ - rf = fopen(routerfile,"r"); - if (!rf) { - log(LOG_ERR,"Could not open %s.",routerfile); + fd = open(routerfile,O_RDONLY,0); + if (fd<0) { + log(LOG_ERR,"router_get_list_from_file(): Could not open %s.",routerfile); + return NULL; + } + + string = malloc(statbuf.st_size+1); + if(!string) { + log(LOG_ERR,"router_get_list_from_file(): Out of memory."); + return NULL; + } + + if(read(fd,string,statbuf.st_size) != statbuf.st_size) { + log(LOG_ERR,"router_get_list_from_file(): Couldn't read all %d bytes of file '%s'.",statbuf.st_size,routerfile); return NULL; } + close(fd); - retp = fgets(line,512,rf); - while (retp) { - log(LOG_DEBUG,"getrouters():Line :%s",line); - token = (char *)strtok(line,OR_ROUTERLIST_SEPCHARS); - if (token) - { - log(LOG_DEBUG,"getrouters():Token : %s",token); - if (token[0] != '#') /* ignore comment lines */ - { - router = malloc(sizeof(routerinfo_t)); - if (!router) - { - log(LOG_ERR,"Could not allocate memory."); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - - /* read the address */ - router->address = malloc(strlen(token)+1); - if (!router->address) - { - log(LOG_ERR,"Could not allocate memory."); - fclose(rf); - free((void *)router); - delete_routerlist(routerlist); - return NULL; - } - strcpy(router->address,token); - - rent = (struct hostent *)gethostbyname(router->address); - if (!rent) - { - log(LOG_ERR,"Could not get address for router %s.",router->address); - fclose(rf); - free((void *)router->address); - free((void *)router); - delete_routerlist(routerlist); - return NULL; - } - - memcpy(&router->addr, rent->h_addr,rent->h_length); - - /* read the port */ - token = (char *)strtok(NULL,OR_ROUTERLIST_SEPCHARS); - if (token) - { - log(LOG_DEBUG,"getrouters():Token :%s",token); - router->or_port = (uint16_t)strtoul(token,&errtest,0); - if ((*token != '\0') && (*errtest == '\0')) /* conversion was successful */ - { -/* FIXME patch from RD. We should make it actually read these. */ - router->op_port = router->or_port + 10; - router->ap_port = router->or_port + 20; - - /* read min bandwidth */ - token = (char *)strtok(NULL,OR_ROUTERLIST_SEPCHARS); - if (token) /* min bandwidth */ - { - router->min = (uint32_t)strtoul(token,&errtest,0); - if ((*token != '\0') && (*errtest == '\0')) /* conversion was successful */ - { - if (router->min) /* must not be zero */ - { - /* read max bandwidth */ - token = (char *)strtok(NULL,OR_ROUTERLIST_SEPCHARS); - if (token) /* max bandwidth */ - { - router->max = (uint32_t)strtoul(token,&errtest,0); - if ((*token != '\0') && (*errtest == '\0')) /* conversion was successful */ - { - if (router->max) /* must not be zero */ - { - /* check that there is a public key entry for that router */ - retval = fgetpos(rf, &fpos); /* save the current file position - * we wil return to it later if we find a public key */ - if (retval == -1) - { - log(LOG_ERR,"Could not save position in %s.",routerfile); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - do /* read through to the next non-empty line */ - { - retp=fgets(line,512,rf); - if (!retp) - { - log(LOG_ERR,"Could not find a public key entry for router %s:%u.", - router->address,router->or_port); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - log(LOG_DEBUG,"getrouters():Line:%s",line); - if ((*line != '#') && ( strspn(line,OR_ROUTERLIST_SEPCHARS) != strlen(line) )) - { - break; - } - } while (1); - - if (!strcmp(line,OR_PUBLICKEY_BEGIN_TAG)) /* we've got the public key */ - { - retval = fsetpos(rf,&fpos); /* get us back to where we were otherwise crypto lib won't find the key */ - if (retval == -1) - { - log(LOG_ERR,"Could not set position in %s.",routerfile); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } - else /* we found something else; this isn't right */ - { - log(LOG_ERR,"Could not find a public key entry for router %s:%u.", - router->address,router->or_port); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - - log(LOG_DEBUG,"getrouters():Reading the key ..."); - /* read the public key into router->pkey */ - router->pkey = crypto_new_pk_env(CRYPTO_PK_RSA); - if (crypto_pk_read_public_key(router->pkey, rf)) /* something went wrong */ - { - log(LOG_ERR,"Could not read public key for router %s:%u.", - router->address,router->or_port); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - else /* read the key */ - { - log(LOG_DEBUG,"getrouters():Public key size = %u.", crypto_pk_keysize(router->pkey)); - if (crypto_pk_keysize(router->pkey) != 128) /* keys MUST be 1024 bits in size */ - { - log(LOG_ERR,"Key for router %s:%u is not 1024 bits. All keys must be exactly 1024 bits long.",router->address,router->or_port); - free((void *)router->address); - crypto_free_pk_env(router->pkey); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - - /* check that this router doesn't actually represent us */ - retval = router_is_me(router->addr, router->or_port, or_listenport); - if (!retval) { /* this isn't us, continue */ - router->next = NULL; - /* save the entry into the routerlist linked list */ - if (!routerlist) /* this is the first entry */ - routerlist = router; - else - lastrouter->next = (void *)router; - lastrouter = router; - } - else if (retval == 1) /* this is us, ignore */ - { - log(LOG_DEBUG,"getrouters(): This entry is actually me. Ignoring."); - free((void *)router->address); - crypto_free_pk_env(router->pkey); - free((void *)router); - } - else /* router_is_me() returned an error */ - { - free((void *)router->address); - crypto_free_pk_env(router->pkey); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } - } - else /* maximum link utilisation is zero */ - { - log(LOG_ERR,"Entry for router %s doesn't contain a valid maximum bandwidth entry (must be > 0).",router->address); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } - else - { - log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid maximum bandwidth entry.",router->address); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } - else - { - log(LOG_ERR,"Entry for router %s doesn't seem to contain a maximum bandwidth entry.",router->address); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } - else - { - log(LOG_ERR,"Entry for router %s doesn't contain a valid minimum bandwidth entry (must be > 0).",router->address); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } - else - { - log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid minimum bandwidth entry.",router->address); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } - else - { - log(LOG_ERR,"Entry for router %s doesn't seem to contain a minimum bandwidth entry.",router->address); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } - else - { - log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid port number.",router->address); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } - else - { - log(LOG_ERR,"Entry for router %s doesn't seem to contain a port number.",router->address); - free((void *)router->address); - free((void *)router); - fclose(rf); - delete_routerlist(routerlist); - return NULL; - } - } + string[statbuf.st_size] = 0; /* null terminate it */ + tmps = string; + while(*tmps) { /* while not at the end of the string */ + router = router_get_entry_from_string(&tmps); + if(router == NULL) { + routerlist_free(routerlist); + free(string); + return NULL; + } + if(!router_is_me(router->addr, router->or_port, or_listenport)) { + router->next = routerlist; + routerlist = router; } - retp=fgets(line,512,rf); + tmps = eat_whitespace(tmps); } - - fclose(rf); + free(string); return make_rarray(routerlist, len); +} + +/* return the first char of s that is not whitespace and not a comment */ +static char *eat_whitespace(char *s) { + assert(s); + + while(isspace(*s) || *s == '#') { + while(isspace(*s)) + s++; + if(*s == '#') { /* read to a \n or \0 */ + while(*s && *s != '\n') + s++; + if(!*s) + return s; + } + } + return s; +} + +/* return the first char of s that is whitespace or '#' or '\0 */ +static char *find_whitespace(char *s) { + assert(s); + + while(*s && !isspace(*s) && *s != '#') + s++; + + return s; +} + +/* reads a single router entry from s. + * updates s so it points to after the router it just read. + * mallocs a new router, returns it if all goes well, else returns NULL. + */ +static routerinfo_t *router_get_entry_from_string(char **s) { + routerinfo_t *router; + char *next; + struct hostent *rent; + + router = malloc(sizeof(routerinfo_t)); + if (!router) { + log(LOG_ERR,"router_get_entry_from_string(): Could not allocate memory."); + return NULL; + } + memset(router,0,sizeof(routerinfo_t)); /* zero it out first */ + +#define NEXT_TOKEN(s, next) \ + *s = eat_whitespace(*s); \ + next = find_whitespace(*s); \ + if(!*next) { \ + goto router_read_failed; \ + } \ + *next = 0; + + /* read router->address */ + NEXT_TOKEN(s, next); + router->address = strdup(*s); + *s = next+1; + + rent = (struct hostent *)gethostbyname(router->address); + if (!rent) { + log(LOG_ERR,"router_get_entry_from_string(): Could not get address for router %s.",router->address); + goto router_read_failed; + } + assert(rent->h_length == 4); + memcpy(&router->addr, rent->h_addr,rent->h_length); + + /* read router->or_port */ + NEXT_TOKEN(s, next); + router->or_port = atoi(*s); + if(!router->or_port) { + log(LOG_ERR,"router_get_entry_from_string(): or_port '%s' unreadable or 0. Failing.",*s); + goto router_read_failed; + } + *s = next+1; + + /* read router->op_port */ + NEXT_TOKEN(s, next); + router->op_port = atoi(*s); + *s = next+1; + + /* read router->ap_port */ + NEXT_TOKEN(s, next); + router->ap_port = atoi(*s); + *s = next+1; + + /* read router->dir_port */ + NEXT_TOKEN(s, next); + router->dir_port = atoi(*s); + *s = next+1; + + /* read router->bandwidth */ + NEXT_TOKEN(s, next); + router->bandwidth = atoi(*s); + if(!router->bandwidth) { + log(LOG_ERR,"router_get_entry_from_string(): bandwidth '%s' unreadable or 0. Failing.",*s); + goto router_read_failed; + } + *s = next+1; + + log(LOG_DEBUG,"or_port %d, op_port %d, ap_port %d, dir_port %d, bandwidth %d.", + router->or_port, router->op_port, router->ap_port, router->dir_port, router->bandwidth); + + *s = eat_whitespace(*s); + next = strstr(*s,OR_PUBLICKEY_END_TAG); + router->pkey = crypto_new_pk_env(CRYPTO_PK_RSA); + if(!next || !router->pkey) { + log(LOG_ERR,"router_get_entry_from_string(): Couldn't find pk in string"); + goto router_read_failed; + } + + /* now advance *s so it's at the end of this router entry */ + next = strchr(next, '\n'); + assert(next); /* can't fail, we just checked it was here */ + *next = 0; + log(LOG_DEBUG,"Key about to be read is: '%s'",*s); + if((crypto_pk_read_public_key_from_string(router->pkey, *s, strlen(*s))<0)) { + log(LOG_ERR,"router_get_entry_from_string(): Couldn't read pk from string"); + goto router_read_failed; + } + log(LOG_DEBUG,"router_get_entry_from_string(): Public key size = %u.", crypto_pk_keysize(router->pkey)); + + if (crypto_pk_keysize(router->pkey) != 128) { /* keys MUST be 1024 bits in size */ + log(LOG_ERR,"Key for router %s:%u is not 1024 bits. All keys must be exactly 1024 bits long.", + router->address,router->or_port); + goto router_read_failed; + } + +// test_write_pkey(router->pkey); + + *s = next+1; + + /* success */ + return(router); + +router_read_failed: + if(router->address) + free(router->address); + if(router->pkey) + crypto_free_pk_env(router->pkey); + free(router); + return NULL; +} + +#if 0 +void test_write_pkey(crypto_pk_env_t *pkey) { + char *string; + int len; + + log(LOG_DEBUG,"Trying test write."); + if(crypto_pk_write_public_key_to_string(pkey,&string,&len)<0) { + log(LOG_DEBUG,"router_get_entry_from_string(): write pkey to string failed\n"); + return; + } + log(LOG_DEBUG,"I did it: len %d, string '%s'.",len,string); + free(string); } +#endif diff --git a/src/orkeygen/orkeygen.c b/src/orkeygen/orkeygen.c index 8e4c87fff5..d26a9237e0 100644 --- a/src/orkeygen/orkeygen.c +++ b/src/orkeygen/orkeygen.c @@ -8,6 +8,20 @@ /* * Changes : * $Log$ + * Revision 1.3 2002/09/24 10:43:57 arma + * laying the groundwork for dynamic router lists + * + * revamped the router reading section + * + * reference counting for crypto pk env's (so we can dup them) + * + * we now read and write pem pk keys from string rather than from FILE*, + * in anticipation of fetching directories over a socket + * (so now on startup we slurp in the whole file, then parse it as a string) + * + * fixed a bug in the proxy side, where you could get some circuits + * wedged if they showed up while the connection was being made + * * Revision 1.2 2002/07/25 08:18:05 badbytes * Updated to use crypto.h instead of OpenSSL. * @@ -20,6 +34,13 @@ * */ +/* likely obsoleted by: + * + * openssl genrsa -out private.pem 1024 + * openssl rsa -in private.pem -pubout -out public.pem + * + */ + #include <stdlib.h> #include <stdio.h> @@ -84,7 +105,7 @@ int main(int argc, char *argv[]) } /* write the private key */ - if (crypto_pk_write_private_key(env, f_pr) == -1) + if (crypto_pk_write_private_key_to_file(env, f_pr) == -1) { printf("%s",crypto_perror()); fclose(f_pr); @@ -94,7 +115,7 @@ int main(int argc, char *argv[]) } /* write the public key */ - if (crypto_pk_write_public_key(env, f_pu) == -1) + if (crypto_pk_write_public_key_to_file(env, f_pu) == -1) { printf("%s",crypto_perror()); fclose(f_pr); |