diff options
Diffstat (limited to 'src/or/routers.c')
-rw-r--r-- | src/or/routers.c | 507 |
1 files changed, 219 insertions, 288 deletions
diff --git a/src/or/routers.c b/src/or/routers.c index 6838b13c7..4f9b0846e 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 |