diff --git a/doc/TODO b/doc/TODO index d899f6dbd5..c13d939952 100644 --- a/doc/TODO +++ b/doc/TODO @@ -19,12 +19,12 @@ For scalability: For dtor: NICK pre1: - - make all ORs serve the directory too. - - "AuthoritativeDir 1" for dirservers - - non-authorative servers with dirport publish opt dircacheport - - make clients read that and use it. - - make clients able to read a normal dirport from non-trusted OR too - - make ORs parse-and-keep the directory they pull down + . make all ORs serve the directory too. + o "AuthoritativeDir 1" for dirservers + o non-authorative servers with dirport publish opt dircacheport + o make clients read that and use it. + o make clients able to read a normal dirport from non-trusted OR too + o make ORs parse-and-keep-and-serve the directory they pull down - authoritativedirservers should pull down directories from other authdirservers, to merge descriptors. - Have clients and dirservers preserve reputation info over @@ -35,12 +35,16 @@ NICK pre1: - distinguish directory-is-dirty from runninglist-is-dirty - ORs keep this too, and serve it - tor remembers descriptor-lists across reboots. - - Packages define datadir as /var/lib/tor/. If no datadir is defined, + . Packages define datadir as /var/lib/tor/. If no datadir is defined, then choose, make, and secure ~/.tor as datadir. - - Contact info, pgp fingerprint, comments in router desc. - - Add a ContactInfo line to torrc, which gets published in + o Adjust tor + o Change torrc.sample + - Change packages + - Look in ~/.torrc if no */etc/torrc is found? + o Contact info, pgp fingerprint, comments in router desc. + o Add a ContactInfo line to torrc, which gets published in descriptor (as opt) - - write tor version at the top of each log file + o write tor version at the top of each log file pre2: - refer to things by key: diff --git a/src/common/log.c b/src/common/log.c index 3e55501dd7..05f656c176 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -48,20 +48,12 @@ static INLINE const char *sev_to_string(int severity) { /** Linked list of logfile_t. */ static logfile_t *logfiles = NULL; -/** Helper: Format a log message into a fixed-sized buffer. (This is - * factored out of logv so that we never format a message more - * than once.) - */ -static INLINE void format_msg(char *buf, size_t buf_len, - int severity, const char *funcname, - const char *format, va_list ap) +static INLINE size_t _log_prefix(char *buf, size_t buf_len, int severity) { time_t t; struct timeval now; size_t n; - buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */ - tor_gettimeofday(&now); t = (time_t)now.tv_sec; @@ -73,6 +65,45 @@ static INLINE void format_msg(char *buf, size_t buf_len, n = buf_len-1; /* the *nprintf funcs return how many bytes they * _would_ print, if the output is truncated. * Subtract one because the count doesn't include the \0 */ + return n; +} + +/** If lf refers to an actual file that we have just opened, and the file + * contains no data, log an "opening new logfile" message at the top. **/ +static void log_tor_version(logfile_t *lf) +{ + char buf[256]; + size_t n; + + if (!lf->needs_close) + /* If it doesn't get closed, it isn't really a file. */ + return; + if (lf->is_temporary) + /* If it's temporary, it isn't really a file. */ + return; + if (ftell(lf->file) != 0) + /* We aren't at the start of the file; no need to log. */ + return; + n = _log_prefix(buf, 250, LOG_NOTICE); + n += snprintf(buf+n, 250-n, "Tor %s creating new log file\n", VERSION); + if (n>250) + n = 250; + buf[n+1]='\0'; + fputs(buf, lf->file); +} + +/** Helper: Format a log message into a fixed-sized buffer. (This is + * factored out of logv so that we never format a message more + * than once.) + */ +static INLINE void format_msg(char *buf, size_t buf_len, + int severity, const char *funcname, + const char *format, va_list ap) +{ + size_t n; + buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */ + + n = _log_prefix(buf, buf_len, severity); if (funcname) { n += snprintf(buf+n, buf_len-n, "%s(): ", funcname); @@ -159,6 +190,7 @@ void reset_logs() if (lf->needs_close) { fclose(lf->file); lf->file = fopen(lf->filename, "a"); + log_tor_version(lf); } } } @@ -224,6 +256,7 @@ int add_file_log(int loglevelMin, int loglevelMax, const char *filename) if (!f) return -1; add_stream_log(loglevelMin, loglevelMax, filename, f); logfiles->needs_close = 1; + log_tor_version(logfiles); return 0; } diff --git a/src/or/config.c b/src/or/config.c index 332a6e009f..10ac500288 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -188,10 +188,13 @@ static int config_assign(or_options_t *options, struct config_line_t *list) { /* string options */ config_compare(list, "Address", CONFIG_TYPE_STRING, &options->Address) || + config_compare(list, "AuthoritativeDirectory",CONFIG_TYPE_BOOL, &options->AuthoritativeDir) || config_compare(list, "BandwidthRate", CONFIG_TYPE_INT, &options->BandwidthRate) || config_compare(list, "BandwidthBurst", CONFIG_TYPE_INT, &options->BandwidthBurst) || + config_compare(list, "ContactInfo", CONFIG_TYPE_STRING, &options->ContactInfo) || + config_compare(list, "DebugLogFile", CONFIG_TYPE_STRING, &options->DebugLogFile) || config_compare(list, "DataDirectory", CONFIG_TYPE_STRING, &options->DataDirectory) || config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) || @@ -627,10 +630,12 @@ int getconfig(int argc, char **argv, or_options_t *options) { result = -1; } +#if 0 if(options->ORPort && options->DataDirectory == NULL) { log(LOG_WARN,"DataDirectory option required if ORPort is set, but not found."); result = -1; } +#endif if (options->ORPort) { if (options->Nickname == NULL) { @@ -675,6 +680,11 @@ int getconfig(int argc, char **argv, or_options_t *options) { result = -1; } + if(options->AuthoritativeDir && !options->DirPort) { + log(LOG_WARN,"Running as authoritative directory, but no DirPort set."); + result = -1; + } + if(options->SocksPort > 1 && (options->PathlenCoinWeight < 0.0 || options->PathlenCoinWeight >= 1.0)) { log(LOG_WARN,"PathlenCoinWeight option must be >=0.0 and <1.0."); @@ -880,6 +890,33 @@ void exit_policy_free(struct exit_policy_t *p) { } } +const char *get_data_directory(or_options_t *options) { + const char *d; + char buf[1024]; + const char *home; + size_t n; + if (options->DataDirectory) + d = options->DataDirectory; + else + d = "~/.tor"; + + if (!strncmp(d,"~/",2)) { + home = getenv("HOME"); + if (!home) { + log_fn(LOG_ERR, "Couldn't find $HOME environment variable for data directory %s", d); + exit(1); + } + n = snprintf(buf,1020,"%s/%s",home,d+2); + if (n>=1020) { + log_fn(LOG_ERR, "Overlong data directory name."); + exit(1); + } + tor_free(options->DataDirectory); + options->DataDirectory = tor_strdup(buf); + } + return options->DataDirectory; +} + /* Local Variables: mode:c diff --git a/src/or/dirserv.c b/src/or/dirserv.c index d2d41627f2..e8e7278926 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -576,6 +576,23 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen, /** Most recently generated encoded signed directory. */ static char *the_directory = NULL; static int the_directory_len = -1; +static char *cached_directory = NULL; +static time_t cached_directory_published = 0; +static int cached_directory_len = -1; + +void dirserv_set_cached_directory(const char *directory, time_t when) +{ + time_t now; + if (!options.AuthoritativeDir) + return; + now = time(NULL); + if (when>cached_directory_published && + whendirectory to the most recently generated encoded signed * directory, generating a new one as necessary. */ @@ -583,6 +600,15 @@ size_t dirserv_get_directory(const char **directory) { char *new_directory; char filename[512]; + if (!options.AuthoritativeDir) { + if (cached_directory) { + *directory = cached_directory; + return (size_t) cached_directory_len; + } else { + /* no directory yet retrieved */ + return 0; + } + } if (the_directory_is_dirty) { new_directory = tor_malloc(MAX_DIR_SIZE); if (dirserv_dump_directory_to_string(new_directory, MAX_DIR_SIZE, diff --git a/src/or/main.c b/src/or/main.c index 4f40f8adb2..983e9a34dd 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -576,6 +576,13 @@ static int init_from_config(int argc, char **argv) { } } + /* Ensure data directory is private; create if possible. */ + if (check_private_dir(get_data_directory(&options), 1) != 0) { + log_fn(LOG_ERR, "Couldn't access/create private data directory %s", + get_data_directory(&options)); + return -1; + } + /* Start backgrounding the process, if requested. */ if (options.RunAsDaemon) { start_daemon(options.DataDirectory); diff --git a/src/or/or.h b/src/or/or.h index a91fae4199..e6a014dc53 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -363,7 +363,6 @@ #define RELAY_COMMAND_INTRODUCE2 35 #define RELAY_COMMAND_RENDEZVOUS1 36 #define RELAY_COMMAND_RENDEZVOUS2 37 -/* DOCDOC Spec these next two. */ #define RELAY_COMMAND_INTRO_ESTABLISHED 38 #define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39 #define RELAY_COMMAND_INTRODUCE_ACK 40 @@ -823,6 +822,7 @@ typedef struct { int ORPort; /**< Port to listen on for OR connections. */ int SocksPort; /**< Port to listen on for SOCKS connections. */ int DirPort; /**< Port to listen on for directory connections. */ + int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */ int MaxConn; /**< Maximum number of simultaneous connections. */ int TrafficShaping; /**< Unused. */ int LinkPadding; /**< Unused. */ @@ -848,6 +848,7 @@ typedef struct { * other ORs are running. */ struct config_line_t *RendConfigLines; /**< List of configuration lines * for rendezvous services. */ + char *ContactInfo; /** Contact info to be published in the directory */ } or_options_t; /* XXX are these good enough defaults? */ @@ -989,6 +990,7 @@ int config_init_logs(or_options_t *options); void config_parse_exit_policy(struct config_line_t *cfg, struct exit_policy_t **dest); void exit_policy_free(struct exit_policy_t *p); +const char *get_data_directory(or_options_t *options); /********************************* connection.c ***************************/ @@ -1136,6 +1138,7 @@ int dirserv_dump_directory_to_string(char *s, unsigned int maxlen, void directory_set_dirty(void); size_t dirserv_get_directory(const char **cp); size_t dirserv_get_runningrouters(const char **rr); +void dirserv_set_cached_directory(const char *directory, time_t when); /********************************* dns.c ***************************/ diff --git a/src/or/router.c b/src/or/router.c index ebdea64cdf..bd9d5276ca 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -532,8 +532,10 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, router->address, router->or_port, router->socks_port, - router->dir_port, - /* XXX008 only use dir_port here if authoritative server, else use opt line below */ + /* Due to an 0.0.7 bug, we can't actually say that we have a dirport unles + * we're an authoritative directory. + */ + router->is_trusted_dir ? router->dir_port : 0, router->platform, published, (int) router->bandwidthrate, @@ -550,6 +552,24 @@ int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router, /* From now on, we use 'written' to remember the current length of 's'. */ written = result; + if (router->dir_port && !router->is_trusted_dir) { + /* dircacheport wasn't recognized before 0.0.8pre. (When 0.0.7 is gone, + * we can fold this back into dirport anyway.) + result = snprintf(s+written,maxlen-written, "opt dircacheport %d\n", + router->dir_port); + if (result<0 || result+written > maxlen) + return -1; + written += result; + } + + if (options.ContactInfo && strlen(options.ContactInfo)) { + result = snprintf(s+written,maxlen-written, "opt contact %s\n", + options.ContactInfo); + if (result<0 || result+written > maxlen) + return -1; + written += result; + } + /* Write the exit policy to the end of 's'. */ for(tmpe=router->exit_policy; tmpe; tmpe=tmpe->next) { in.s_addr = htonl(tmpe->addr); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index b77c796920..ed9a06420d 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -477,6 +477,7 @@ int router_load_routerlist_from_directory(const char *s, log_fn(LOG_WARN, "Error resolving routerlist"); return -1; } + dirserv_set_cached_directory(s, routerlist->published_on); return 0; } diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 1304975015..efd8f3731b 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -39,6 +39,8 @@ typedef enum { K_OPT, K_BANDWIDTH, K_PORTS, + K_DIRCACHEPORT, + K_CONTACT, _UNRECOGNIZED, _ERR, _EOF, @@ -109,7 +111,8 @@ static struct { { "platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ, RTR_ONLY }, { "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ, ANY }, { "opt", K_OPT, CONCAT_ARGS, OBJ_OK, ANY }, - + { "dircacheport", K_DIRCACHEPORT, ARGS, NO_OBJ, RTR_ONLY }, + { "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ, ANY }, { NULL, -1 } }; @@ -587,6 +590,17 @@ routerinfo_t *router_parse_entry_from_string(const char *s, ports_set = 1; } + tok = find_first_by_keyword(tokens, K_DIRCACHEPORT); + if (tok) { + if (router->dir_port) + log_fn(LOG_WARN,"Redundant dircacheport line"); + if (tok->n_args != 1) { + log_fn(LOG_WARN,"Wrong # of arguments to \"dircacheport\""); + goto err; + } + router->dir_port = atoi(tok->args[0]); + } + tok = find_first_by_keyword(tokens, K_BANDWIDTH); if (tok && bw_set) { log_fn(LOG_WARN,"Redundant bandwidth line"); @@ -898,7 +912,7 @@ token_free(directory_token_t *tok) static directory_token_t * get_next_token(const char **s, where_syntax where) { const char *next, *obstart; - int i, done, allocated; + int i, done, allocated, is_opt; directory_token_t *tok; arg_syntax a_syn; obj_syntax o_syn = NO_OBJ; @@ -923,7 +937,17 @@ get_next_token(const char **s, where_syntax where) { tok->error = "Unexpected EOF"; return tok; } /* It's a keyword... but which one? */ - for (i = 0 ; token_table[i].t ; ++i) { + is_opt = !strncmp("opt", *s, next-*s); + if (is_opt) { + *s = eat_whitespace(next); + next = NULL; + if (**s) + next = find_whitespace(*s); + if (!**s || !next) { + RET_ERR("opt without keyword"); + } + } + for (i = 0; token_table[i].t ; ++i) { if (!strncmp(token_table[i].t, *s, next-*s)) { /* We've found the keyword. */ tok->tp = token_table[i].v; @@ -979,16 +1003,29 @@ get_next_token(const char **s, where_syntax where) { } } if (tok->tp == _ERR) { - tok->tp = _UNRECOGNIZED; - next = strchr(*s, '\n'); - if (!next) { - RET_ERR("Unexpected EOF"); + if (is_opt) { + tok->tp = K_OPT; + *s = eat_whitespace_no_nl(next); + next = strchr(*s,'\n'); + if (!next) + RET_ERR("Unexpected EOF"); + tok->args = tor_malloc(sizeof(char*)); + tok->args[0] = tor_strndup(*s,next-*s); + tok->n_args = 1; + *s = eat_whitespace_no_nl(next+1); + a_syn = OBJ_OK; + } else { + tok->tp = _UNRECOGNIZED; + next = strchr(*s, '\n'); + if (!next) { + RET_ERR("Unexpected EOF"); + } + tok->args = tor_malloc(sizeof(char*)); + tok->args[0] = tor_strndup(*s,next-*s); + tok->n_args = 1; + *s = next+1; + o_syn = OBJ_OK; } - tok->args = tor_malloc(sizeof(char*)); - tok->args[0] = tor_strndup(*s,next-*s); - tok->n_args = 1; - *s = next+1; - o_syn = OBJ_OK; } *s = eat_whitespace(*s); if (strncmp(*s, "-----BEGIN ", 11)) { diff --git a/src/or/test.c b/src/or/test.c index caf0814762..5ee5866112 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -666,6 +666,7 @@ test_dir_format() r1.or_port = 9000; r1.socks_port = 9002; r1.dir_port = 9003; + r1.is_trusted_dir = 1; r1.onion_pkey = pk1; r1.identity_pkey = pk2; r1.bandwidthrate = 1000;