1 /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
7 /* How old do we allow a router to get before removing it? (seconds) */
8 #define ROUTER_MAX_AGE (60*60*24)
10 /* How far in the future do we allow a router to get? (seconds) */
11 #define ROUTER_ALLOW_SKEW (30*60)
13 extern or_options_t options
; /* command-line and config-file options */
15 static int the_directory_is_dirty
= 1;
17 static int list_running_servers(char **nicknames_out
);
18 static void directory_remove_unrecognized(void);
20 /************** Fingerprint handling code ************/
22 typedef struct fingerprint_entry_t
{
25 } fingerprint_entry_t
;
27 static fingerprint_entry_t fingerprint_list
[MAX_ROUTERS_IN_DIR
];
28 static int n_fingerprints
= 0;
30 void /* Should be static; exposed for testing */
31 add_fingerprint_to_dir(const char *nickname
, const char *fp
)
34 for (i
= 0; i
< n_fingerprints
; ++i
) {
35 if (!strcasecmp(fingerprint_list
[i
].nickname
,nickname
)) {
36 free(fingerprint_list
[i
].fingerprint
);
37 fingerprint_list
[i
].fingerprint
= tor_strdup(fp
);
41 fingerprint_list
[n_fingerprints
].nickname
= tor_strdup(nickname
);
42 fingerprint_list
[n_fingerprints
].fingerprint
= tor_strdup(fp
);
47 dirserv_add_own_fingerprint(const char *nickname
, crypto_pk_env_t
*pk
)
49 char fp
[FINGERPRINT_LEN
+1];
50 if (crypto_pk_get_fingerprint(pk
, fp
)<0) {
51 log_fn(LOG_ERR
, "Error computing fingerprint");
54 add_fingerprint_to_dir(nickname
, fp
);
58 /* return 0 on success, -1 on failure */
60 dirserv_parse_fingerprint_file(const char *fname
)
63 char line
[FINGERPRINT_LEN
+MAX_NICKNAME_LEN
+20+1];
64 char *nickname
, *fingerprint
;
65 fingerprint_entry_t fingerprint_list_tmp
[MAX_ROUTERS_IN_DIR
];
66 int n_fingerprints_tmp
= 0;
69 if(!(file
= fopen(fname
, "r"))) {
70 log_fn(LOG_WARN
, "Cannot open fingerprint file %s", fname
);
73 while( (result
=parse_line_from_file(line
, sizeof(line
),file
,&nickname
,&fingerprint
)) > 0) {
74 if (strlen(nickname
) > MAX_NICKNAME_LEN
) {
75 log(LOG_WARN
, "Nickname %s too long in fingerprint file. Skipping.", nickname
);
78 if(strlen(fingerprint
) != FINGERPRINT_LEN
||
79 !crypto_pk_check_fingerprint_syntax(fingerprint
)) {
80 log_fn(LOG_WARN
, "Invalid fingerprint (nickname %s, fingerprint %s). Skipping.",
81 nickname
, fingerprint
);
84 for (i
= 0; i
< n_fingerprints_tmp
; ++i
) {
85 if (0==strcasecmp(fingerprint_list_tmp
[i
].nickname
, nickname
)) {
86 log(LOG_WARN
, "Duplicate nickname %s. Skipping.",nickname
);
87 break; /* out of the for. the 'if' below means skip to the next line. */
90 if(i
== n_fingerprints_tmp
) { /* not a duplicate */
91 fingerprint_list_tmp
[n_fingerprints_tmp
].nickname
= tor_strdup(nickname
);
92 fingerprint_list_tmp
[n_fingerprints_tmp
].fingerprint
= tor_strdup(fingerprint
);
97 if(result
== 0) { /* eof; replace the global fingerprints list. */
98 dirserv_free_fingerprint_list();
99 memcpy(fingerprint_list
, fingerprint_list_tmp
,
100 sizeof(fingerprint_entry_t
)*n_fingerprints_tmp
);
101 n_fingerprints
= n_fingerprints_tmp
;
102 /* Delete any routers whose fingerprints we no longer recognize */
103 directory_remove_unrecognized();
107 log_fn(LOG_WARN
, "Error reading from fingerprint file");
108 for (i
= 0; i
< n_fingerprints_tmp
; ++i
) {
109 free(fingerprint_list_tmp
[i
].nickname
);
110 free(fingerprint_list_tmp
[i
].fingerprint
);
115 /* return 1 if router's identity and nickname match,
116 * -1 if they don't match, 0 if the nickname is not known. */
118 dirserv_router_fingerprint_is_known(const routerinfo_t
*router
)
121 fingerprint_entry_t
*ent
=NULL
;
122 char fp
[FINGERPRINT_LEN
+1];
124 log_fn(LOG_DEBUG
, "%d fingerprints known.", n_fingerprints
);
125 for (i
=0;i
<n_fingerprints
;++i
) {
126 log_fn(LOG_DEBUG
,"%s vs %s", router
->nickname
, fingerprint_list
[i
].nickname
);
127 if (!strcasecmp(router
->nickname
,fingerprint_list
[i
].nickname
)) {
128 ent
= &fingerprint_list
[i
];
133 if (!ent
) { /* No such server known */
134 log_fn(LOG_INFO
,"no fingerprint found for %s",router
->nickname
);
137 if (crypto_pk_get_fingerprint(router
->identity_pkey
, fp
)) {
138 log_fn(LOG_WARN
,"error computing fingerprint");
141 if (0==strcasecmp(ent
->fingerprint
, fp
)) {
142 log_fn(LOG_DEBUG
,"good fingerprint for %s",router
->nickname
);
143 return 1; /* Right fingerprint. */
145 log_fn(LOG_WARN
,"mismatched fingerprint for %s",router
->nickname
);
146 return -1; /* Wrong fingerprint. */
151 dirserv_free_fingerprint_list()
154 for (i
= 0; i
< n_fingerprints
; ++i
) {
155 free(fingerprint_list
[i
].nickname
);
156 free(fingerprint_list
[i
].fingerprint
);
164 typedef struct descriptor_entry_t
{
169 routerinfo_t
*router
;
170 } descriptor_entry_t
;
172 static descriptor_entry_t
*descriptor_list
[MAX_ROUTERS_IN_DIR
];
173 static int n_descriptors
= 0;
175 static void free_descriptor_entry(descriptor_entry_t
*desc
)
177 tor_free(desc
->descriptor
);
178 tor_free(desc
->nickname
);
179 routerinfo_free(desc
->router
);
184 dirserv_free_descriptors()
187 for (i
= 0; i
< n_descriptors
; ++i
) {
188 free_descriptor_entry(descriptor_list
[i
]);
193 /* Return 1 if descriptor is well-formed and accepted;
194 * 0 if well-formed and server or descriptor is unapproved;
195 * -1 if not well-formed or other error.
197 * Update *desc to point after the descriptor if the
198 * descriptor is well-formed.
201 dirserv_add_descriptor(const char **desc
)
203 descriptor_entry_t
**desc_ent_ptr
;
204 routerinfo_t
*ri
= NULL
;
207 char *desc_tmp
= NULL
;
212 start
= strstr(*desc
, "router ");
214 log_fn(LOG_WARN
, "no 'router' line found. This is not a descriptor.");
217 if ((end
= strstr(start
+6, "\nrouter "))) {
218 ++end
; /* Include NL. */
219 } else if ((end
= strstr(start
+6, "\ndirectory-signature"))) {
222 end
= start
+strlen(start
);
224 desc_len
= end
-start
;
225 cp
= desc_tmp
= tor_strndup(start
, desc_len
);
227 /* Check: is the descriptor syntactically valid? */
228 ri
= router_get_entry_from_string(cp
, NULL
);
231 log(LOG_WARN
, "Couldn't parse descriptor");
234 /* Okay. Now check whether the fingerprint is recognized. */
235 r
= dirserv_router_fingerprint_is_known(ri
);
238 char fp
[FINGERPRINT_LEN
+1];
239 log_fn(LOG_WARN
, "Unknown nickname %s (%s:%d). Not adding.",
240 ri
->nickname
, ri
->address
, ri
->or_port
);
241 if (crypto_pk_get_fingerprint(ri
->identity_pkey
, fp
) < 0) {
242 log_fn(LOG_WARN
, "Error computing fingerprint for %s", ri
->nickname
);
244 log_fn(LOG_WARN
, "Fingerprint line: %s %s", ri
->nickname
, fp
);
247 log_fn(LOG_WARN
, "Known nickname %s, wrong fingerprint. Not adding.", ri
->nickname
);
253 /* Is there too much clock skew? */
255 if (ri
->published_on
> now
+ROUTER_ALLOW_SKEW
) {
256 log_fn(LOG_WARN
, "Publication time for nickname %s is too far in the future; possible clock skew. Not adding.", ri
->nickname
);
261 if (ri
->published_on
< now
-ROUTER_MAX_AGE
) {
262 log_fn(LOG_WARN
, "Publication time for router with nickname %s is too far in the past. Not adding.", ri
->nickname
);
268 /* Do we already have an entry for this router? */
270 for (i
= 0; i
< n_descriptors
; ++i
) {
271 if (!strcasecmp(ri
->nickname
, descriptor_list
[i
]->nickname
)) {
272 desc_ent_ptr
= &descriptor_list
[i
];
277 /* if so, decide whether to update it. */
278 if ((*desc_ent_ptr
)->published
> ri
->published_on
) {
279 /* We already have a newer descriptor */
280 log_fn(LOG_INFO
,"We already have a newer desc for nickname %s. Not adding.",ri
->nickname
);
281 /* This isn't really an error; return success. */
286 /* We don't have a newer one; we'll update this one. */
287 log_fn(LOG_INFO
,"Dirserv updating desc for nickname %s",ri
->nickname
);
288 free_descriptor_entry(*desc_ent_ptr
);
290 /* Add this at the end. */
291 log_fn(LOG_INFO
,"Dirserv adding desc for nickname %s",ri
->nickname
);
292 desc_ent_ptr
= &descriptor_list
[n_descriptors
++];
293 /* XXX check if n_descriptors is too big */
296 (*desc_ent_ptr
) = tor_malloc(sizeof(descriptor_entry_t
));
297 (*desc_ent_ptr
)->nickname
= tor_strdup(ri
->nickname
);
298 (*desc_ent_ptr
)->published
= ri
->published_on
;
299 (*desc_ent_ptr
)->desc_len
= desc_len
;
300 (*desc_ent_ptr
)->descriptor
= tor_malloc(desc_len
+1);
301 strncpy((*desc_ent_ptr
)->descriptor
, start
, desc_len
);
302 (*desc_ent_ptr
)->descriptor
[desc_len
] = '\0';
303 (*desc_ent_ptr
)->router
= ri
;
305 directory_set_dirty();
311 directory_remove_unrecognized(void)
314 for (i
= 0; i
< n_descriptors
; ++i
) {
315 if (dirserv_router_fingerprint_is_known(descriptor_list
[i
]->router
)<=0) {
316 log(LOG_INFO
, "Router %s is no longer recognized",
317 descriptor_list
[i
]->nickname
);
318 free_descriptor_entry(descriptor_list
[i
]);
319 descriptor_list
[i
--] = descriptor_list
[--n_descriptors
];
325 directory_set_dirty()
327 the_directory_is_dirty
= 1;
331 dirserv_init_from_directory_string(const char *dir
)
333 const char *cp
= dir
;
335 cp
= strstr(cp
, "\nrouter ");
338 if (dirserv_add_descriptor(&cp
) < 0) {
341 --cp
; /*Back up to newline.*/
347 list_running_servers(char **nicknames_out
)
349 char *nickname_lst
[MAX_ROUTERS_IN_DIR
];
350 connection_t
**connection_array
;
356 *nicknames_out
= NULL
;
357 nickname_lst
[n
++] = options
.Nickname
;
359 get_connection_array(&connection_array
, &n_conns
);
360 for (i
= 0; i
<n_conns
; ++i
) {
361 conn
= connection_array
[i
];
362 if (conn
->type
!= CONN_TYPE_OR
|| conn
->state
!= OR_CONN_STATE_OPEN
)
363 continue; /* only list successfully handshaked OR's. */
364 if(!conn
->nickname
) /* it's an OP, don't list it */
366 nickname_lst
[n
++] = conn
->nickname
;
368 length
= n
+ 1; /* spaces + EOS + 1. */
369 for (i
= 0; i
<n
; ++i
) {
370 length
+= strlen(nickname_lst
[i
]);
372 *nicknames_out
= tor_malloc_zero(length
);
374 for (i
= 0; i
<n
; ++i
) {
377 strcat(cp
, nickname_lst
[i
]); /* can't overflow */
384 /* Remove any descriptors from the directory that are more than ROUTER_MAX_AGE
388 dirserv_remove_old_servers(void)
392 cutoff
= time(NULL
) - ROUTER_MAX_AGE
;
393 for (i
= 0; i
< n_descriptors
; ++i
) {
394 if (descriptor_list
[i
]->published
< cutoff
) {
395 /* descriptor_list[i] is too old. Remove it. */
396 free_descriptor_entry(descriptor_list
[i
]);
397 descriptor_list
[i
] = descriptor_list
[n_descriptors
-1];
399 directory_set_dirty();
400 --i
; /* Don't advance the index; consider the new value now at i. */
405 /* Dump all routers currently in the directory into the string <s>, using
406 * at most <maxlen> characters, and signing the directory with <private_key>.
407 * Return 0 on success, -1 on failure.
410 dirserv_dump_directory_to_string(char *s
, int maxlen
,
411 crypto_pk_env_t
*private_key
)
421 if (list_running_servers(&cp
))
423 dirserv_remove_old_servers();
424 published_on
= time(NULL
);
425 strftime(published
, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on
));
429 "recommended-software %s\n"
430 "running-routers %s\n\n", published
, options
.RecommendedVersions
, cp
);
435 for (i
= 0; i
< n_descriptors
; ++i
) {
436 if (strlcat(s
, descriptor_list
[i
]->descriptor
, maxlen
) >= maxlen
)
439 /* These multiple strlcat calls are inefficient, but dwarfed by the RSA
442 if (strlcat(s
, "directory-signature ", maxlen
) >= maxlen
)
444 if (strlcat(s
, options
.Nickname
, maxlen
) >= maxlen
)
446 if (strlcat(s
, "\n", maxlen
) >= maxlen
)
450 if (router_get_dir_hash(s
,digest
)) {
451 log_fn(LOG_WARN
,"couldn't compute digest");
454 if (crypto_pk_private_sign(private_key
, digest
, 20, signature
) < 0) {
455 log_fn(LOG_WARN
,"couldn't sign digest");
458 log(LOG_DEBUG
,"generated directory digest begins with %s",hex_str(digest
,4));
460 if (strlcat(cp
, "-----BEGIN SIGNATURE-----\n", maxlen
) >= maxlen
)
465 if (base64_encode(cp
, maxlen
-i
, signature
, 128) < 0) {
466 log_fn(LOG_WARN
,"couldn't base64-encode signature");
470 if (strlcat(s
, "-----END SIGNATURE-----\n", maxlen
) >= maxlen
)
475 log_fn(LOG_WARN
,"tried to exceed string length.");
479 static char *the_directory
= NULL
;
480 static int the_directory_len
= -1;
482 size_t dirserv_get_directory(const char **directory
)
486 if (the_directory_is_dirty
) {
487 new_directory
= tor_malloc(MAX_DIR_SIZE
);
488 if (dirserv_dump_directory_to_string(new_directory
, MAX_DIR_SIZE
,
489 get_identity_key())) {
490 log(LOG_WARN
, "Error creating directory.");
494 tor_free(the_directory
);
495 the_directory
= new_directory
;
496 the_directory_len
= strlen(the_directory
);
497 log_fn(LOG_INFO
,"New directory (size %d):\n%s",the_directory_len
,
499 the_directory_is_dirty
= 0;
500 /* Now read the directory we just made in order to update our own
501 * router lists. This does more signature checking than is strictly
502 * necessary, but safe is better than sorry. */
503 new_directory
= tor_strdup(the_directory
);
504 /* use a new copy of the dir, since get_dir_from_string scribbles on it */
505 if (router_set_routerlist_from_directory(new_directory
, get_identity_key())) {
506 log_fn(LOG_ERR
, "We just generated a directory we can't parse. Dying.");
510 sprintf(filename
,"%s/cached-directory", options
.DataDirectory
);
511 if(write_str_to_file(filename
,the_directory
) < 0) {
512 log_fn(LOG_WARN
, "Couldn't write cached directory to disk. Ignoring.");
515 log(LOG_INFO
,"Directory still clean, reusing.");
517 *directory
= the_directory
;
518 return the_directory_len
;