Implemented link padding and receiver token buckets
Each socket reads at most 'bandwidth' bytes per second sustained, but
can handle bursts of up to 10*bandwidth bytes.
Cells are now sent out at evenly-spaced intervals, with padding sent
out otherwise. Set Linkpadding=0 in the rc file to send cells as soon
as they're available (and to never send padding cells).
Added license/copyrights statements at the top of most files.
router->min and router->max have been merged into a single 'bandwidth'
value. We should make the routerinfo_t reflect this (want to do that,
Mat?)
As the bandwidth increases, and we want to stop sleeping more and more
frequently to send a single cell, cpu usage goes up. At 128kB/s we're
pretty much calling poll with a timeout of 1ms or even 0ms. The current
code takes a timeout of 0-9ms and makes it 10ms. prepare_for_poll()
handles everything that should have happened in the past, so as long as
our buffers don't get too full in that 10ms, we're ok.
Speaking of too full, if you run three servers at 100kB/s with -l debug,
it spends too much time printing debugging messages to be able to keep
up with the cells. The outbuf ultimately fills up and it kills that
connection. If you run with -l err, it works fine up through 500kB/s and
probably beyond. Down the road we'll want to teach it to recognize when
an outbuf is getting full, and back off.
svn:r50
2002-07-16 03:12:15 +02:00
|
|
|
/* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */
|
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
/* $Id$ */
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
#define OR_PUBLICKEY_BEGIN_TAG "-----BEGIN RSA PUBLIC KEY-----\n"
|
2002-09-24 12:43:57 +02:00
|
|
|
#define OR_PUBLICKEY_END_TAG "-----END RSA PUBLIC KEY-----\n"
|
2003-05-07 20:30:46 +02:00
|
|
|
#define OR_SIGNATURE_BEGIN_TAG "-----BEGIN SIGNATURE-----\n"
|
|
|
|
#define OR_SIGNATURE_END_TAG "-----END SIGNATURE-----\n"
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-09-30 20:47:29 +02:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
/* XXX this is required on rh7 to make strptime not complain. how bad
|
|
|
|
* is this for portability?
|
|
|
|
*/
|
|
|
|
|
2002-06-27 00:45:49 +02:00
|
|
|
#include "or.h"
|
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
|
2003-10-01 03:49:53 +02:00
|
|
|
static directory_t *directory = NULL; /* router array */
|
|
|
|
static routerinfo_t *desc_routerinfo = NULL; /* my descriptor */
|
|
|
|
static char descriptor[8192]; /* string representation of my descriptor */
|
2002-09-26 14:09:10 +02:00
|
|
|
|
|
|
|
extern or_options_t options; /* command-line and config-file options */
|
|
|
|
|
|
|
|
/****************************************************************************/
|
2002-09-04 08:29:28 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
struct directory_token;
|
|
|
|
typedef struct directory_token directory_token_t;
|
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
/* static function prototypes */
|
2003-05-07 04:13:23 +02:00
|
|
|
void routerlist_free(routerinfo_t *list);
|
2002-09-24 12:43:57 +02:00
|
|
|
static char *eat_whitespace(char *s);
|
2003-05-07 20:30:46 +02:00
|
|
|
static char *eat_whitespace_no_nl(char *s);
|
2002-09-24 12:43:57 +02:00
|
|
|
static char *find_whitespace(char *s);
|
2003-04-07 06:38:19 +02:00
|
|
|
static void router_free_exit_policy(routerinfo_t *router);
|
2003-10-08 01:04:31 +02:00
|
|
|
static int router_add_exit_policy_from_string(routerinfo_t *router, char *s);
|
2003-05-07 20:30:46 +02:00
|
|
|
static int router_add_exit_policy(routerinfo_t *router,
|
|
|
|
directory_token_t *tok);
|
2003-10-01 02:43:34 +02:00
|
|
|
static int router_resolve_directory(directory_t *dir);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
|
2002-10-03 00:54:20 +02:00
|
|
|
void router_retry_connections(void) {
|
2002-09-26 14:09:10 +02:00
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
for (i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
2002-09-26 14:09:10 +02:00
|
|
|
if(!connection_exact_get_by_addr_port(router->addr,router->or_port)) { /* not in the list */
|
2003-06-17 23:15:25 +02:00
|
|
|
log_fn(LOG_DEBUG,"connecting to OR %s:%u.",router->address,router->or_port);
|
2003-05-28 04:03:25 +02:00
|
|
|
connection_or_connect(router);
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
routerinfo_t *router_pick_directory_server(void) {
|
2003-09-30 23:27:16 +02:00
|
|
|
/* pick the first running router with a positive dir_port */
|
2002-09-26 14:09:10 +02:00
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
if(!directory)
|
2002-09-26 14:09:10 +02:00
|
|
|
return NULL;
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
for(i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
2003-09-30 23:27:16 +02:00
|
|
|
if(router->dir_port > 0 && router->is_running)
|
2002-09-26 14:09:10 +02:00
|
|
|
return router;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-09-25 12:42:07 +02:00
|
|
|
void router_upload_desc_to_dirservers(void) {
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
|
|
|
if(!directory)
|
|
|
|
return;
|
|
|
|
|
2003-10-01 02:43:34 +02:00
|
|
|
if (!router_get_my_descriptor()) {
|
|
|
|
log_fn(LOG_WARNING, "No descriptor; skipping upload");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-09-25 12:42:07 +02:00
|
|
|
for(i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
|
|
|
if(router->dir_port > 0)
|
|
|
|
directory_initiate_command(router, DIR_CONN_STATE_CONNECTING_UPLOAD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
assert(directory);
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
for(i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
2002-09-26 14:09:10 +02:00
|
|
|
if ((router->addr == addr) && (router->or_port == port))
|
|
|
|
return router;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-09-25 07:17:11 +02:00
|
|
|
routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk)
|
2003-09-11 22:32:15 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
|
|
|
assert(directory);
|
|
|
|
|
|
|
|
for(i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
2003-09-25 07:17:11 +02:00
|
|
|
if (0 == crypto_pk_cmp_keys(router->link_pkey, pk))
|
2003-09-11 22:32:15 +02:00
|
|
|
return router;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2003-09-30 23:27:16 +02:00
|
|
|
routerinfo_t *router_get_by_nickname(char *nickname)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
|
|
|
assert(directory);
|
|
|
|
|
|
|
|
for(i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
2003-09-30 23:27:16 +02:00
|
|
|
if (0 == strcmp(router->nickname, nickname))
|
2003-09-25 07:17:11 +02:00
|
|
|
return router;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2003-09-11 22:32:15 +02:00
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
void router_get_directory(directory_t **pdirectory) {
|
|
|
|
*pdirectory = directory;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
|
2002-06-27 00:45:49 +02:00
|
|
|
/* delete a list of routers from memory */
|
2003-05-09 04:00:33 +02:00
|
|
|
void routerinfo_free(routerinfo_t *router)
|
2002-06-27 00:45:49 +02:00
|
|
|
{
|
2003-05-06 19:38:16 +02:00
|
|
|
struct exit_policy_t *e = NULL, *etmp = NULL;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-05-09 04:00:33 +02:00
|
|
|
if (!router)
|
2002-06-27 00:45:49 +02:00
|
|
|
return;
|
|
|
|
|
2003-05-09 04:00:33 +02:00
|
|
|
if (router->address)
|
|
|
|
free(router->address);
|
2003-09-25 07:17:11 +02:00
|
|
|
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);
|
2003-05-09 04:00:33 +02:00
|
|
|
e = router->exit_policy;
|
|
|
|
while (e) {
|
|
|
|
etmp = e->next;
|
|
|
|
if (e->string) free(e->string);
|
|
|
|
if (e->address) free(e->address);
|
|
|
|
if (e->port) free(e->port);
|
|
|
|
free(e);
|
|
|
|
e = etmp;
|
|
|
|
}
|
|
|
|
free(router);
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
void directory_free(directory_t *directory)
|
|
|
|
{
|
2003-05-09 04:00:33 +02:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < directory->n_routers; ++i)
|
|
|
|
routerinfo_free(directory->routers[i]);
|
2003-09-25 07:17:11 +02:00
|
|
|
if (directory->routers)
|
|
|
|
free(directory->routers);
|
2003-09-13 23:53:38 +02:00
|
|
|
if(directory->software_versions)
|
|
|
|
free(directory->software_versions);
|
2003-05-06 19:38:16 +02:00
|
|
|
free(directory);
|
|
|
|
}
|
|
|
|
|
2003-09-30 23:27:16 +02:00
|
|
|
void router_mark_as_down(char *nickname) {
|
|
|
|
routerinfo_t *router = router_get_by_nickname(nickname);
|
2002-09-26 15:17:14 +02:00
|
|
|
if(!router) /* we don't seem to know about him in the first place */
|
|
|
|
return;
|
2003-09-30 23:27:16 +02:00
|
|
|
log_fn(LOG_DEBUG,"Marking %s as down.",router->nickname);
|
|
|
|
router->is_running = 0;
|
2002-09-26 15:17:14 +02:00
|
|
|
}
|
|
|
|
|
2002-06-27 00:45:49 +02:00
|
|
|
/* load the router list */
|
2002-10-03 00:54:20 +02:00
|
|
|
int router_get_list_from_file(char *routerfile)
|
2002-06-27 00:45:49 +02:00
|
|
|
{
|
2002-09-24 12:43:57 +02:00
|
|
|
char *string;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-09-28 08:48:20 +02:00
|
|
|
string = read_file_to_str(routerfile);
|
|
|
|
if(!string) {
|
|
|
|
log_fn(LOG_WARNING,"Failed to load routerfile %s.",routerfile);
|
2002-09-26 14:09:10 +02:00
|
|
|
return -1;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2002-10-03 00:54:20 +02:00
|
|
|
if(router_get_list_from_string(string) < 0) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"The routerfile itself was corrupt.");
|
2002-09-26 14:09:10 +02:00
|
|
|
free(string);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(string);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
K_ACCEPT,
|
|
|
|
K_DIRECTORY_SIGNATURE,
|
2003-05-09 04:25:37 +02:00
|
|
|
K_RECOMMENDED_SOFTWARE,
|
2003-05-07 20:30:46 +02:00
|
|
|
K_REJECT,
|
|
|
|
K_ROUTER,
|
|
|
|
K_SIGNED_DIRECTORY,
|
|
|
|
K_SIGNING_KEY,
|
2003-09-25 07:17:11 +02:00
|
|
|
K_ONION_KEY,
|
|
|
|
K_LINK_KEY,
|
|
|
|
K_ROUTER_SIGNATURE,
|
2003-09-26 20:27:35 +02:00
|
|
|
K_PUBLISHED,
|
2003-09-27 23:30:10 +02:00
|
|
|
K_RUNNING_ROUTERS,
|
2003-10-01 00:44:33 +02:00
|
|
|
K_PLATFORM,
|
2003-05-07 20:30:46 +02:00
|
|
|
_SIGNATURE,
|
|
|
|
_PUBLIC_KEY,
|
|
|
|
_ERR,
|
|
|
|
_EOF
|
|
|
|
} directory_keyword;
|
|
|
|
|
|
|
|
struct token_table_ent { char *t; int v; };
|
|
|
|
|
|
|
|
static struct token_table_ent token_table[] = {
|
|
|
|
{ "accept", K_ACCEPT },
|
|
|
|
{ "directory-signature", K_DIRECTORY_SIGNATURE },
|
|
|
|
{ "reject", K_REJECT },
|
|
|
|
{ "router", K_ROUTER },
|
2003-05-09 04:25:37 +02:00
|
|
|
{ "recommended-software", K_RECOMMENDED_SOFTWARE },
|
2003-05-07 20:30:46 +02:00
|
|
|
{ "signed-directory", K_SIGNED_DIRECTORY },
|
|
|
|
{ "signing-key", K_SIGNING_KEY },
|
2003-09-25 07:17:11 +02:00
|
|
|
{ "onion-key", K_ONION_KEY },
|
|
|
|
{ "link-key", K_LINK_KEY },
|
|
|
|
{ "router-signature", K_ROUTER_SIGNATURE },
|
2003-09-26 20:27:35 +02:00
|
|
|
{ "published", K_PUBLISHED },
|
2003-09-27 23:30:10 +02:00
|
|
|
{ "running-routers", K_RUNNING_ROUTERS },
|
2003-10-01 00:44:33 +02:00
|
|
|
{ "platform", K_PLATFORM },
|
2003-05-07 20:30:46 +02:00
|
|
|
{ NULL, -1 }
|
|
|
|
};
|
|
|
|
|
2003-09-27 23:30:10 +02:00
|
|
|
#define MAX_ARGS 1024
|
2003-05-07 20:30:46 +02:00
|
|
|
struct directory_token {
|
|
|
|
directory_keyword tp;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
char *args[MAX_ARGS+1];
|
|
|
|
int n_args;
|
|
|
|
} cmd;
|
|
|
|
char *signature;
|
|
|
|
char *error;
|
|
|
|
crypto_pk_env_t *public_key;
|
|
|
|
} val;
|
|
|
|
};
|
|
|
|
|
2003-08-28 06:21:57 +02:00
|
|
|
/* Free any malloced resources allocated for a token. Don't call this if
|
|
|
|
you inherit the reference to those resources.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
router_release_token(directory_token_t *tok)
|
|
|
|
{
|
|
|
|
switch (tok->tp)
|
|
|
|
{
|
|
|
|
case _SIGNATURE:
|
|
|
|
free(tok->val.signature);
|
|
|
|
break;
|
|
|
|
case _PUBLIC_KEY:
|
|
|
|
crypto_free_pk_env(tok->val.public_key);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
static int
|
|
|
|
_router_get_next_token(char **s, directory_token_t *tok) {
|
|
|
|
char *next;
|
|
|
|
crypto_pk_env_t *pkey = NULL;
|
|
|
|
char *signature = NULL;
|
|
|
|
int i, done;
|
|
|
|
|
|
|
|
tok->tp = _ERR;
|
|
|
|
tok->val.error = "";
|
|
|
|
|
|
|
|
*s = eat_whitespace(*s);
|
|
|
|
if (!**s) {
|
|
|
|
tok->tp = _EOF;
|
|
|
|
return 0;
|
|
|
|
} else if (**s == '-') {
|
|
|
|
next = strchr(*s, '\n');
|
|
|
|
if (! next) { tok->val.error = "No newline at EOF"; return -1; }
|
|
|
|
++next;
|
|
|
|
if (! strncmp(*s, OR_PUBLICKEY_BEGIN_TAG, next-*s)) {
|
|
|
|
next = strstr(*s, OR_PUBLICKEY_END_TAG);
|
|
|
|
if (!next) { tok->val.error = "No public key end tag found"; return -1; }
|
|
|
|
next = strchr(next, '\n'); /* Part of OR_PUBLICKEY_END_TAG; can't fail.*/
|
|
|
|
++next;
|
|
|
|
if (!(pkey = crypto_new_pk_env(CRYPTO_PK_RSA)))
|
|
|
|
return -1;
|
|
|
|
if (crypto_pk_read_public_key_from_string(pkey, *s, next-*s)) {
|
|
|
|
crypto_free_pk_env(pkey);
|
|
|
|
tok->val.error = "Couldn't parse public key.";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
tok->tp = _PUBLIC_KEY;
|
|
|
|
tok->val.public_key = pkey;
|
|
|
|
*s = next;
|
|
|
|
return 0;
|
|
|
|
} else if (! strncmp(*s, OR_SIGNATURE_BEGIN_TAG, next-*s)) {
|
|
|
|
/* Advance past newline; can't fail. */
|
|
|
|
*s = strchr(*s, '\n');
|
|
|
|
++*s;
|
|
|
|
/* Find end of base64'd data */
|
|
|
|
next = strstr(*s, OR_SIGNATURE_END_TAG);
|
|
|
|
if (!next) { tok->val.error = "No signature end tag found"; return -1; }
|
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
signature = tor_malloc(256);
|
2003-05-07 20:30:46 +02:00
|
|
|
i = base64_decode(signature, 256, *s, next-*s);
|
|
|
|
if (i<0) {
|
|
|
|
free(signature);
|
|
|
|
tok->val.error = "Error decoding signature."; return -1;
|
|
|
|
} else if (i != 128) {
|
|
|
|
free(signature);
|
|
|
|
tok->val.error = "Bad length on decoded signature."; return -1;
|
|
|
|
}
|
|
|
|
tok->tp = _SIGNATURE;
|
|
|
|
tok->val.signature = signature;
|
|
|
|
|
|
|
|
next = strchr(next, '\n'); /* Part of OR_SIGNATURE_END_TAG; can't fail.*/
|
|
|
|
*s = next+1;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
tok->val.error = "Unrecognized begin line"; return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
next = find_whitespace(*s);
|
|
|
|
if (!next) {
|
|
|
|
tok->val.error = "Unexpected EOF"; return -1;
|
|
|
|
}
|
|
|
|
for (i = 0 ; token_table[i].t ; ++i) {
|
|
|
|
if (!strncmp(token_table[i].t, *s, next-*s)) {
|
|
|
|
tok->tp = token_table[i].v;
|
|
|
|
i = 0;
|
|
|
|
done = (*next == '\n');
|
|
|
|
*s = eat_whitespace_no_nl(next);
|
|
|
|
while (**s != '\n' && i <= MAX_ARGS && !done) {
|
|
|
|
next = find_whitespace(*s);
|
|
|
|
if (*next == '\n')
|
|
|
|
done = 1;
|
|
|
|
*next = 0;
|
|
|
|
tok->val.cmd.args[i++] = *s;
|
|
|
|
*s = eat_whitespace_no_nl(next+1);
|
|
|
|
};
|
|
|
|
tok->val.cmd.n_args = i;
|
|
|
|
if (i > MAX_ARGS) {
|
|
|
|
tok->tp = _ERR;
|
|
|
|
tok->val.error = "Too many arguments"; return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tok->val.error = "Unrecognized command"; return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-09 04:20:16 +02:00
|
|
|
#ifdef DEBUG_ROUTER_TOKENS
|
2003-05-07 20:30:46 +02:00
|
|
|
static void
|
|
|
|
router_dump_token(directory_token_t *tok) {
|
|
|
|
int i;
|
|
|
|
switch(tok->tp)
|
|
|
|
{
|
|
|
|
case _SIGNATURE:
|
|
|
|
puts("(signature)");
|
|
|
|
return;
|
|
|
|
case _PUBLIC_KEY:
|
|
|
|
puts("(public key)");
|
|
|
|
return;
|
|
|
|
case _ERR:
|
|
|
|
printf("(Error: %s\n)", tok->val.error);
|
|
|
|
return;
|
|
|
|
case _EOF:
|
|
|
|
puts("EOF");
|
|
|
|
return;
|
|
|
|
case K_ACCEPT: printf("Accept"); break;
|
|
|
|
case K_DIRECTORY_SIGNATURE: printf("Directory-Signature"); break;
|
|
|
|
case K_REJECT: printf("Reject"); break;
|
2003-05-09 04:25:37 +02:00
|
|
|
case K_RECOMMENDED_SOFTWARE: printf("Server-Software"); break;
|
2003-05-07 20:30:46 +02:00
|
|
|
case K_ROUTER: printf("Router"); break;
|
|
|
|
case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break;
|
|
|
|
case K_SIGNING_KEY: printf("Signing-Key"); break;
|
2003-09-25 07:17:11 +02:00
|
|
|
case K_ONION_KEY: printf("Onion-key"); break;
|
|
|
|
case K_LINK_KEY: printf("Link-key"); break;
|
|
|
|
case K_ROUTER_SIGNATURE: printf("Router-signature"); break;
|
2003-09-26 20:27:35 +02:00
|
|
|
case K_PUBLISHED: printf("Published"); break;
|
2003-09-27 23:30:10 +02:00
|
|
|
case K_RUNNING_ROUTERS: printf("Running-routers"); break;
|
2003-10-01 00:44:33 +02:00
|
|
|
case K_PLATFORM: printf("Platform"); break;
|
2003-05-07 20:30:46 +02:00
|
|
|
default:
|
|
|
|
printf("?????? %d\n", tok->tp); return;
|
|
|
|
}
|
|
|
|
for (i = 0; i < tok->val.cmd.n_args; ++i) {
|
|
|
|
printf(" \"%s\"", tok->val.cmd.args[i]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static int
|
|
|
|
router_get_next_token(char **s, directory_token_t *tok) {
|
|
|
|
int i;
|
|
|
|
i = _router_get_next_token(s, tok);
|
|
|
|
router_dump_token(tok);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define router_get_next_token _router_get_next_token
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *eat_whitespace_no_nl(char *s) {
|
|
|
|
while(*s == ' ' || *s == '\t')
|
|
|
|
++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;
|
|
|
|
}
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
int router_get_list_from_string(char *s)
|
|
|
|
{
|
2003-09-27 23:30:10 +02:00
|
|
|
if (router_get_list_from_string_impl(&s, &directory, -1, NULL)) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log(LOG_WARNING, "Error parsing router file");
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (router_resolve_directory(directory)) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log(LOG_WARNING, "Error resolving directory");
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2003-05-06 19:38:16 +02:00
|
|
|
}
|
|
|
|
|
2003-09-25 07:17:11 +02:00
|
|
|
static int router_get_hash_impl(char *s, char *digest, const char *start_str,
|
|
|
|
const char *end_str)
|
2003-05-07 20:30:46 +02:00
|
|
|
{
|
|
|
|
char *start, *end;
|
2003-09-25 07:17:11 +02:00
|
|
|
start = strstr(s, start_str);
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (!start) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"couldn't find \"%s\"",start_str);
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2003-09-25 07:17:11 +02:00
|
|
|
end = strstr(start+strlen(start_str), end_str);
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (!end) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"couldn't find \"%s\"",end_str);
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
end = strchr(end, '\n');
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (!end) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"couldn't find EOL");
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
++end;
|
|
|
|
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (crypto_SHA_digest(start, end-start, digest)) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"couldn't compute digest");
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1;
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-09-30 21:27:54 +02:00
|
|
|
int router_get_dir_hash(char *s, char *digest)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2003-08-23 12:09:25 +02:00
|
|
|
/* return 0 if myversion is in start. Else return -1. */
|
|
|
|
int compare_recommended_versions(char *myversion, char *start) {
|
|
|
|
int len_myversion = strlen(myversion);
|
|
|
|
char *comma;
|
|
|
|
char *end = start + strlen(start);
|
|
|
|
|
|
|
|
log_fn(LOG_DEBUG,"checking '%s' in '%s'.", myversion, start);
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
comma = strchr(start, ',');
|
|
|
|
if( ((comma ? comma : end) - start == len_myversion) &&
|
|
|
|
!strncmp(start, myversion, len_myversion)) /* only do strncmp if the length matches */
|
|
|
|
return 0; /* success, it's there */
|
|
|
|
if(!comma)
|
|
|
|
return -1; /* nope */
|
|
|
|
start = comma+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey)
|
|
|
|
{
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (router_get_dir_from_string_impl(s, &directory, pkey)) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Couldn't parse directory.");
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (router_resolve_directory(directory)) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Error resolving directory");
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2003-08-23 12:09:25 +02:00
|
|
|
if (compare_recommended_versions(VERSION, directory->software_versions) < 0) {
|
2003-10-07 18:56:27 +02:00
|
|
|
log(LOG_WARNING, "You are running tor version %s, which is no longer supported.\nPlease upgrade to one of %s.", VERSION, directory->software_versions);
|
2003-08-23 12:09:25 +02:00
|
|
|
if(options.IgnoreVersion) {
|
|
|
|
log(LOG_WARNING, "IgnoreVersion is set. If it breaks, we told you so.");
|
|
|
|
} else {
|
2003-09-26 12:03:50 +02:00
|
|
|
log(LOG_ERR,"Set IgnoreVersion config variable if you want to proceed.");
|
2003-08-23 12:09:25 +02:00
|
|
|
fflush(0);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return 0;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int router_get_dir_from_string_impl(char *s, directory_t **dest,
|
|
|
|
crypto_pk_env_t *pkey)
|
|
|
|
{
|
|
|
|
directory_token_t tok;
|
|
|
|
char digest[20];
|
|
|
|
char signed_digest[128];
|
2003-05-07 20:39:44 +02:00
|
|
|
directory_t *new_dir = NULL;
|
2003-05-09 04:25:37 +02:00
|
|
|
char *versions;
|
2003-09-27 23:30:10 +02:00
|
|
|
struct tm published;
|
|
|
|
time_t published_on;
|
|
|
|
const char *good_nickname_lst[1024];
|
|
|
|
int n_good_nicknames;
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
#define NEXT_TOK() \
|
|
|
|
do { \
|
|
|
|
if (router_get_next_token(&s, &tok)) { \
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Error reading directory: %s", tok.val.error);\
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1; \
|
|
|
|
} } while (0)
|
|
|
|
#define TOK_IS(type,name) \
|
|
|
|
do { \
|
|
|
|
if (tok.tp != type) { \
|
2003-08-28 06:21:57 +02:00
|
|
|
router_release_token(&tok); \
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Error reading directory: expected %s", name);\
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1; \
|
|
|
|
} } while(0)
|
2003-09-25 07:17:11 +02:00
|
|
|
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (router_get_dir_hash(s, digest)) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Unable to compute digest of directory");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
}
|
2003-09-30 22:05:45 +02:00
|
|
|
log(LOG_DEBUG,"Received directory hashes to %02x:%02x:%02x:%02x",
|
|
|
|
((int)digest[0])&0xff,((int)digest[1])&0xff,
|
|
|
|
((int)digest[2])&0xff,((int)digest[3])&0xff);
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
NEXT_TOK();
|
|
|
|
TOK_IS(K_SIGNED_DIRECTORY, "signed-directory");
|
|
|
|
|
2003-09-27 23:30:10 +02:00
|
|
|
NEXT_TOK();
|
|
|
|
TOK_IS(K_PUBLISHED, "published");
|
|
|
|
if (tok.val.cmd.n_args != 2) {
|
|
|
|
log_fn(LOG_WARNING, "Invalid published line");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
tok.val.cmd.args[1][-1] = ' ';
|
|
|
|
if (!strptime(tok.val.cmd.args[0], "%Y-%m-%d %H:%M:%S", &published)) {
|
|
|
|
log_fn(LOG_WARNING, "Published time was unparseable"); goto err;
|
|
|
|
}
|
|
|
|
published_on = timegm(&published);
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
NEXT_TOK();
|
2003-05-09 04:25:37 +02:00
|
|
|
TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software");
|
|
|
|
if (tok.val.cmd.n_args != 1) {
|
2003-09-30 01:14:49 +02:00
|
|
|
log_fn(LOG_WARNING, "Invalid recommended-software line");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
2003-05-09 04:25:37 +02:00
|
|
|
}
|
2003-10-04 05:29:09 +02:00
|
|
|
versions = tor_strdup(tok.val.cmd.args[0]);
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-09-27 23:30:10 +02:00
|
|
|
NEXT_TOK();
|
|
|
|
TOK_IS(K_RUNNING_ROUTERS, "running-routers");
|
|
|
|
n_good_nicknames = tok.val.cmd.n_args;
|
2003-09-30 01:14:49 +02:00
|
|
|
memcpy(good_nickname_lst, tok.val.cmd.args, n_good_nicknames*sizeof(char *));
|
2003-09-27 23:30:10 +02:00
|
|
|
|
|
|
|
if (router_get_list_from_string_impl(&s, &new_dir,
|
|
|
|
n_good_nicknames, good_nickname_lst)) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Error reading routers from directory");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
}
|
2003-05-09 04:25:37 +02:00
|
|
|
new_dir->software_versions = versions;
|
2003-09-27 23:30:10 +02:00
|
|
|
new_dir->published_on = published_on;
|
2003-09-25 07:17:11 +02:00
|
|
|
|
|
|
|
NEXT_TOK();
|
2003-05-07 20:30:46 +02:00
|
|
|
TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature");
|
|
|
|
NEXT_TOK();
|
|
|
|
TOK_IS(_SIGNATURE, "signature");
|
|
|
|
if (pkey) {
|
|
|
|
if (crypto_pk_public_checksig(pkey, tok.val.signature, 128, signed_digest)
|
|
|
|
!= 20) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Error reading directory: invalid signature.");
|
2003-05-07 20:30:46 +02:00
|
|
|
free(tok.val.signature);
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
2003-09-30 22:05:45 +02:00
|
|
|
log(LOG_DEBUG,"Signed directory hash starts %02x:%02x:%02x:%02x",
|
|
|
|
((int)signed_digest[0])&0xff,((int)signed_digest[1])&0xff,
|
|
|
|
((int)signed_digest[2])&0xff,((int)signed_digest[3])&0xff);
|
2003-05-07 20:30:46 +02:00
|
|
|
if (memcmp(digest, signed_digest, 20)) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Error reading directory: signature does not match.");
|
2003-05-07 20:30:46 +02:00
|
|
|
free(tok.val.signature);
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
free(tok.val.signature);
|
|
|
|
|
|
|
|
NEXT_TOK();
|
|
|
|
TOK_IS(_EOF, "end of directory");
|
|
|
|
|
2003-05-07 20:39:44 +02:00
|
|
|
if (*dest)
|
|
|
|
directory_free(*dest);
|
|
|
|
*dest = new_dir;
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
return 0;
|
2003-09-25 07:17:11 +02:00
|
|
|
|
|
|
|
err:
|
|
|
|
if (new_dir)
|
|
|
|
directory_free(new_dir);
|
|
|
|
return -1;
|
2003-05-07 20:30:46 +02:00
|
|
|
#undef NEXT_TOK
|
|
|
|
#undef TOK_IS
|
|
|
|
}
|
|
|
|
|
2003-09-27 23:30:10 +02:00
|
|
|
int router_get_list_from_string_impl(char **s, directory_t **dest,
|
|
|
|
int n_good_nicknames,
|
|
|
|
const char **good_nickname_lst)
|
2003-05-06 19:38:16 +02:00
|
|
|
{
|
2002-09-26 14:09:10 +02:00
|
|
|
routerinfo_t *router;
|
2003-05-09 04:00:33 +02:00
|
|
|
routerinfo_t **rarray;
|
|
|
|
int rarray_len = 0;
|
2003-09-30 10:18:10 +02:00
|
|
|
int i;
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2003-09-30 10:18:10 +02:00
|
|
|
assert(s && *s);
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
rarray = (routerinfo_t **)tor_malloc((sizeof(routerinfo_t *))*MAX_ROUTERS_IN_DIR);
|
2003-05-09 04:00:33 +02:00
|
|
|
|
2003-09-25 07:17:11 +02:00
|
|
|
while (1) {
|
|
|
|
*s = eat_whitespace(*s);
|
|
|
|
if (strncmp(*s, "router ", 7)!=0)
|
|
|
|
break;
|
|
|
|
router = router_get_entry_from_string(s);
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (!router) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Error reading router");
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2003-05-09 04:00:33 +02:00
|
|
|
if (rarray_len >= MAX_ROUTERS_IN_DIR) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "too many routers");
|
2003-05-09 04:00:33 +02:00
|
|
|
routerinfo_free(router);
|
|
|
|
continue;
|
|
|
|
}
|
2003-09-27 23:30:10 +02:00
|
|
|
if (n_good_nicknames>=0) {
|
|
|
|
router->is_running = 0;
|
|
|
|
for (i = 0; i < n_good_nicknames; ++i) {
|
|
|
|
if (0==strcasecmp(good_nickname_lst[i], router->nickname)) {
|
|
|
|
router->is_running = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-09-30 23:27:16 +02:00
|
|
|
} else {
|
|
|
|
router->is_running = 1; /* start out assuming all dirservers are up */
|
2003-09-27 23:30:10 +02:00
|
|
|
}
|
2003-05-09 04:00:33 +02:00
|
|
|
rarray[rarray_len++] = router;
|
2003-09-30 10:18:10 +02:00
|
|
|
log_fn(LOG_DEBUG,"just added router #%d.",rarray_len);
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2003-05-09 04:00:33 +02:00
|
|
|
if (*dest)
|
|
|
|
directory_free(*dest);
|
2003-05-20 08:41:23 +02:00
|
|
|
*dest = (directory_t *)tor_malloc(sizeof(directory_t));
|
2003-05-09 04:00:33 +02:00
|
|
|
(*dest)->routers = rarray;
|
|
|
|
(*dest)->n_routers = rarray_len;
|
2003-09-13 23:53:38 +02:00
|
|
|
(*dest)->software_versions = NULL;
|
2003-05-09 04:00:33 +02:00
|
|
|
return 0;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
2003-05-07 20:39:44 +02:00
|
|
|
|
2003-09-16 07:41:49 +02:00
|
|
|
static int
|
2003-05-06 19:38:16 +02:00
|
|
|
router_resolve(routerinfo_t *router)
|
|
|
|
{
|
|
|
|
struct hostent *rent;
|
|
|
|
|
|
|
|
rent = (struct hostent *)gethostbyname(router->address);
|
|
|
|
if (!rent) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"Could not get address for router %s.",router->address);
|
2003-05-06 19:38:16 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
assert(rent->h_length == 4);
|
|
|
|
memcpy(&router->addr, rent->h_addr,rent->h_length);
|
|
|
|
router->addr = ntohl(router->addr); /* get it back into host order */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-09-16 07:41:49 +02:00
|
|
|
static int
|
2003-05-08 14:32:30 +02:00
|
|
|
router_resolve_directory(directory_t *dir)
|
|
|
|
{
|
2003-05-09 03:24:44 +02:00
|
|
|
int i, max, remove;
|
2003-05-08 14:32:30 +02:00
|
|
|
if (!dir)
|
|
|
|
dir = directory;
|
|
|
|
|
|
|
|
max = dir->n_routers;
|
|
|
|
for (i = 0; i < max; ++i) {
|
2003-05-09 03:24:44 +02:00
|
|
|
remove = 0;
|
2003-05-08 14:32:30 +02:00
|
|
|
if (router_resolve(dir->routers[i])) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Couldn't resolve router %s; removing",
|
|
|
|
dir->routers[i]->address);
|
2003-05-09 03:24:44 +02:00
|
|
|
remove = 1;
|
2003-05-09 04:00:33 +02:00
|
|
|
routerinfo_free(dir->routers[i]);
|
2003-10-01 03:49:53 +02:00
|
|
|
} else if (options.Nickname && !strcmp(dir->routers[i]->nickname, options.Nickname)) {
|
2003-05-09 03:24:44 +02:00
|
|
|
remove = 1;
|
|
|
|
}
|
|
|
|
if (remove) {
|
2003-05-08 14:32:30 +02:00
|
|
|
dir->routers[i] = dir->routers[--max];
|
|
|
|
--dir->n_routers;
|
2003-05-09 03:24:44 +02:00
|
|
|
--i;
|
2003-05-08 14:32:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
/* 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.
|
|
|
|
*/
|
2003-09-25 07:17:11 +02:00
|
|
|
routerinfo_t *router_get_entry_from_string(char**s) {
|
2003-05-07 20:30:46 +02:00
|
|
|
routerinfo_t *router = NULL;
|
2003-09-25 07:17:11 +02:00
|
|
|
char signed_digest[128];
|
|
|
|
char digest[128];
|
|
|
|
directory_token_t _tok;
|
|
|
|
directory_token_t *tok = &_tok;
|
2003-09-26 20:27:35 +02:00
|
|
|
struct tm published;
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2003-10-02 00:31:13 +02:00
|
|
|
int t;
|
|
|
|
|
2003-09-25 07:17:11 +02:00
|
|
|
#define NEXT_TOKEN() \
|
|
|
|
do { if (router_get_next_token(s, tok)) { \
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Error reading directory: %s", tok->val.error);\
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err; \
|
2003-05-09 04:00:33 +02:00
|
|
|
} } while(0)
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
#define ARGS tok->val.cmd.args
|
|
|
|
|
2003-10-02 00:31:13 +02:00
|
|
|
if (router_get_router_hash(*s, digest) < 0) {
|
|
|
|
log_fn(LOG_WARNING, "Couldn't compute router hash.");
|
2003-09-25 07:17:11 +02:00
|
|
|
return NULL;
|
2003-10-02 00:31:13 +02:00
|
|
|
}
|
2003-09-25 07:17:11 +02:00
|
|
|
|
|
|
|
NEXT_TOKEN();
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
if (tok->tp != K_ROUTER) {
|
2003-08-28 06:21:57 +02:00
|
|
|
router_release_token(tok);
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"Entry does not start with \"router\"");
|
2003-05-06 19:38:16 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2003-05-20 08:41:23 +02:00
|
|
|
|
|
|
|
router = tor_malloc(sizeof(routerinfo_t));
|
2002-09-24 12:43:57 +02:00
|
|
|
memset(router,0,sizeof(routerinfo_t)); /* zero it out first */
|
2003-05-09 04:00:33 +02:00
|
|
|
/* C doesn't guarantee that NULL is represented by 0 bytes. You'll
|
|
|
|
thank me for this someday. */
|
2003-09-25 07:17:11 +02:00
|
|
|
router->onion_pkey = router->identity_pkey = router->link_pkey = NULL;
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-09-27 23:30:10 +02:00
|
|
|
if (tok->val.cmd.n_args != 6) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"Wrong # of arguments to \"router\"");
|
2003-05-07 20:30:46 +02:00
|
|
|
goto err;
|
|
|
|
}
|
2003-10-04 05:29:09 +02:00
|
|
|
router->nickname = tor_strdup(ARGS[0]);
|
2003-10-02 00:31:13 +02:00
|
|
|
if (strlen(router->nickname) > MAX_NICKNAME_LEN) {
|
|
|
|
log_fn(LOG_WARNING,"Router nickname too long.");
|
2003-09-27 23:30:10 +02:00
|
|
|
goto err;
|
2003-10-02 00:31:13 +02:00
|
|
|
}
|
2003-09-27 23:30:10 +02:00
|
|
|
if (strspn(router->nickname, LEGAL_NICKNAME_CHARACTERS) !=
|
2003-10-02 00:31:13 +02:00
|
|
|
strlen(router->nickname)) {
|
|
|
|
log_fn(LOG_WARNING, "Router nickname contains illegal characters.");
|
2003-09-27 23:30:10 +02:00
|
|
|
goto err;
|
2003-10-02 00:31:13 +02:00
|
|
|
}
|
2003-09-27 23:30:10 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
/* read router.address */
|
2003-10-04 05:29:09 +02:00
|
|
|
router->address = tor_strdup(ARGS[1]);
|
2003-05-06 19:38:16 +02:00
|
|
|
router->addr = 0;
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
/* Read router->or_port */
|
2003-09-27 23:30:10 +02:00
|
|
|
router->or_port = atoi(ARGS[2]);
|
2002-09-24 12:43:57 +02:00
|
|
|
if(!router->or_port) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"or_port unreadable or 0. Failing.");
|
2003-05-07 20:30:46 +02:00
|
|
|
goto err;
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
/* Router->ap_port */
|
2003-09-27 23:30:10 +02:00
|
|
|
router->ap_port = atoi(ARGS[3]);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
/* Router->dir_port */
|
2003-09-27 23:30:10 +02:00
|
|
|
router->dir_port = atoi(ARGS[4]);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
/* Router->bandwidth */
|
2003-09-27 23:30:10 +02:00
|
|
|
router->bandwidth = atoi(ARGS[5]);
|
2003-05-07 20:30:46 +02:00
|
|
|
if (!router->bandwidth) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"bandwidth unreadable or 0. Failing.");
|
2003-10-02 00:31:13 +02:00
|
|
|
goto err;
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"or_port %d, ap_port %d, dir_port %d, bandwidth %d.",
|
2003-08-28 00:42:10 +02:00
|
|
|
router->or_port, router->ap_port, router->dir_port, router->bandwidth);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-10-01 00:44:33 +02:00
|
|
|
/* XXX Later, require platform before published. */
|
2003-09-26 20:27:35 +02:00
|
|
|
NEXT_TOKEN();
|
2003-10-01 00:44:33 +02:00
|
|
|
if (tok->tp == K_PLATFORM) {
|
|
|
|
NEXT_TOKEN();
|
|
|
|
}
|
|
|
|
|
2003-09-26 20:27:35 +02:00
|
|
|
if (tok->tp != K_PUBLISHED) {
|
|
|
|
log_fn(LOG_WARNING, "Missing published time"); goto err;
|
|
|
|
}
|
|
|
|
if (tok->val.cmd.n_args != 2) {
|
|
|
|
log_fn(LOG_WARNING, "Wrong number of arguments to published"); goto err;
|
|
|
|
}
|
2003-09-27 23:30:10 +02:00
|
|
|
ARGS[1][-1] = ' '; /* Re-insert space. */
|
|
|
|
if (!strptime(ARGS[0], "%Y-%m-%d %H:%M:%S", &published)) {
|
2003-09-26 20:27:35 +02:00
|
|
|
log_fn(LOG_WARNING, "Published time was unparseable"); goto err;
|
|
|
|
}
|
|
|
|
router->published_on = timegm(&published);
|
|
|
|
|
2003-09-25 07:17:11 +02:00
|
|
|
NEXT_TOKEN();
|
|
|
|
if (tok->tp != K_ONION_KEY) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Missing onion-key"); goto err;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
NEXT_TOKEN();
|
2003-08-28 06:21:57 +02:00
|
|
|
if (tok->tp != _PUBLIC_KEY) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Missing onion key"); goto err;
|
2003-09-25 07:17:11 +02:00
|
|
|
} /* XXX Check key length */
|
|
|
|
router->onion_pkey = tok->val.public_key;
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
NEXT_TOKEN();
|
2003-09-25 07:17:11 +02:00
|
|
|
if (tok->tp != K_LINK_KEY) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Missing link-key"); goto err;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
NEXT_TOKEN();
|
|
|
|
if (tok->tp != _PUBLIC_KEY) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Missing link key"); goto err;
|
2003-09-25 07:17:11 +02:00
|
|
|
} /* XXX Check key length */
|
|
|
|
router->link_pkey = tok->val.public_key;
|
|
|
|
|
|
|
|
NEXT_TOKEN();
|
|
|
|
if (tok->tp != K_SIGNING_KEY) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Missing signing-key"); goto err;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
NEXT_TOKEN();
|
|
|
|
if (tok->tp != _PUBLIC_KEY) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Missing signing key"); goto err;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
router->identity_pkey = tok->val.public_key;
|
2003-05-07 04:13:23 +02:00
|
|
|
|
2003-09-25 07:17:11 +02:00
|
|
|
NEXT_TOKEN();
|
2003-05-07 20:30:46 +02:00
|
|
|
while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) {
|
|
|
|
router_add_exit_policy(router, tok);
|
|
|
|
NEXT_TOKEN();
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-09-25 07:17:11 +02:00
|
|
|
if (tok->tp != K_ROUTER_SIGNATURE) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"Missing router signature");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
NEXT_TOKEN();
|
|
|
|
if (tok->tp != _SIGNATURE) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"Missing router signature");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
assert (router->identity_pkey);
|
2003-09-30 22:05:45 +02:00
|
|
|
|
2003-10-02 00:31:13 +02:00
|
|
|
if ((t=crypto_pk_public_checksig(router->identity_pkey, tok->val.signature,
|
|
|
|
128, signed_digest)) != 20) {
|
|
|
|
log_fn(LOG_WARNING, "Invalid signature %d",t);
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (memcmp(digest, signed_digest, 20)) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING, "Mismatched signature");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2003-04-07 06:38:19 +02:00
|
|
|
return router;
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
err:
|
2003-08-28 06:21:57 +02:00
|
|
|
router_release_token(tok);
|
2002-09-24 12:43:57 +02:00
|
|
|
if(router->address)
|
|
|
|
free(router->address);
|
2003-09-25 07:17:11 +02:00
|
|
|
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);
|
2003-04-07 06:38:19 +02:00
|
|
|
router_free_exit_policy(router);
|
2002-09-24 12:43:57 +02:00
|
|
|
free(router);
|
|
|
|
return NULL;
|
2003-05-07 20:30:46 +02:00
|
|
|
#undef ARGS
|
|
|
|
#undef NEXT_TOKEN
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2003-04-07 06:38:19 +02:00
|
|
|
static void router_free_exit_policy(routerinfo_t *router) {
|
|
|
|
struct exit_policy_t *tmpe;
|
|
|
|
|
|
|
|
while(router->exit_policy) {
|
|
|
|
tmpe = router->exit_policy;
|
|
|
|
router->exit_policy = tmpe->next;
|
|
|
|
free(tmpe->string);
|
|
|
|
free(tmpe->address);
|
|
|
|
free(tmpe->port);
|
|
|
|
free(tmpe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-08 01:04:31 +02:00
|
|
|
void router_add_exit_policy_from_config(routerinfo_t *router) {
|
|
|
|
char *s = options.ExitPolicy, *e;
|
|
|
|
int last=0;
|
2003-10-08 01:25:10 +02:00
|
|
|
char line[1024];
|
2003-10-08 01:04:31 +02:00
|
|
|
|
|
|
|
if(!s) {
|
|
|
|
log_fn(LOG_INFO,"No exit policy configured. Ok.");
|
|
|
|
return; /* nothing to see here */
|
|
|
|
}
|
|
|
|
if(!*s) {
|
|
|
|
log_fn(LOG_INFO,"Exit policy is empty. Ok.");
|
|
|
|
return; /* nothing to see here */
|
|
|
|
}
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
e = strchr(s,',');
|
2003-10-08 01:25:10 +02:00
|
|
|
if(!e) {
|
2003-10-08 01:04:31 +02:00
|
|
|
last = 1;
|
2003-10-08 01:25:10 +02:00
|
|
|
strcpy(line,s);
|
|
|
|
} else {
|
|
|
|
memcpy(line,s,e-s);
|
|
|
|
line[e-s] = 0;
|
|
|
|
}
|
|
|
|
log_fn(LOG_DEBUG,"Adding new entry '%s'",line);
|
|
|
|
if(router_add_exit_policy_from_string(router,line) < 0)
|
|
|
|
log_fn(LOG_WARNING,"Malformed exit policy %s; skipping.", line);
|
2003-10-08 01:04:31 +02:00
|
|
|
if(last)
|
|
|
|
return;
|
|
|
|
s = e+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
router_add_exit_policy_from_string(routerinfo_t *router,
|
|
|
|
char *s)
|
2003-10-08 00:09:09 +02:00
|
|
|
{
|
|
|
|
directory_token_t tok;
|
|
|
|
char *tmp, *cp;
|
|
|
|
int r;
|
2003-10-08 01:02:37 +02:00
|
|
|
int len, idx;
|
2003-10-08 00:09:09 +02:00
|
|
|
|
2003-10-08 00:15:47 +02:00
|
|
|
len = strlen(s);
|
|
|
|
tmp = cp = tor_malloc(len+2);
|
2003-10-08 01:02:37 +02:00
|
|
|
for (idx = 0; idx < len; ++idx) {
|
|
|
|
tmp[idx] = tolower(s[idx]);
|
|
|
|
}
|
2003-10-08 00:15:47 +02:00
|
|
|
tmp[len]='\n';
|
|
|
|
tmp[len+1]='\0';
|
2003-10-08 00:09:09 +02:00
|
|
|
if (router_get_next_token(&cp, &tok)) {
|
|
|
|
log_fn(LOG_WARNING, "Error reading exit policy: %s", tok.val.error);
|
|
|
|
free(tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (tok.tp != K_ACCEPT && tok.tp != K_REJECT) {
|
|
|
|
log_fn(LOG_WARNING, "Expected 'accept' or 'reject'.");
|
|
|
|
free(tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
r = router_add_exit_policy(router, &tok);
|
|
|
|
free(tmp);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
static int router_add_exit_policy(routerinfo_t *router,
|
|
|
|
directory_token_t *tok) {
|
2003-04-07 06:38:19 +02:00
|
|
|
struct exit_policy_t *tmpe, *newe;
|
2003-05-07 20:30:46 +02:00
|
|
|
char *arg, *colon;
|
2003-04-07 06:38:19 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
if (tok->val.cmd.n_args != 1)
|
|
|
|
return -1;
|
|
|
|
arg = tok->val.cmd.args[0];
|
2003-04-07 06:38:19 +02:00
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
newe = tor_malloc(sizeof(struct exit_policy_t));
|
2003-04-07 06:38:19 +02:00
|
|
|
memset(newe,0,sizeof(struct exit_policy_t));
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
newe->string = tor_malloc(8+strlen(arg));
|
2003-05-07 20:30:46 +02:00
|
|
|
if (tok->tp == K_REJECT) {
|
|
|
|
strcpy(newe->string, "reject ");
|
2003-04-07 06:38:19 +02:00
|
|
|
newe->policy_type = EXIT_POLICY_REJECT;
|
|
|
|
} else {
|
2003-05-07 20:30:46 +02:00
|
|
|
assert(tok->tp == K_ACCEPT);
|
|
|
|
strcpy(newe->string, "accept ");
|
|
|
|
newe->policy_type = EXIT_POLICY_ACCEPT;
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
strcat(newe->string, arg);
|
|
|
|
|
|
|
|
colon = strchr(arg,':');
|
|
|
|
if(!colon)
|
2003-04-07 06:38:19 +02:00
|
|
|
goto policy_read_failed;
|
2003-05-07 20:30:46 +02:00
|
|
|
*colon = 0;
|
2003-10-04 05:29:09 +02:00
|
|
|
newe->address = tor_strdup(arg);
|
|
|
|
newe->port = tor_strdup(colon+1);
|
2003-04-07 06:38:19 +02:00
|
|
|
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"%s %s:%s",
|
2003-08-14 05:52:51 +02:00
|
|
|
newe->policy_type == EXIT_POLICY_REJECT ? "reject" : "accept",
|
|
|
|
newe->address, newe->port);
|
2003-04-07 06:38:19 +02:00
|
|
|
|
|
|
|
/* now link newe onto the end of exit_policy */
|
|
|
|
|
|
|
|
if(!router->exit_policy) {
|
|
|
|
router->exit_policy = newe;
|
2003-05-07 20:30:46 +02:00
|
|
|
return 0;
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for(tmpe=router->exit_policy; tmpe->next; tmpe=tmpe->next) ;
|
|
|
|
tmpe->next = newe;
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
return 0;
|
2003-04-07 06:38:19 +02:00
|
|
|
|
|
|
|
policy_read_failed:
|
|
|
|
assert(newe->string);
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_WARNING,"Couldn't parse line '%s'. Dropping", newe->string);
|
2003-04-07 06:38:19 +02:00
|
|
|
if(newe->string)
|
|
|
|
free(newe->string);
|
|
|
|
if(newe->address)
|
|
|
|
free(newe->address);
|
|
|
|
if(newe->port)
|
|
|
|
free(newe->port);
|
|
|
|
free(newe);
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1;
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
|
|
|
|
2003-04-08 08:44:38 +02:00
|
|
|
/* Return 0 if my exit policy says to allow connection to conn.
|
|
|
|
* Else return -1.
|
|
|
|
*/
|
|
|
|
int router_compare_to_exit_policy(connection_t *conn) {
|
|
|
|
struct exit_policy_t *tmpe;
|
2003-10-08 00:18:14 +02:00
|
|
|
struct in_addr in;
|
2003-04-08 08:44:38 +02:00
|
|
|
|
2003-10-01 03:49:53 +02:00
|
|
|
assert(desc_routerinfo);
|
2003-04-08 08:44:38 +02:00
|
|
|
|
2003-10-01 03:49:53 +02:00
|
|
|
for(tmpe=desc_routerinfo->exit_policy; tmpe; tmpe=tmpe->next) {
|
2003-04-08 08:44:38 +02:00
|
|
|
assert(tmpe->address);
|
|
|
|
assert(tmpe->port);
|
|
|
|
|
2003-10-08 01:04:31 +02:00
|
|
|
log_fn(LOG_DEBUG,"Considering exit policy %s:%s",tmpe->address, tmpe->port);
|
2003-10-08 01:54:02 +02:00
|
|
|
if(strcmp(tmpe->address,"*") &&
|
|
|
|
inet_aton(tmpe->address,&in) == 0) { /* malformed IP. reject. */
|
2003-10-08 00:18:14 +02:00
|
|
|
log_fn(LOG_WARNING,"Malformed IP %s in exit policy. Rejecting.",tmpe->address);
|
|
|
|
return -1;
|
|
|
|
}
|
2003-10-08 01:04:31 +02:00
|
|
|
if((!strcmp(tmpe->address,"*") || conn->addr == ntohl(in.s_addr)) &&
|
2003-10-08 00:18:14 +02:00
|
|
|
(!strcmp(tmpe->port,"*") || atoi(tmpe->port) == conn->port)) {
|
|
|
|
log_fn(LOG_INFO,"Address '%s' matches '%s' and port '%s' matches '%d'. %s.",
|
|
|
|
tmpe->address, conn->address,
|
2003-04-08 08:44:38 +02:00
|
|
|
tmpe->port, conn->port,
|
|
|
|
tmpe->policy_type == EXIT_POLICY_ACCEPT ? "Accepting" : "Rejecting");
|
|
|
|
if(tmpe->policy_type == EXIT_POLICY_ACCEPT)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0; /* accept all by default. */
|
|
|
|
}
|
|
|
|
|
2003-10-01 02:43:34 +02:00
|
|
|
const char *router_get_my_descriptor(void) {
|
|
|
|
if (!desc_routerinfo) {
|
2003-10-01 03:08:20 +02:00
|
|
|
if (router_rebuild_descriptor())
|
2003-10-01 02:43:34 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
log_fn(LOG_DEBUG,"my desc is '%s'",descriptor);
|
|
|
|
return descriptor;
|
|
|
|
}
|
|
|
|
const routerinfo_t *router_get_desc_routerinfo(void) {
|
|
|
|
if (!desc_routerinfo) {
|
2003-10-01 03:08:20 +02:00
|
|
|
if (router_rebuild_descriptor())
|
2003-10-01 02:43:34 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return desc_routerinfo;
|
|
|
|
}
|
|
|
|
|
2003-10-01 03:08:20 +02:00
|
|
|
int router_rebuild_descriptor(void) {
|
2003-10-01 02:43:34 +02:00
|
|
|
routerinfo_t *ri;
|
|
|
|
char localhostname[256];
|
|
|
|
char *address = options.Address;
|
|
|
|
|
|
|
|
if(!address) { /* if not specified in config, we find a default */
|
|
|
|
if(gethostname(localhostname,sizeof(localhostname)) < 0) {
|
|
|
|
log_fn(LOG_WARNING,"Error obtaining local hostname");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
address = localhostname;
|
|
|
|
}
|
|
|
|
ri = tor_malloc(sizeof(routerinfo_t));
|
2003-10-04 05:29:09 +02:00
|
|
|
ri->address = tor_strdup(address);
|
|
|
|
ri->nickname = tor_strdup(options.Nickname);
|
2003-10-01 02:43:34 +02:00
|
|
|
/* No need to set addr. */
|
|
|
|
ri->or_port = options.ORPort;
|
|
|
|
ri->ap_port = options.APPort;
|
|
|
|
ri->dir_port = options.DirPort;
|
|
|
|
ri->published_on = time(NULL);
|
|
|
|
ri->onion_pkey = crypto_pk_dup_key(get_onion_key());
|
|
|
|
ri->link_pkey = crypto_pk_dup_key(get_link_key());
|
|
|
|
ri->identity_pkey = crypto_pk_dup_key(get_identity_key());
|
|
|
|
ri->bandwidth = options.TotalBandwidth;
|
2003-10-08 01:04:31 +02:00
|
|
|
ri->exit_policy = NULL; /* zero it out first */
|
|
|
|
router_add_exit_policy_from_config(ri);
|
2003-10-01 02:43:34 +02:00
|
|
|
if (desc_routerinfo)
|
|
|
|
routerinfo_free(desc_routerinfo);
|
|
|
|
desc_routerinfo = ri;
|
|
|
|
if (router_dump_router_to_string(descriptor, 8192, ri, get_identity_key())<0) {
|
|
|
|
log_fn(LOG_WARNING, "Couldn't dump router to string.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_platform_str(char *platform, int len)
|
|
|
|
{
|
2003-10-02 00:31:13 +02:00
|
|
|
snprintf(platform, len-1, "Tor %s on %s", VERSION, get_uname());
|
|
|
|
platform[len-1] = '\0';
|
|
|
|
return;
|
2003-10-01 02:43:34 +02:00
|
|
|
}
|
|
|
|
|
2003-10-02 00:31:13 +02:00
|
|
|
#define DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
|
2003-10-01 02:43:34 +02:00
|
|
|
int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
|
|
|
|
crypto_pk_env_t *ident_key) {
|
|
|
|
char *onion_pkey;
|
|
|
|
char *link_pkey;
|
|
|
|
char *identity_pkey;
|
|
|
|
char platform[256];
|
|
|
|
char digest[20];
|
|
|
|
char signature[128];
|
|
|
|
char published[32];
|
|
|
|
int onion_pkeylen, link_pkeylen, identity_pkeylen;
|
|
|
|
int written;
|
|
|
|
int result=0;
|
|
|
|
struct exit_policy_t *tmpe;
|
2003-10-02 00:31:13 +02:00
|
|
|
#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
|
|
|
|
char *s_tmp, *s_dup;
|
|
|
|
routerinfo_t *ri_tmp;
|
|
|
|
#endif
|
2003-10-01 02:43:34 +02:00
|
|
|
|
|
|
|
get_platform_str(platform, sizeof(platform));
|
|
|
|
|
2003-10-02 00:31:13 +02:00
|
|
|
if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) {
|
|
|
|
log_fn(LOG_WARNING,"Tried to sign a router with a private key that didn't match router's public key!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-10-01 02:43:34 +02:00
|
|
|
if(crypto_pk_write_public_key_to_string(router->onion_pkey,
|
|
|
|
&onion_pkey,&onion_pkeylen)<0) {
|
|
|
|
log_fn(LOG_WARNING,"write onion_pkey to string failed!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(crypto_pk_write_public_key_to_string(router->identity_pkey,
|
|
|
|
&identity_pkey,&identity_pkeylen)<0) {
|
|
|
|
log_fn(LOG_WARNING,"write identity_pkey to string failed!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(crypto_pk_write_public_key_to_string(router->link_pkey,
|
|
|
|
&link_pkey,&link_pkeylen)<0) {
|
|
|
|
log_fn(LOG_WARNING,"write link_pkey to string failed!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&router->published_on));
|
|
|
|
|
|
|
|
result = snprintf(s, maxlen,
|
|
|
|
"router %s %s %d %d %d %d\n"
|
|
|
|
"platform %s\n"
|
|
|
|
"published %s\n"
|
|
|
|
"onion-key\n%s"
|
|
|
|
"link-key\n%s"
|
|
|
|
"signing-key\n%s",
|
|
|
|
router->nickname,
|
|
|
|
router->address,
|
|
|
|
router->or_port,
|
|
|
|
router->ap_port,
|
|
|
|
router->dir_port,
|
|
|
|
router->bandwidth,
|
|
|
|
platform,
|
|
|
|
published,
|
|
|
|
onion_pkey, link_pkey, identity_pkey);
|
|
|
|
|
|
|
|
free(onion_pkey);
|
|
|
|
free(link_pkey);
|
|
|
|
free(identity_pkey);
|
|
|
|
|
|
|
|
if(result < 0 || result >= maxlen) {
|
|
|
|
/* apparently different glibcs do different things on snprintf error.. so check both */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
written = result;
|
|
|
|
|
|
|
|
for(tmpe=router->exit_policy; tmpe; tmpe=tmpe->next) {
|
|
|
|
result = snprintf(s+written, maxlen-written, "%s %s:%s\n",
|
|
|
|
tmpe->policy_type == EXIT_POLICY_ACCEPT ? "accept" : "reject",
|
|
|
|
tmpe->address, tmpe->port);
|
|
|
|
if(result < 0 || result+written > maxlen) {
|
|
|
|
/* apparently different glibcs do different things on snprintf error.. so check both */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
written += result;
|
|
|
|
}
|
|
|
|
if (written > maxlen-256) /* Not enough room for signature. */
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
strcat(s+written, "router-signature\n");
|
|
|
|
written += strlen(s+written);
|
|
|
|
s[written] = '\0';
|
|
|
|
if (router_get_router_hash(s, digest) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (crypto_pk_private_sign(ident_key, digest, 20, signature) < 0) {
|
|
|
|
log_fn(LOG_WARNING, "Error signing digest");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
strcat(s+written, "-----BEGIN SIGNATURE-----\n");
|
|
|
|
written += strlen(s+written);
|
|
|
|
if (base64_encode(s+written, maxlen-written, signature, 128) < 0) {
|
|
|
|
log_fn(LOG_WARNING, "Couldn't base64-encode signature");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
written += strlen(s+written);
|
|
|
|
strcat(s+written, "-----END SIGNATURE-----\n");
|
|
|
|
written += strlen(s+written);
|
|
|
|
|
|
|
|
if (written > maxlen-2)
|
|
|
|
return -1;
|
|
|
|
/* include a last '\n' */
|
|
|
|
s[written] = '\n';
|
|
|
|
s[written+1] = 0;
|
2003-10-02 00:31:13 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
|
2003-10-04 05:29:09 +02:00
|
|
|
s_tmp = s_dup = tor_strdup(s);
|
2003-10-02 00:31:13 +02:00
|
|
|
ri_tmp = router_get_entry_from_string(&s_tmp);
|
|
|
|
if (!ri_tmp) {
|
|
|
|
log_fn(LOG_ERR, "We just generated a router descriptor we can't parse: <<%s>>",
|
|
|
|
s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(s_dup);
|
|
|
|
routerinfo_free(ri_tmp);
|
|
|
|
#endif
|
|
|
|
|
2003-10-01 02:43:34 +02:00
|
|
|
return written+1;
|
|
|
|
}
|
|
|
|
|
2003-04-07 04:12:02 +02:00
|
|
|
/*
|
|
|
|
Local Variables:
|
|
|
|
mode:c
|
|
|
|
indent-tabs-mode:nil
|
|
|
|
c-basic-offset:2
|
|
|
|
End:
|
|
|
|
*/
|