Back to index

tor  0.2.3.18-rc
nodelist.c
Go to the documentation of this file.
00001 /* Copyright (c) 2001 Matej Pfajfar.
00002  * Copyright (c) 2001-2004, Roger Dingledine.
00003  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
00004  * Copyright (c) 2007-2012, The Tor Project, Inc. */
00005 /* See LICENSE for licensing information */
00006 
00007 #include "or.h"
00008 #include "config.h"
00009 #include "dirserv.h"
00010 #include "microdesc.h"
00011 #include "networkstatus.h"
00012 #include "nodelist.h"
00013 #include "policies.h"
00014 #include "router.h"
00015 #include "routerlist.h"
00016 
00017 #include <string.h>
00018 
00019 static void nodelist_drop_node(node_t *node, int remove_from_ht);
00020 static void node_free(node_t *node);
00021 
00026 typedef struct nodelist_t {
00027   /* A list of all the nodes. */
00028   smartlist_t *nodes;
00029   /* Hash table to map from node ID digest to node. */
00030   HT_HEAD(nodelist_map, node_t) nodes_by_id;
00031 
00032 } nodelist_t;
00033 
00034 static INLINE unsigned int
00035 node_id_hash(const node_t *node)
00036 {
00037 #if SIZEOF_INT == 4
00038   const uint32_t *p = (const uint32_t*)node->identity;
00039   return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4];
00040 #elif SIZEOF_INT == 8
00041   const uint64_t *p = (const uint32_t*)node->identity;
00042   const uint32_t *p32 = (const uint32_t*)node->identity;
00043   return p[0] ^ p[1] ^ p32[4];
00044 #endif
00045 }
00046 
00047 static INLINE unsigned int
00048 node_id_eq(const node_t *node1, const node_t *node2)
00049 {
00050   return tor_memeq(node1->identity, node2->identity, DIGEST_LEN);
00051 }
00052 
00053 HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq);
00054 HT_GENERATE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq,
00055             0.6, malloc, realloc, free);
00056 
00058 static nodelist_t *the_nodelist=NULL;
00059 
00061 static void
00062 init_nodelist(void)
00063 {
00064   if (PREDICT_UNLIKELY(the_nodelist == NULL)) {
00065     the_nodelist = tor_malloc_zero(sizeof(nodelist_t));
00066     HT_INIT(nodelist_map, &the_nodelist->nodes_by_id);
00067     the_nodelist->nodes = smartlist_new();
00068   }
00069 }
00070 
00072 node_t *
00073 node_get_mutable_by_id(const char *identity_digest)
00074 {
00075   node_t search, *node;
00076   if (PREDICT_UNLIKELY(the_nodelist == NULL))
00077     return NULL;
00078 
00079   memcpy(&search.identity, identity_digest, DIGEST_LEN);
00080   node = HT_FIND(nodelist_map, &the_nodelist->nodes_by_id, &search);
00081   return node;
00082 }
00083 
00086 const node_t *
00087 node_get_by_id(const char *identity_digest)
00088 {
00089   return node_get_mutable_by_id(identity_digest);
00090 }
00091 
00098 static node_t *
00099 node_get_or_create(const char *identity_digest)
00100 {
00101   node_t *node;
00102 
00103   if ((node = node_get_mutable_by_id(identity_digest)))
00104     return node;
00105 
00106   node = tor_malloc_zero(sizeof(node_t));
00107   memcpy(node->identity, identity_digest, DIGEST_LEN);
00108   HT_INSERT(nodelist_map, &the_nodelist->nodes_by_id, node);
00109 
00110   smartlist_add(the_nodelist->nodes, node);
00111   node->nodelist_idx = smartlist_len(the_nodelist->nodes) - 1;
00112 
00113   node->country = -1;
00114 
00115   return node;
00116 }
00117 
00119 node_t *
00120 nodelist_add_routerinfo(routerinfo_t *ri)
00121 {
00122   node_t *node;
00123   init_nodelist();
00124   node = node_get_or_create(ri->cache_info.identity_digest);
00125   node->ri = ri;
00126 
00127   if (node->country == -1)
00128     node_set_country(node);
00129 
00130   if (authdir_mode(get_options())) {
00131     const char *discard=NULL;
00132     uint32_t status = dirserv_router_get_status(ri, &discard);
00133     dirserv_set_node_flags_from_authoritative_status(node, status);
00134   }
00135 
00136   return node;
00137 }
00138 
00144 node_t *
00145 nodelist_add_microdesc(microdesc_t *md)
00146 {
00147   networkstatus_t *ns =
00148     networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC);
00149   const routerstatus_t *rs;
00150   node_t *node;
00151   if (ns == NULL)
00152     return NULL;
00153   init_nodelist();
00154 
00155   /* Microdescriptors don't carry an identity digest, so we need to figure
00156    * it out by looking up the routerstatus. */
00157   rs = router_get_consensus_status_by_descriptor_digest(ns, md->digest);
00158   if (rs == NULL)
00159     return NULL;
00160   node = node_get_mutable_by_id(rs->identity_digest);
00161   if (node) {
00162     if (node->md)
00163       node->md->held_by_nodes--;
00164     node->md = md;
00165     md->held_by_nodes++;
00166   }
00167   return node;
00168 }
00169 
00175 void
00176 nodelist_set_consensus(networkstatus_t *ns)
00177 {
00178   const or_options_t *options = get_options();
00179   int authdir = authdir_mode_v2(options) || authdir_mode_v3(options);
00180 
00181   init_nodelist();
00182   if (ns->flavor == FLAV_MICRODESC)
00183     (void) get_microdesc_cache(); /* Make sure it exists first. */
00184 
00185   SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node,
00186                     node->rs = NULL);
00187 
00188   SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
00189     node_t *node = node_get_or_create(rs->identity_digest);
00190     node->rs = rs;
00191     if (ns->flavor == FLAV_MICRODESC) {
00192       if (node->md == NULL ||
00193           tor_memneq(node->md->digest,rs->descriptor_digest,DIGEST256_LEN)) {
00194         if (node->md)
00195           node->md->held_by_nodes--;
00196         node->md = microdesc_cache_lookup_by_digest256(NULL,
00197                                                        rs->descriptor_digest);
00198         if (node->md)
00199           node->md->held_by_nodes++;
00200       }
00201     }
00202 
00203     node_set_country(node);
00204 
00205     /* If we're not an authdir, believe others. */
00206     if (!authdir) {
00207       node->is_valid = rs->is_valid;
00208       node->is_running = rs->is_flagged_running;
00209       node->is_fast = rs->is_fast;
00210       node->is_stable = rs->is_stable;
00211       node->is_possible_guard = rs->is_possible_guard;
00212       node->is_exit = rs->is_exit;
00213       node->is_bad_directory = rs->is_bad_directory;
00214       node->is_bad_exit = rs->is_bad_exit;
00215       node->is_hs_dir = rs->is_hs_dir;
00216     }
00217 
00218   } SMARTLIST_FOREACH_END(rs);
00219 
00220   nodelist_purge();
00221 
00222   if (! authdir) {
00223     SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
00224       /* We have no routerstatus for this router. Clear flags so we can skip
00225        * it, maybe.*/
00226       if (!node->rs) {
00227         tor_assert(node->ri); /* if it had only an md, or nothing, purge
00228                                * would have removed it. */
00229         if (node->ri->purpose == ROUTER_PURPOSE_GENERAL) {
00230           /* Clear all flags. */
00231           node->is_valid = node->is_running = node->is_hs_dir =
00232             node->is_fast = node->is_stable =
00233             node->is_possible_guard = node->is_exit =
00234             node->is_bad_exit = node->is_bad_directory = 0;
00235         }
00236       }
00237     } SMARTLIST_FOREACH_END(node);
00238   }
00239 }
00240 
00242 static INLINE int
00243 node_is_usable(const node_t *node)
00244 {
00245   return (node->rs) || (node->ri);
00246 }
00247 
00250 void
00251 nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md)
00252 {
00253   node_t *node = node_get_mutable_by_id(identity_digest);
00254   if (node && node->md == md) {
00255     node->md = NULL;
00256     md->held_by_nodes--;
00257   }
00258 }
00259 
00261 void
00262 nodelist_remove_routerinfo(routerinfo_t *ri)
00263 {
00264   node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
00265   if (node && node->ri == ri) {
00266     node->ri = NULL;
00267     if (! node_is_usable(node)) {
00268       nodelist_drop_node(node, 1);
00269       node_free(node);
00270     }
00271   }
00272 }
00273 
00276 static void
00277 nodelist_drop_node(node_t *node, int remove_from_ht)
00278 {
00279   node_t *tmp;
00280   int idx;
00281   if (remove_from_ht) {
00282     tmp = HT_REMOVE(nodelist_map, &the_nodelist->nodes_by_id, node);
00283     tor_assert(tmp == node);
00284   }
00285 
00286   idx = node->nodelist_idx;
00287   tor_assert(idx >= 0);
00288 
00289   tor_assert(node == smartlist_get(the_nodelist->nodes, idx));
00290   smartlist_del(the_nodelist->nodes, idx);
00291   if (idx < smartlist_len(the_nodelist->nodes)) {
00292     tmp = smartlist_get(the_nodelist->nodes, idx);
00293     tmp->nodelist_idx = idx;
00294   }
00295   node->nodelist_idx = -1;
00296 }
00297 
00299 static void
00300 node_free(node_t *node)
00301 {
00302   if (!node)
00303     return;
00304   if (node->md)
00305     node->md->held_by_nodes--;
00306   tor_assert(node->nodelist_idx == -1);
00307   tor_free(node);
00308 }
00309 
00312 void
00313 nodelist_purge(void)
00314 {
00315   node_t **iter;
00316   if (PREDICT_UNLIKELY(the_nodelist == NULL))
00317     return;
00318 
00319   /* Remove the non-usable nodes. */
00320   for (iter = HT_START(nodelist_map, &the_nodelist->nodes_by_id); iter; ) {
00321     node_t *node = *iter;
00322 
00323     if (node->md && !node->rs) {
00324       /* An md is only useful if there is an rs. */
00325       node->md->held_by_nodes--;
00326       node->md = NULL;
00327     }
00328 
00329     if (node_is_usable(node)) {
00330       iter = HT_NEXT(nodelist_map, &the_nodelist->nodes_by_id, iter);
00331     } else {
00332       iter = HT_NEXT_RMV(nodelist_map, &the_nodelist->nodes_by_id, iter);
00333       nodelist_drop_node(node, 0);
00334       node_free(node);
00335     }
00336   }
00337   nodelist_assert_ok();
00338 }
00339 
00341 void
00342 nodelist_free_all(void)
00343 {
00344   if (PREDICT_UNLIKELY(the_nodelist == NULL))
00345     return;
00346 
00347   HT_CLEAR(nodelist_map, &the_nodelist->nodes_by_id);
00348   SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
00349     node->nodelist_idx = -1;
00350     node_free(node);
00351   } SMARTLIST_FOREACH_END(node);
00352 
00353   smartlist_free(the_nodelist->nodes);
00354 
00355   tor_free(the_nodelist);
00356 }
00357 
00361 void
00362 nodelist_assert_ok(void)
00363 {
00364   routerlist_t *rl = router_get_routerlist();
00365   networkstatus_t *ns = networkstatus_get_latest_consensus();
00366   digestmap_t *dm;
00367 
00368   if (!the_nodelist)
00369     return;
00370 
00371   dm = digestmap_new();
00372 
00373   /* every routerinfo in rl->routers should be in the nodelist. */
00374   if (rl) {
00375     SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) {
00376       const node_t *node = node_get_by_id(ri->cache_info.identity_digest);
00377       tor_assert(node && node->ri == ri);
00378       tor_assert(fast_memeq(ri->cache_info.identity_digest,
00379                              node->identity, DIGEST_LEN));
00380       tor_assert(! digestmap_get(dm, node->identity));
00381       digestmap_set(dm, node->identity, (void*)node);
00382     } SMARTLIST_FOREACH_END(ri);
00383   }
00384 
00385   /* every routerstatus in ns should be in the nodelist */
00386   if (ns) {
00387     SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
00388       const node_t *node = node_get_by_id(rs->identity_digest);
00389       tor_assert(node && node->rs == rs);
00390       tor_assert(fast_memeq(rs->identity_digest, node->identity, DIGEST_LEN));
00391       digestmap_set(dm, node->identity, (void*)node);
00392       if (ns->flavor == FLAV_MICRODESC) {
00393         /* If it's a microdesc consensus, every entry that has a
00394          * microdescriptor should be in the nodelist.
00395          */
00396         microdesc_t *md =
00397           microdesc_cache_lookup_by_digest256(NULL, rs->descriptor_digest);
00398         tor_assert(md == node->md);
00399         if (md)
00400           tor_assert(md->held_by_nodes >= 1);
00401       }
00402     } SMARTLIST_FOREACH_END(rs);
00403   }
00404 
00405   /* The nodelist should have no other entries, and its entries should be
00406    * well-formed. */
00407   SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
00408     tor_assert(digestmap_get(dm, node->identity) != NULL);
00409     tor_assert(node_sl_idx == node->nodelist_idx);
00410   } SMARTLIST_FOREACH_END(node);
00411 
00412   tor_assert((long)smartlist_len(the_nodelist->nodes) ==
00413              (long)HT_SIZE(&the_nodelist->nodes_by_id));
00414 
00415   digestmap_free(dm, NULL);
00416 }
00417 
00421 smartlist_t *
00422 nodelist_get_list(void)
00423 {
00424   init_nodelist();
00425   return the_nodelist->nodes;
00426 }
00427 
00432 const node_t *
00433 node_get_by_hex_id(const char *hex_id)
00434 {
00435   char digest_buf[DIGEST_LEN];
00436   char nn_buf[MAX_NICKNAME_LEN+1];
00437   char nn_char='\0';
00438 
00439   if (hex_digest_nickname_decode(hex_id, digest_buf, &nn_char, nn_buf)==0) {
00440     const node_t *node = node_get_by_id(digest_buf);
00441     if (!node)
00442       return NULL;
00443     if (nn_char) {
00444       const char *real_name = node_get_nickname(node);
00445       if (!real_name || strcasecmp(real_name, nn_buf))
00446         return NULL;
00447       if (nn_char == '=') {
00448         const char *named_id =
00449           networkstatus_get_router_digest_by_nickname(nn_buf);
00450         if (!named_id || tor_memneq(named_id, digest_buf, DIGEST_LEN))
00451           return NULL;
00452       }
00453     }
00454     return node;
00455   }
00456 
00457   return NULL;
00458 }
00459 
00464 const node_t *
00465 node_get_by_nickname(const char *nickname, int warn_if_unnamed)
00466 {
00467   const node_t *node;
00468   if (!the_nodelist)
00469     return NULL;
00470 
00471   /* Handle these cases: DIGEST, $DIGEST, $DIGEST=name, $DIGEST~name. */
00472   if ((node = node_get_by_hex_id(nickname)) != NULL)
00473       return node;
00474 
00475   if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME))
00476     return NULL;
00477 
00478   /* Okay, so if we get here, the nickname is just a nickname.  Is there
00479    * a binding for it in the consensus? */
00480   {
00481     const char *named_id =
00482       networkstatus_get_router_digest_by_nickname(nickname);
00483     if (named_id)
00484       return node_get_by_id(named_id);
00485   }
00486 
00487   /* Is it marked as owned-by-someone-else? */
00488   if (networkstatus_nickname_is_unnamed(nickname)) {
00489     log_info(LD_GENERAL, "The name %s is listed as Unnamed: there is some "
00490              "router that holds it, but not one listed in the current "
00491              "consensus.", escaped(nickname));
00492     return NULL;
00493   }
00494 
00495   /* Okay, so the name is not canonical for anybody. */
00496   {
00497     smartlist_t *matches = smartlist_new();
00498     const node_t *choice = NULL;
00499 
00500     SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
00501       if (!strcasecmp(node_get_nickname(node), nickname))
00502         smartlist_add(matches, node);
00503     } SMARTLIST_FOREACH_END(node);
00504 
00505     if (smartlist_len(matches)>1 && warn_if_unnamed) {
00506       int any_unwarned = 0;
00507       SMARTLIST_FOREACH_BEGIN(matches, node_t *, node) {
00508         if (!node->name_lookup_warned) {
00509           node->name_lookup_warned = 1;
00510           any_unwarned = 1;
00511         }
00512       } SMARTLIST_FOREACH_END(node);
00513 
00514       if (any_unwarned) {
00515         log_warn(LD_CONFIG, "There are multiple matches for the name %s, "
00516                  "but none is listed as Named in the directory consensus. "
00517                  "Choosing one arbitrarily.", nickname);
00518       }
00519     } else if (smartlist_len(matches)>1 && warn_if_unnamed) {
00520       char fp[HEX_DIGEST_LEN+1];
00521       node_t *node = smartlist_get(matches, 0);
00522       if (node->name_lookup_warned) {
00523         base16_encode(fp, sizeof(fp), node->identity, DIGEST_LEN);
00524         log_warn(LD_CONFIG,
00525                  "You specified a server \"%s\" by name, but the directory "
00526                  "authorities do not have any key registered for this "
00527                  "nickname -- so it could be used by any server, not just "
00528                  "the one you meant. "
00529                  "To make sure you get the same server in the future, refer "
00530                  "to it by key, as \"$%s\".", nickname, fp);
00531         node->name_lookup_warned = 1;
00532       }
00533     }
00534 
00535     if (smartlist_len(matches))
00536       choice = smartlist_get(matches, 0);
00537 
00538     smartlist_free(matches);
00539     return choice;
00540   }
00541 }
00542 
00544 const char *
00545 node_get_nickname(const node_t *node)
00546 {
00547   tor_assert(node);
00548   if (node->rs)
00549     return node->rs->nickname;
00550   else if (node->ri)
00551     return node->ri->nickname;
00552   else
00553     return NULL;
00554 }
00555 
00558 int
00559 node_is_named(const node_t *node)
00560 {
00561   const char *named_id;
00562   const char *nickname = node_get_nickname(node);
00563   if (!nickname)
00564     return 0;
00565   named_id = networkstatus_get_router_digest_by_nickname(nickname);
00566   if (!named_id)
00567     return 0;
00568   return tor_memeq(named_id, node->identity, DIGEST_LEN);
00569 }
00570 
00573 int
00574 node_is_dir(const node_t *node)
00575 {
00576   if (node->rs)
00577     return node->rs->dir_port != 0;
00578   else if (node->ri)
00579     return node->ri->dir_port != 0;
00580   else
00581     return 0;
00582 }
00583 
00586 int
00587 node_has_descriptor(const node_t *node)
00588 {
00589   return (node->ri ||
00590           (node->rs && node->md));
00591 }
00592 
00594 int
00595 node_get_purpose(const node_t *node)
00596 {
00597   if (node->ri)
00598     return node->ri->purpose;
00599   else
00600     return ROUTER_PURPOSE_GENERAL;
00601 }
00602 
00606 void
00607 node_get_verbose_nickname(const node_t *node,
00608                           char *verbose_name_out)
00609 {
00610   const char *nickname = node_get_nickname(node);
00611   int is_named = node_is_named(node);
00612   verbose_name_out[0] = '$';
00613   base16_encode(verbose_name_out+1, HEX_DIGEST_LEN+1, node->identity,
00614                 DIGEST_LEN);
00615   if (!nickname)
00616     return;
00617   verbose_name_out[1+HEX_DIGEST_LEN] = is_named ? '=' : '~';
00618   strlcpy(verbose_name_out+1+HEX_DIGEST_LEN+1, nickname, MAX_NICKNAME_LEN+1);
00619 }
00620 
00623 int
00624 node_allows_single_hop_exits(const node_t *node)
00625 {
00626   if (node && node->ri)
00627     return node->ri->allow_single_hop_exits;
00628   else
00629     return 0;
00630 }
00631 
00634 int
00635 node_exit_policy_rejects_all(const node_t *node)
00636 {
00637   if (node->rejects_all)
00638     return 1;
00639 
00640   if (node->ri)
00641     return node->ri->policy_is_reject_star;
00642   else if (node->md)
00643     return node->md->exit_policy == NULL ||
00644       short_policy_is_reject_star(node->md->exit_policy);
00645   else
00646     return 1;
00647 }
00648 
00657 smartlist_t *
00658 node_get_all_orports(const node_t *node)
00659 {
00660   smartlist_t *sl = smartlist_new();
00661 
00662   if (node->ri != NULL) {
00663     if (node->ri->addr != 0) {
00664       tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
00665       tor_addr_from_ipv4h(&ap->addr, node->ri->addr);
00666       ap->port = node->ri->or_port;
00667       smartlist_add(sl, ap);
00668     }
00669     if (!tor_addr_is_null(&node->ri->ipv6_addr)) {
00670       tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
00671       tor_addr_copy(&ap->addr, &node->ri->ipv6_addr);
00672       ap->port = node->ri->or_port;
00673       smartlist_add(sl, ap);
00674     }
00675   } else if (node->rs != NULL) {
00676       tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
00677       tor_addr_from_ipv4h(&ap->addr, node->rs->addr);
00678       ap->port = node->rs->or_port;
00679       smartlist_add(sl, ap);
00680   }
00681 
00682   return sl;
00683 }
00684 
00687 void
00688 node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
00689 {
00690   if (node->ri) {
00691     router_get_prim_orport(node->ri, ap_out);
00692   } else if (node->rs) {
00693     tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
00694     ap_out->port = node->rs->or_port;
00695   }
00696 }
00697 
00700 void
00701 node_get_addr(const node_t *node, tor_addr_t *addr_out)
00702 {
00703   tor_addr_port_t ap;
00704   node_get_prim_orport(node, &ap);
00705   tor_addr_copy(addr_out, &ap.addr);
00706 }
00707 
00710 uint32_t
00711 node_get_prim_addr_ipv4h(const node_t *node)
00712 {
00713   if (node->ri) {
00714     return node->ri->addr;
00715   } else if (node->rs) {
00716     return node->rs->addr;
00717   }
00718   return 0;
00719 }
00720 
00723 void
00724 node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out)
00725 {
00726   if (node->ri) {
00727     router_get_pref_orport(node->ri, ap_out);
00728   } else if (node->rs) {
00729     /* No IPv6 in routerstatus_t yet.  XXXprop186 ok for private
00730        bridges but needs fixing */
00731     tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr);
00732     ap_out->port = node->rs->or_port;
00733   }
00734 }
00735 
00738 void
00739 node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
00740 {
00741   if (node->ri) {
00742     router_get_pref_ipv6_orport(node->ri, ap_out);
00743   } else if (node->rs) {
00744     /* No IPv6 in routerstatus_t yet.  XXXprop186 ok for private
00745        bridges but needs fixing */
00746     tor_addr_make_unspec(&ap_out->addr);
00747     ap_out->port = 0;
00748   }
00749 }
00750 
00753 void
00754 node_get_address_string(const node_t *node, char *buf, size_t len)
00755 {
00756   if (node->ri) {
00757     strlcpy(buf, node->ri->address, len);
00758   } else if (node->rs) {
00759     tor_addr_t addr;
00760     tor_addr_from_ipv4h(&addr, node->rs->addr);
00761     tor_addr_to_str(buf, &addr, len, 0);
00762   } else {
00763     buf[0] = '\0';
00764   }
00765 }
00766 
00769 long
00770 node_get_declared_uptime(const node_t *node)
00771 {
00772   if (node->ri)
00773     return node->ri->uptime;
00774   else
00775     return -1;
00776 }
00777 
00779 const char *
00780 node_get_platform(const node_t *node)
00781 {
00782   /* If we wanted, we could record the version in the routerstatus_t, since
00783    * the consensus lists it.  We don't, though, so this function just won't
00784    * work with microdescriptors. */
00785   if (node->ri)
00786     return node->ri->platform;
00787   else
00788     return NULL;
00789 }
00790 
00792 time_t
00793 node_get_published_on(const node_t *node)
00794 {
00795   if (node->ri)
00796     return node->ri->cache_info.published_on;
00797   else
00798     return 0;
00799 }
00800 
00802 int
00803 node_is_me(const node_t *node)
00804 {
00805   return router_digest_is_me(node->identity);
00806 }
00807 
00810 const smartlist_t *
00811 node_get_declared_family(const node_t *node)
00812 {
00813   if (node->ri && node->ri->declared_family)
00814     return node->ri->declared_family;
00815   else if (node->md && node->md->family)
00816     return node->md->family;
00817   else
00818     return NULL;
00819 }
00820