aboutsummaryrefslogtreecommitdiff
path: root/src/or/routers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/routers.c')
-rw-r--r--src/or/routers.c233
1 files changed, 152 insertions, 81 deletions
diff --git a/src/or/routers.c b/src/or/routers.c
index 6341d335f1..24baa5a340 100644
--- a/src/or/routers.c
+++ b/src/or/routers.c
@@ -28,10 +28,6 @@ static char *eat_whitespace(char *s);
static char *eat_whitespace_no_nl(char *s);
static char *find_whitespace(char *s);
static void router_free_exit_policy(routerinfo_t *router);
-static routerinfo_t *router_get_entry_from_string_tok(char**s,
- directory_token_t *tok);
-static int router_get_list_from_string_tok(char **s, directory_t **dest,
- directory_token_t *tok);
static int router_add_exit_policy(routerinfo_t *router,
directory_token_t *tok);
static int
@@ -119,7 +115,7 @@ routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
return NULL;
}
-routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk)
+routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk)
{
int i;
routerinfo_t *router;
@@ -128,14 +124,32 @@ routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk)
for(i=0;i<directory->n_routers;i++) {
router = directory->routers[i];
- /* XXX Should this really be a separate link key? */
- if (0 == crypto_pk_cmp_keys(router->pkey, pk))
+ if (0 == crypto_pk_cmp_keys(router->link_pkey, pk))
return router;
}
return NULL;
}
+
+#if 0
+routerinfo_t *router_get_by_identity_pk(crypto_pk_env_t *pk)
+{
+ int i;
+ routerinfo_t *router;
+
+ assert(directory);
+
+ for(i=0;i<directory->n_routers;i++) {
+ router = directory->routers[i];
+ /* XXX Should this really be a separate link key? */
+ if (0 == crypto_pk_cmp_keys(router->identity_pkey, pk))
+ return router;
+ }
+ return NULL;
+}
+#endif
+
void router_get_directory(directory_t **pdirectory) {
*pdirectory = directory;
@@ -174,10 +188,12 @@ void routerinfo_free(routerinfo_t *router)
if (router->address)
free(router->address);
- if (router->pkey)
- crypto_free_pk_env(router->pkey);
- if (router->signing_pkey)
- crypto_free_pk_env(router->signing_pkey);
+ if (router->onion_pkey)
+ crypto_free_pk_env(router->onion_pkey);
+ if (router->link_pkey)
+ crypto_free_pk_env(router->link_pkey);
+ if (router->identity_pkey)
+ crypto_free_pk_env(router->identity_pkey);
e = router->exit_policy;
while (e) {
etmp = e->next;
@@ -195,7 +211,8 @@ void directory_free(directory_t *directory)
int i;
for (i = 0; i < directory->n_routers; ++i)
routerinfo_free(directory->routers[i]);
- free(directory->routers);
+ if (directory->routers)
+ free(directory->routers);
if(directory->software_versions)
free(directory->software_versions);
free(directory);
@@ -282,6 +299,9 @@ typedef enum {
K_ROUTER,
K_SIGNED_DIRECTORY,
K_SIGNING_KEY,
+ K_ONION_KEY,
+ K_LINK_KEY,
+ K_ROUTER_SIGNATURE,
_SIGNATURE,
_PUBLIC_KEY,
_ERR,
@@ -298,6 +318,9 @@ static struct token_table_ent token_table[] = {
{ "recommended-software", K_RECOMMENDED_SOFTWARE },
{ "signed-directory", K_SIGNED_DIRECTORY },
{ "signing-key", K_SIGNING_KEY },
+ { "onion-key", K_ONION_KEY },
+ { "link-key", K_LINK_KEY },
+ { "router-signature", K_ROUTER_SIGNATURE },
{ NULL, -1 }
};
@@ -450,6 +473,9 @@ router_dump_token(directory_token_t *tok) {
case K_ROUTER: printf("Router"); break;
case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break;
case K_SIGNING_KEY: printf("Signing-Key"); break;
+ case K_ONION_KEY: printf("Onion-key"); break;
+ case K_LINK_KEY: printf("Link-key"); break;
+ case K_ROUTER_SIGNATURE: printf("Router-signature"); break;
default:
printf("?????? %d\n", tok->tp); return;
}
@@ -459,7 +485,6 @@ router_dump_token(directory_token_t *tok) {
printf("\n");
return;
}
-
static int
router_get_next_token(char **s, directory_token_t *tok) {
int i;
@@ -508,7 +533,7 @@ static char *find_whitespace(char *s) {
int router_get_list_from_string(char *s)
{
- if (router_get_list_from_string_impl(s, &directory)) {
+ if (router_get_list_from_string_impl(&s, &directory)) {
log(LOG_ERR, "Error parsing router file");
return -1;
}
@@ -519,43 +544,46 @@ int router_get_list_from_string(char *s)
return 0;
}
-int router_get_list_from_string_impl(char *s, directory_t **dest) {
- directory_token_t tok;
- if (router_get_next_token(&s, &tok)) {
- log(LOG_ERR, "Error reading routers: %s", tok.val.error);
- return -1;
- }
- return router_get_list_from_string_tok(&s, dest, &tok);
-}
-
-static int router_get_dir_hash(char *s, char *digest)
+static int router_get_hash_impl(char *s, char *digest, const char *start_str,
+ const char *end_str)
{
char *start, *end;
- start = strstr(s, "signed-directory");
+ start = strstr(s, start_str);
if (!start) {
- log(LOG_ERR,"router_get_dir_hash(): couldn't find \"signed-directory\"");
+ log_fn(LOG_ERR,"couldn't find \"%s\"",start_str);
return -1;
}
- end = strstr(start, "directory-signature");
+ end = strstr(start+strlen(start_str), end_str);
if (!end) {
- log(LOG_ERR,"router_get_dir_hash(): couldn't find \"directory-signature\"");
+ log_fn(LOG_ERR,"couldn't find \"%s\"",end_str);
return -1;
}
end = strchr(end, '\n');
if (!end) {
- log(LOG_ERR,"router_get_dir_hash(): couldn't find EOL");
+ log_fn(LOG_ERR,"couldn't find EOL");
return -1;
}
++end;
if (crypto_SHA_digest(start, end-start, digest)) {
- log(LOG_ERR,"router_get_dir_hash(): couldn't compute digest");
+ log_fn(LOG_ERR,"couldn't compute digest");
return -1;
}
return 0;
}
+static int router_get_dir_hash(char *s, char *digest)
+{
+ return router_get_hash_impl(s,digest,
+ "signed-directory","directory-signature");
+}
+int router_get_router_hash(char *s, char *digest)
+{
+ return router_get_hash_impl(s,digest,
+ "router ","router-signature");
+}
+
/* return 0 if myversion is in start. Else return -1. */
int compare_recommended_versions(char *myversion, char *start) {
int len_myversion = strlen(myversion);
@@ -621,12 +649,11 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest,
log(LOG_ERR, "Error reading directory: expected %s", name); \
return -1; \
} } while(0)
-
+
if (router_get_dir_hash(s, digest)) {
log(LOG_ERR, "Unable to compute digest of directory");
- return -1;
+ goto err;
}
-
NEXT_TOK();
TOK_IS(K_SIGNED_DIRECTORY, "signed-directory");
@@ -634,17 +661,17 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest,
TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software");
if (tok.val.cmd.n_args != 1) {
log(LOG_ERR, "Invalid recommded-software line");
- return -1;
+ goto err;
}
versions = strdup(tok.val.cmd.args[0]);
- NEXT_TOK();
- if (router_get_list_from_string_tok(&s, &new_dir, &tok)) {
+ if (router_get_list_from_string_impl(&s, &new_dir)) {
log(LOG_ERR, "Error reading routers from directory");
- return -1;
+ goto err;
}
new_dir->software_versions = versions;
-
+
+ NEXT_TOK();
TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature");
NEXT_TOK();
TOK_IS(_SIGNATURE, "signature");
@@ -653,12 +680,12 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest,
!= 20) {
log(LOG_ERR, "Error reading directory: invalid signature.");
free(tok.val.signature);
- return -1;
+ goto err;
}
if (memcmp(digest, signed_digest, 20)) {
log(LOG_ERR, "Error reading directory: signature does not match.");
free(tok.val.signature);
- return -1;
+ goto err;
}
}
free(tok.val.signature);
@@ -671,12 +698,16 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest,
*dest = new_dir;
return 0;
+
+ err:
+ if (new_dir)
+ directory_free(new_dir);
+ return -1;
#undef NEXT_TOK
#undef TOK_IS
}
-static int router_get_list_from_string_tok(char **s, directory_t **dest,
- directory_token_t *tok)
+int router_get_list_from_string_impl(char **s, directory_t **dest)
{
routerinfo_t *router;
routerinfo_t **rarray;
@@ -686,8 +717,11 @@ static int router_get_list_from_string_tok(char **s, directory_t **dest,
rarray = (routerinfo_t **)tor_malloc((sizeof(routerinfo_t *))*MAX_ROUTERS_IN_DIR);
- while (tok->tp == K_ROUTER) {
- router = router_get_entry_from_string_tok(s, tok);
+ while (1) {
+ *s = eat_whitespace(*s);
+ if (strncmp(*s, "router ", 7)!=0)
+ break;
+ router = router_get_entry_from_string(s);
if (!router) {
log(LOG_ERR, "Error reading router");
return -1;
@@ -755,34 +789,32 @@ router_resolve_directory(directory_t *dir)
return 0;
}
-
-routerinfo_t *router_get_entry_from_string(char **s) {
- directory_token_t tok;
- routerinfo_t *router;
- if (router_get_next_token(s, &tok)) return NULL;
- router = router_get_entry_from_string_tok(s, &tok);
- if (tok.tp != _EOF) {
- router_release_token(&tok);
- return NULL;
- }
- return router;
-}
-
/* 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_tok(char**s, directory_token_t *tok) {
+routerinfo_t *router_get_entry_from_string(char**s) {
routerinfo_t *router = NULL;
-
-#define NEXT_TOKEN() \
- do { if (router_get_next_token(s, tok)) { \
- log(LOG_ERR, "Error reading directory: %s", tok->val.error); \
- goto err; \
+#if 0
+ char signed_digest[128];
+#endif
+ char digest[128];
+ directory_token_t _tok;
+ directory_token_t *tok = &_tok;
+
+#define NEXT_TOKEN() \
+ do { if (router_get_next_token(s, tok)) { \
+ log(LOG_ERR, "Error reading directory: %s", tok->val.error); \
+ goto err; \
} } while(0)
#define ARGS tok->val.cmd.args
+ if (router_get_router_hash(*s, digest) < 0)
+ return NULL;
+
+ NEXT_TOKEN();
+
if (tok->tp != K_ROUTER) {
router_release_token(tok);
log(LOG_ERR,"router_get_entry_from_string(): Entry does not start with \"router\"");
@@ -793,7 +825,7 @@ static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t
memset(router,0,sizeof(routerinfo_t)); /* zero it out first */
/* C doesn't guarantee that NULL is represented by 0 bytes. You'll
thank me for this someday. */
- router->pkey = router->signing_pkey = NULL;
+ router->onion_pkey = router->identity_pkey = router->link_pkey = NULL;
if (tok->val.cmd.n_args != 5) {
log(LOG_ERR,"router_get_entry_from_string(): Wrong # of arguments to \"router\"");
@@ -828,38 +860,77 @@ static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t
router->or_port, router->ap_port, router->dir_port, router->bandwidth);
NEXT_TOKEN();
+ if (tok->tp != K_ONION_KEY) {
+ log_fn(LOG_ERR, "Missing onion-key"); goto err;
+ }
+ NEXT_TOKEN();
if (tok->tp != _PUBLIC_KEY) {
- log(LOG_ERR,"router_get_entry_from_string(): Missing public key");
- goto err;
- } /* Check key length */
- router->pkey = tok->val.public_key;
+ log_fn(LOG_ERR, "Missing onion key"); goto err;
+ } /* XXX Check key length */
+ router->onion_pkey = tok->val.public_key;
NEXT_TOKEN();
- if (tok->tp == K_SIGNING_KEY) {
- NEXT_TOKEN();
- if (tok->tp != _PUBLIC_KEY) {
- log(LOG_ERR,"router_get_entry_from_string(): Missing signing key");
- goto err;
- }
- router->signing_pkey = tok->val.public_key;
- NEXT_TOKEN();
- }
+ if (tok->tp != K_LINK_KEY) {
+ log_fn(LOG_ERR, "Missing link-key"); goto err;
+ }
+ NEXT_TOKEN();
+ if (tok->tp != _PUBLIC_KEY) {
+ log_fn(LOG_ERR, "Missing link key"); goto err;
+ } /* XXX Check key length */
+ router->link_pkey = tok->val.public_key;
+
+ NEXT_TOKEN();
+ if (tok->tp != K_SIGNING_KEY) {
+ log_fn(LOG_ERR, "Missing signing-key"); goto err;
+ }
+ NEXT_TOKEN();
+ if (tok->tp != _PUBLIC_KEY) {
+ log_fn(LOG_ERR, "Missing signing key"); goto err;
+ }
+ router->identity_pkey = tok->val.public_key;
+ NEXT_TOKEN();
while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) {
router_add_exit_policy(router, tok);
NEXT_TOKEN();
}
+ if (tok->tp != K_ROUTER_SIGNATURE) {
+ log_fn(LOG_ERR,"Missing router signature");
+ goto err;
+ }
+ NEXT_TOKEN();
+ if (tok->tp != _SIGNATURE) {
+ log_fn(LOG_ERR,"Missing router signature");
+ goto err;
+ }
+ assert (router->identity_pkey);
+#if 0
+ /* XXX This should get re-enabled, once directory servers properly
+ * XXX relay signed router blocks. */
+ if (crypto_pk_public_checksig(router->identity_pkey, tok->val.signature,
+ 128, signed_digest) != 20) {
+ log_fn(LOG_ERR, "Invalid signature");
+ goto err;
+ }
+ if (memcmp(digest, signed_digest, 20)) {
+ log_fn(LOG_ERR, "Mismatched signature");
+ goto err;
+ }
+#endif
+
return router;
err:
router_release_token(tok);
if(router->address)
free(router->address);
- if(router->pkey)
- crypto_free_pk_env(router->pkey);
- if(router->signing_pkey)
- crypto_free_pk_env(router->signing_pkey);
+ if(router->link_pkey)
+ crypto_free_pk_env(router->link_pkey);
+ if(router->onion_pkey)
+ crypto_free_pk_env(router->onion_pkey);
+ if(router->identity_pkey)
+ crypto_free_pk_env(router->identity_pkey);
router_free_exit_policy(router);
free(router);
return NULL;