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;