aboutsummaryrefslogtreecommitdiff
path: root/src/feature/nodelist/nodelist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/nodelist/nodelist.c')
-rw-r--r--src/feature/nodelist/nodelist.c255
1 files changed, 141 insertions, 114 deletions
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index 7ebc4f5fda..03b158e68d 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -127,7 +127,7 @@ typedef struct nodelist_t {
*
* Whenever a node's routerinfo or microdescriptor is about to change,
* you should remove it from this map with node_remove_from_ed25519_map().
- * Whenever a node's routerinfo or microdescriptor has just chaned,
+ * Whenever a node's routerinfo or microdescriptor has just changed,
* you should add it to this map with node_add_to_ed25519_map().
*/
HT_HEAD(nodelist_ed_map, node_t) nodes_by_ed_id;
@@ -451,8 +451,6 @@ node_addrs_changed(node_t *node)
static void
node_add_to_address_set(const node_t *node)
{
- tor_addr_t tmp_addr;
-
if (!the_nodelist ||
!the_nodelist->node_addrs || !the_nodelist->reentry_set)
return;
@@ -465,19 +463,17 @@ node_add_to_address_set(const node_t *node)
* test succeeds and thus the 0 value for the DirPort. */
if (node->rs) {
- if (node->rs->addr) {
- tor_addr_from_ipv4h(&tmp_addr, node->rs->addr);
- nodelist_add_addr_to_address_set(&tmp_addr, node->rs->or_port, 0);
- }
+ if (!tor_addr_is_null(&node->rs->ipv4_addr))
+ nodelist_add_addr_to_address_set(&node->rs->ipv4_addr,
+ node->rs->ipv4_orport, 0);
if (!tor_addr_is_null(&node->rs->ipv6_addr))
nodelist_add_addr_to_address_set(&node->rs->ipv6_addr,
node->rs->ipv6_orport, 0);
}
if (node->ri) {
- if (node->ri->addr) {
- tor_addr_from_ipv4h(&tmp_addr, node->ri->addr);
- nodelist_add_addr_to_address_set(&tmp_addr, node->ri->or_port, 0);
- }
+ if (!tor_addr_is_null(&node->ri->ipv4_addr))
+ nodelist_add_addr_to_address_set(&node->ri->ipv4_addr,
+ node->ri->ipv4_orport, 0);
if (!tor_addr_is_null(&node->ri->ipv6_addr))
nodelist_add_addr_to_address_set(&node->ri->ipv6_addr,
node->ri->ipv6_orport, 0);
@@ -531,7 +527,7 @@ nodelist_add_addr_to_address_set(const tor_addr_t *addr,
uint16_t or_port, uint16_t dir_port)
{
if (BUG(!addr) || tor_addr_is_null(addr) ||
- (!tor_addr_is_v4(addr) && tor_addr_family(addr) != AF_INET6) ||
+ (!tor_addr_is_v4(addr) && !tor_addr_is_v6(addr)) ||
!the_nodelist || !the_nodelist->node_addrs ||
!the_nodelist->reentry_set) {
return;
@@ -691,7 +687,7 @@ get_estimated_address_per_node, (void))
* and grab microdescriptors into nodes as appropriate.
*/
void
-nodelist_set_consensus(networkstatus_t *ns)
+nodelist_set_consensus(const networkstatus_t *ns)
{
const or_options_t *options = get_options();
int authdir = authdir_mode_v3(options);
@@ -749,7 +745,7 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_bad_exit = rs->is_bad_exit;
node->is_hs_dir = rs->is_hs_dir;
node->ipv6_preferred = 0;
- if (fascist_firewall_prefer_ipv6_orport(options) &&
+ if (reachable_addr_prefer_ipv6_orport(options) &&
(tor_addr_is_null(&rs->ipv6_addr) == 0 ||
(node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0)))
node->ipv6_preferred = 1;
@@ -1028,7 +1024,7 @@ nodelist_assert_ok(void)
/** Ensure that the nodelist has been created with the most recent consensus.
* If that's not the case, make it so. */
void
-nodelist_ensure_freshness(networkstatus_t *ns)
+nodelist_ensure_freshness(const networkstatus_t *ns)
{
tor_assert(ns);
@@ -1209,7 +1205,7 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
/** Dummy object that should be unreturnable. Used to ensure that
* node_get_protover_summary_flags() always returns non-NULL. */
static const protover_summary_flags_t zero_protover_flags = {
- 0,0,0,0,0,0,0,0,0
+ 0,0,0,0,0,0,0,0,0,0,0,0
};
/** Return the protover_summary_flags for a given node. */
@@ -1234,9 +1230,9 @@ node_get_protover_summary_flags(const node_t *node)
* by ed25519 ID during the link handshake. If <b>compatible_with_us</b>,
* it needs to be using a link authentication method that we understand.
* If not, any plausible link authentication method will do. */
-MOCK_IMPL(int,
+MOCK_IMPL(bool,
node_supports_ed25519_link_authentication,(const node_t *node,
- int compatible_with_us))
+ bool compatible_with_us))
{
if (! node_get_ed25519_id(node))
return 0;
@@ -1251,7 +1247,7 @@ node_supports_ed25519_link_authentication,(const node_t *node,
/** Return true iff <b>node</b> supports the hidden service directory version
* 3 protocol (proposal 224). */
-int
+bool
node_supports_v3_hsdir(const node_t *node)
{
tor_assert(node);
@@ -1261,7 +1257,7 @@ node_supports_v3_hsdir(const node_t *node)
/** Return true iff <b>node</b> supports ed25519 authentication as an hidden
* service introduction point.*/
-int
+bool
node_supports_ed25519_hs_intro(const node_t *node)
{
tor_assert(node);
@@ -1269,9 +1265,24 @@ node_supports_ed25519_hs_intro(const node_t *node)
return node_get_protover_summary_flags(node)->supports_ed25519_hs_intro;
}
+/** Return true iff <b>node</b> can be a rendezvous point for hidden
+ * service version 3 (HSRend=2). */
+bool
+node_supports_v3_rendezvous_point(const node_t *node)
+{
+ tor_assert(node);
+
+ /* We can't use a v3 rendezvous point without the curve25519 onion pk. */
+ if (!node_get_curve25519_onion_key(node)) {
+ return 0;
+ }
+
+ return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
+}
+
/** Return true iff <b>node</b> supports the DoS ESTABLISH_INTRO cell
- * extenstion. */
-int
+ * extension. */
+bool
node_supports_establish_intro_dos_extension(const node_t *node)
{
tor_assert(node);
@@ -1280,19 +1291,54 @@ node_supports_establish_intro_dos_extension(const node_t *node)
supports_establish_intro_dos_extension;
}
-/** Return true iff <b>node</b> supports to be a rendezvous point for hidden
- * service version 3 (HSRend=2). */
-int
-node_supports_v3_rendezvous_point(const node_t *node)
+/** Return true iff <b>node</b> can initiate IPv6 extends (Relay=3).
+ *
+ * This check should only be performed by client path selection code.
+ *
+ * Extending relays should check their own IPv6 support using
+ * router_can_extend_over_ipv6(). Like other extends, they should not verify
+ * the link specifiers in the extend cell against the consensus, because it
+ * may be out of date. */
+bool
+node_supports_initiating_ipv6_extends(const node_t *node)
{
tor_assert(node);
- /* We can't use a v3 rendezvous point without the curve25519 onion pk. */
- if (!node_get_curve25519_onion_key(node)) {
+ /* Relays can't initiate an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
return 0;
}
- return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
+ /* Initiating relays also need to support the relevant protocol version. */
+ return
+ node_get_protover_summary_flags(node)->supports_initiating_ipv6_extends;
+}
+
+/** Return true iff <b>node</b> can accept IPv6 extends (Relay=2 or Relay=3)
+ * from other relays. If <b>need_canonical_ipv6_conn</b> is true, also check
+ * if the relay supports canonical IPv6 connections (Relay=3 only).
+ *
+ * This check should only be performed by client path selection code.
+ */
+bool
+node_supports_accepting_ipv6_extends(const node_t *node,
+ bool need_canonical_ipv6_conn)
+{
+ tor_assert(node);
+
+ /* Relays can't accept an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
+ return 0;
+ }
+
+ /* Accepting relays also need to support the relevant protocol version. */
+ if (need_canonical_ipv6_conn) {
+ return
+ node_get_protover_summary_flags(node)->supports_canonical_ipv6_conns;
+ } else {
+ return
+ node_get_protover_summary_flags(node)->supports_accepting_ipv6_extends;
+ }
}
/** Return the RSA ID key's SHA1 digest for the provided node. */
@@ -1567,32 +1613,14 @@ node_exit_policy_is_exact(const node_t *node, sa_family_t family)
* "addr" is an IPv4 host-order address and port_field is a uint16_t.
* r is typically a routerinfo_t or routerstatus_t.
*/
-#define SL_ADD_NEW_IPV4_AP(r, port_field, sl, valid) \
- STMT_BEGIN \
- if (tor_addr_port_is_valid_ipv4h((r)->addr, (r)->port_field, 0)) { \
- valid = 1; \
- tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); \
- tor_addr_from_ipv4h(&ap->addr, (r)->addr); \
- ap->port = (r)->port_field; \
- smartlist_add((sl), ap); \
- } \
- STMT_END
-
-/* Check if the "addr" and port_field fields from r are a valid non-listening
- * address/port. If so, set valid to true and add a newly allocated
- * tor_addr_port_t containing "addr" and port_field to sl.
- * "addr" is a tor_addr_t and port_field is a uint16_t.
- * r is typically a routerinfo_t or routerstatus_t.
- */
-#define SL_ADD_NEW_IPV6_AP(r, port_field, sl, valid) \
- STMT_BEGIN \
- if (tor_addr_port_is_valid(&(r)->ipv6_addr, (r)->port_field, 0)) { \
- valid = 1; \
- tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); \
- tor_addr_copy(&ap->addr, &(r)->ipv6_addr); \
- ap->port = (r)->port_field; \
- smartlist_add((sl), ap); \
- } \
+#define SL_ADD_NEW_AP(r, addr_field, port_field, sl, valid) \
+ STMT_BEGIN \
+ if (tor_addr_port_is_valid(&(r)->addr_field, (r)->port_field, 0)) { \
+ valid = 1; \
+ tor_addr_port_t *ap = tor_addr_port_new(&(r)->addr_field, \
+ (r)->port_field); \
+ smartlist_add((sl), ap); \
+ } \
STMT_END
/** Return list of tor_addr_port_t with all OR ports (in the sense IP
@@ -1611,33 +1639,32 @@ node_get_all_orports(const node_t *node)
/* Find a valid IPv4 address and port */
if (node->ri != NULL) {
- SL_ADD_NEW_IPV4_AP(node->ri, or_port, sl, valid);
+ SL_ADD_NEW_AP(node->ri, ipv4_addr, ipv4_orport, sl, valid);
}
/* If we didn't find a valid address/port in the ri, try the rs */
if (!valid && node->rs != NULL) {
- SL_ADD_NEW_IPV4_AP(node->rs, or_port, sl, valid);
+ SL_ADD_NEW_AP(node->rs, ipv4_addr, ipv4_orport, sl, valid);
}
/* Find a valid IPv6 address and port */
valid = 0;
if (node->ri != NULL) {
- SL_ADD_NEW_IPV6_AP(node->ri, ipv6_orport, sl, valid);
+ SL_ADD_NEW_AP(node->ri, ipv6_addr, ipv6_orport, sl, valid);
}
if (!valid && node->rs != NULL) {
- SL_ADD_NEW_IPV6_AP(node->rs, ipv6_orport, sl, valid);
+ SL_ADD_NEW_AP(node->rs, ipv6_addr, ipv6_orport, sl, valid);
}
if (!valid && node->md != NULL) {
- SL_ADD_NEW_IPV6_AP(node->md, ipv6_orport, sl, valid);
+ SL_ADD_NEW_AP(node->md, ipv6_addr, ipv6_orport, sl, valid);
}
return sl;
}
-#undef SL_ADD_NEW_IPV4_AP
-#undef SL_ADD_NEW_IPV6_AP
+#undef SL_ADD_NEW_AP
/** Wrapper around node_get_prim_orport for backward
compatibility. */
@@ -1649,21 +1676,20 @@ node_get_addr(const node_t *node, tor_addr_t *addr_out)
tor_addr_copy(addr_out, &ap.addr);
}
-/** Return the host-order IPv4 address for <b>node</b>, or 0 if it doesn't
- * seem to have one. */
-uint32_t
-node_get_prim_addr_ipv4h(const node_t *node)
+/** Return the IPv4 address for <b>node</b>, or NULL if none found. */
+static const tor_addr_t *
+node_get_prim_addr_ipv4(const node_t *node)
{
/* Don't check the ORPort or DirPort, as this function isn't port-specific,
* and the node might have a valid IPv4 address, yet have a zero
* ORPort or DirPort.
*/
- if (node->ri && tor_addr_is_valid_ipv4h(node->ri->addr, 0)) {
- return node->ri->addr;
- } else if (node->rs && tor_addr_is_valid_ipv4h(node->rs->addr, 0)) {
- return node->rs->addr;
+ if (node->ri && tor_addr_is_valid(&node->ri->ipv4_addr, 0)) {
+ return &node->ri->ipv4_addr;
+ } else if (node->rs && tor_addr_is_valid(&node->rs->ipv4_addr, 0)) {
+ return &node->rs->ipv4_addr;
}
- return 0;
+ return NULL;
}
/** Copy a string representation of an IP address for <b>node</b> into
@@ -1671,12 +1697,10 @@ node_get_prim_addr_ipv4h(const node_t *node)
void
node_get_address_string(const node_t *node, char *buf, size_t len)
{
- uint32_t ipv4_addr = node_get_prim_addr_ipv4h(node);
+ const tor_addr_t *ipv4_addr = node_get_prim_addr_ipv4(node);
- if (tor_addr_is_valid_ipv4h(ipv4_addr, 0)) {
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ipv4_addr);
- tor_addr_to_str(buf, &addr, len, 0);
+ if (ipv4_addr) {
+ tor_addr_to_str(buf, ipv4_addr, len, 0);
} else if (len > 0) {
buf[0] = '\0';
}
@@ -1761,7 +1785,7 @@ node_has_ipv6_dirport(const node_t *node)
* ii) the router has no IPv4 OR address.
*
* If you don't have a node, consider looking it up.
- * If there is no node, use fascist_firewall_prefer_ipv6_orport().
+ * If there is no node, use reachable_addr_prefer_ipv6_orport().
*/
int
node_ipv6_or_preferred(const node_t *node)
@@ -1771,10 +1795,10 @@ node_ipv6_or_preferred(const node_t *node)
node_assert_ok(node);
/* XX/teor - node->ipv6_preferred is set from
- * fascist_firewall_prefer_ipv6_orport() each time the consensus is loaded.
+ * reachable_addr_prefer_ipv6_orport() each time the consensus is loaded.
*/
node_get_prim_orport(node, &ipv4_addr);
- if (!fascist_firewall_use_ipv6(options)) {
+ if (!reachable_addr_use_ipv6(options)) {
return 0;
} else if (node->ipv6_preferred ||
!tor_addr_port_is_valid_ap(&ipv4_addr, 0)) {
@@ -1783,12 +1807,12 @@ node_ipv6_or_preferred(const node_t *node)
return 0;
}
-#define RETURN_IPV4_AP(r, port_field, ap_out) \
- STMT_BEGIN \
- if (r && tor_addr_port_is_valid_ipv4h((r)->addr, (r)->port_field, 0)) { \
- tor_addr_from_ipv4h(&(ap_out)->addr, (r)->addr); \
- (ap_out)->port = (r)->port_field; \
- } \
+#define RETURN_IPV4_AP(r, port_field, ap_out) \
+ STMT_BEGIN \
+ if (r && tor_addr_port_is_valid(&(r)->ipv4_addr, (r)->port_field, 0)) { \
+ tor_addr_copy(&(ap_out)->addr, &(r)->ipv4_addr); \
+ (ap_out)->port = (r)->port_field; \
+ } \
STMT_END
/** Copy the primary (IPv4) OR port (IP address and TCP port) for <b>node</b>
@@ -1807,8 +1831,8 @@ node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
/* Check ri first, because rewrite_node_address_for_bridge() updates
* node->ri with the configured bridge address. */
- RETURN_IPV4_AP(node->ri, or_port, ap_out);
- RETURN_IPV4_AP(node->rs, or_port, ap_out);
+ RETURN_IPV4_AP(node->ri, ipv4_orport, ap_out);
+ RETURN_IPV4_AP(node->rs, ipv4_orport, ap_out);
/* Microdescriptors only have an IPv6 address */
}
@@ -1869,7 +1893,7 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
* or
* ii) our preference is for IPv6 Dir addresses.
*
- * If there is no node, use fascist_firewall_prefer_ipv6_dirport().
+ * If there is no node, use reachable_addr_prefer_ipv6_dirport().
*/
int
node_ipv6_dir_preferred(const node_t *node)
@@ -1878,15 +1902,15 @@ node_ipv6_dir_preferred(const node_t *node)
tor_addr_port_t ipv4_addr;
node_assert_ok(node);
- /* node->ipv6_preferred is set from fascist_firewall_prefer_ipv6_orport(),
+ /* node->ipv6_preferred is set from reachable_addr_prefer_ipv6_orport(),
* so we can't use it to determine DirPort IPv6 preference.
* This means that bridge clients will use IPv4 DirPorts by default.
*/
node_get_prim_dirport(node, &ipv4_addr);
- if (!fascist_firewall_use_ipv6(options)) {
+ if (!reachable_addr_use_ipv6(options)) {
return 0;
} else if (!tor_addr_port_is_valid_ap(&ipv4_addr, 0)
- || fascist_firewall_prefer_ipv6_dirport(get_options())) {
+ || reachable_addr_prefer_ipv6_dirport(get_options())) {
return node_has_ipv6_dirport(node);
}
return 0;
@@ -1908,8 +1932,8 @@ node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out)
/* Check ri first, because rewrite_node_address_for_bridge() updates
* node->ri with the configured bridge address. */
- RETURN_IPV4_AP(node->ri, dir_port, ap_out);
- RETURN_IPV4_AP(node->rs, dir_port, ap_out);
+ RETURN_IPV4_AP(node->ri, ipv4_dirport, ap_out);
+ RETURN_IPV4_AP(node->rs, ipv4_dirport, ap_out);
/* Microdescriptors only have an IPv6 address */
}
@@ -1946,13 +1970,13 @@ node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out)
/* Assume IPv4 and IPv6 dirports are the same */
if (node->ri && tor_addr_port_is_valid(&node->ri->ipv6_addr,
- node->ri->dir_port, 0)) {
+ node->ri->ipv4_dirport, 0)) {
tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
- ap_out->port = node->ri->dir_port;
+ ap_out->port = node->ri->ipv4_dirport;
} else if (node->rs && tor_addr_port_is_valid(&node->rs->ipv6_addr,
- node->rs->dir_port, 0)) {
+ node->rs->ipv4_dirport, 0)) {
tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
- ap_out->port = node->rs->dir_port;
+ ap_out->port = node->rs->ipv4_dirport;
} else {
tor_addr_make_null(&ap_out->addr, AF_INET6);
ap_out->port = 0;
@@ -2004,7 +2028,7 @@ node_get_curve25519_onion_key(const node_t *node)
/* Return a newly allocacted RSA onion public key taken from the given node.
*
* Return NULL if node is NULL or no RSA onion public key can be found. It is
- * the caller responsability to free the returned object. */
+ * the caller responsibility to free the returned object. */
crypto_pk_t *
node_get_rsa_onion_key(const node_t *node)
{
@@ -2037,15 +2061,21 @@ node_get_rsa_onion_key(const node_t *node)
void
node_set_country(node_t *node)
{
- tor_addr_t addr = TOR_ADDR_NULL;
+ const tor_addr_t *ipv4_addr = NULL;
/* XXXXipv6 */
if (node->rs)
- tor_addr_from_ipv4h(&addr, node->rs->addr);
+ ipv4_addr = &node->rs->ipv4_addr;
else if (node->ri)
- tor_addr_from_ipv4h(&addr, node->ri->addr);
+ ipv4_addr = &node->ri->ipv4_addr;
- node->country = geoip_get_country_by_addr(&addr);
+ /* IPv4 is mandatory for a relay so this should not happen unless we are
+ * attempting to set the country code on a node without a descriptor. */
+ if (BUG(!ipv4_addr)) {
+ node->country = -1;
+ return;
+ }
+ node->country = geoip_get_country_by_addr(ipv4_addr);
}
/** Set the country code of all routers in the routerlist. */
@@ -2060,7 +2090,7 @@ nodelist_refresh_countries(void)
/** Return true iff router1 and router2 have similar enough network addresses
* that we should treat them as being in the same family */
int
-addrs_in_same_network_family(const tor_addr_t *a1,
+router_addrs_in_same_network(const tor_addr_t *a1,
const tor_addr_t *a2)
{
if (tor_addr_is_null(a1) || tor_addr_is_null(a2))
@@ -2176,8 +2206,8 @@ nodes_in_same_family(const node_t *node1, const node_t *node2)
node_get_pref_ipv6_orport(node1, &ap6_1);
node_get_pref_ipv6_orport(node2, &ap6_2);
- if (addrs_in_same_network_family(&a1, &a2) ||
- addrs_in_same_network_family(&ap6_1.addr, &ap6_2.addr))
+ if (router_addrs_in_same_network(&a1, &a2) ||
+ router_addrs_in_same_network(&ap6_1.addr, &ap6_2.addr))
return 1;
}
@@ -2235,8 +2265,8 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
tor_addr_port_t ap6;
node_get_addr(node2, &a);
node_get_pref_ipv6_orport(node2, &ap6);
- if (addrs_in_same_network_family(&a, &node_addr) ||
- addrs_in_same_network_family(&ap6.addr, &node_ap6.addr))
+ if (router_addrs_in_same_network(&a, &node_addr) ||
+ router_addrs_in_same_network(&ap6.addr, &node_ap6.addr))
smartlist_add(sl, (void*)node2);
} SMARTLIST_FOREACH_END(node2);
}
@@ -2276,21 +2306,18 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
const node_t *
router_find_exact_exit_enclave(const char *address, uint16_t port)
{/*XXXX MOVE*/
- uint32_t addr;
struct in_addr in;
- tor_addr_t a;
+ tor_addr_t ipv4_addr;
const or_options_t *options = get_options();
if (!tor_inet_aton(address, &in))
return NULL; /* it's not an IP already */
- addr = ntohl(in.s_addr);
-
- tor_addr_from_ipv4h(&a, addr);
+ tor_addr_from_in(&ipv4_addr, &in);
SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
- if (node_get_addr_ipv4h(node) == addr &&
+ if (tor_addr_eq(node_get_prim_addr_ipv4(node), &ipv4_addr) &&
node->is_running &&
- compare_tor_addr_to_node_policy(&a, port, node) ==
+ compare_tor_addr_to_node_policy(&ipv4_addr, port, node) ==
ADDR_POLICY_ACCEPTED &&
!routerset_contains_node(options->ExcludeExitNodesUnion_, node))
return node;