From 1ffa0e102dc0d036241ee1ea2a13df42526c0872 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 12 Apr 2014 13:24:43 +0200 Subject: [PATCH] Remove support for Subnets. --- src/Makefile.am | 3 - src/conf.c | 28 -- src/conf.h | 3 - src/connection.c | 1 - src/control.c | 3 - src/graph.c | 4 - src/libmeshlink.c | 5 - src/net.c | 74 +--- src/net_setup.c | 81 +--- src/node.c | 7 - src/node.h | 3 - src/process.c | 1 - src/protocol.c | 3 +- src/protocol.h | 6 - src/protocol_auth.c | 11 +- src/protocol_subnet.c | 243 ----------- src/route.c | 932 +----------------------------------------- src/script.c | 1 + src/subnet.c | 279 ------------- src/subnet.h | 92 ----- src/subnet_parse.c | 382 ----------------- 21 files changed, 8 insertions(+), 2154 deletions(-) delete mode 100644 src/protocol_subnet.c delete mode 100644 src/subnet.c delete mode 100644 src/subnet.h delete mode 100644 src/subnet_parse.c diff --git a/src/Makefile.am b/src/Makefile.am index fab95089..1cb2b6ac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,15 +66,12 @@ libmeshlink_la_SOURCES = \ protocol_edge.c \ protocol_key.c \ protocol_misc.c \ - protocol_subnet.c \ route.c route.h \ rsa.h \ rsagen.h \ script.c script.h \ splay_tree.c splay_tree.h \ sptps.c sptps.h \ - subnet.c subnet.h \ - subnet_parse.c \ system.h \ tincd.c \ utils.c utils.h \ diff --git a/src/conf.c b/src/conf.c index 95c07477..836c00e4 100644 --- a/src/conf.c +++ b/src/conf.c @@ -187,34 +187,6 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) { return false; } -bool get_config_subnet(const config_t *cfg, subnet_t ** result) { - subnet_t subnet = {NULL}; - - if(!cfg) - return false; - - if(!str2net(&subnet, cfg->value)) { - logger(DEBUG_ALWAYS, LOG_ERR, "Subnet expected for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); - return false; - } - - /* Teach newbies what subnets are... */ - - if(((subnet.type == SUBNET_IPV4) - && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof subnet.net.ipv4.address)) - || ((subnet.type == SUBNET_IPV6) - && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof subnet.net.ipv6.address))) { - logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); - return false; - } - - *(*result = new_subnet()) = subnet; - - return true; -} - /* Read exactly one line and strip the trailing newline if any. */ diff --git a/src/conf.h b/src/conf.h index 4f39b20a..17dcc595 100644 --- a/src/conf.h +++ b/src/conf.h @@ -31,8 +31,6 @@ typedef struct config_t { int line; } config_t; -#include "subnet.h" - extern splay_tree_t *config_tree; extern int pinginterval; @@ -52,7 +50,6 @@ extern bool get_config_bool(const config_t *, bool *); extern bool get_config_int(const config_t *, int *); extern bool get_config_string(const config_t *, char **); extern bool get_config_address(const config_t *, struct addrinfo **); -extern bool get_config_subnet(const config_t *, struct subnet_t **); extern config_t *parse_config_line(char *, const char *, int); extern bool read_config_file(splay_tree_t *, const char *); diff --git a/src/connection.c b/src/connection.c index 496f6747..6f9d9809 100644 --- a/src/connection.c +++ b/src/connection.c @@ -28,7 +28,6 @@ #include "list.h" #include "logger.h" #include "rsa.h" -#include "subnet.h" #include "utils.h" #include "xalloc.h" diff --git a/src/control.c b/src/control.c index 45627495..0a8ca9b9 100644 --- a/src/control.c +++ b/src/control.c @@ -67,9 +67,6 @@ bool control_h(connection_t *c, const char *request) { case REQ_DUMP_EDGES: return dump_edges(c); - case REQ_DUMP_SUBNETS: - return dump_subnets(c); - case REQ_DUMP_CONNECTIONS: return dump_connections(c); diff --git a/src/graph.c b/src/graph.c index 75996eac..b7ace497 100644 --- a/src/graph.c +++ b/src/graph.c @@ -54,7 +54,6 @@ #include "node.h" #include "protocol.h" #include "script.h" -#include "subnet.h" #include "utils.h" #include "xalloc.h" #include "graph.h" @@ -255,8 +254,6 @@ static void check_reachability(void) { for(int i = 0; i < 7; i++) free(envp[i]); - subnet_update(n, NULL, n->status.reachable); - if(!n->status.reachable) { update_node_udp(n, NULL); memset(&n->status, 0, sizeof n->status); @@ -274,7 +271,6 @@ static void check_reachability(void) { } void graph(void) { - subnet_cache_flush(); sssp_bfs(); check_reachability(); mst_kruskal(); diff --git a/src/libmeshlink.c b/src/libmeshlink.c index bd6a3d28..f45faa38 100644 --- a/src/libmeshlink.c +++ b/src/libmeshlink.c @@ -39,7 +39,6 @@ static bool do_mlock = false; */ bool setup_meshlink_network(void) { init_connections(); - init_subnets(); init_nodes(); init_edges(); init_requests(); @@ -66,10 +65,6 @@ bool setup_meshlink_network(void) { if(!init_control()) return false; - /* Run subnet-up scripts for our own subnets */ - - subnet_update(myself, NULL, true); - return true; } diff --git a/src/net.c b/src/net.c index 6d7682d3..ae821015 100644 --- a/src/net.c +++ b/src/net.c @@ -32,7 +32,6 @@ #include "net.h" #include "netutl.h" #include "protocol.h" -#include "subnet.h" #include "xalloc.h" int contradicting_add_edge = 0; @@ -42,23 +41,18 @@ time_t last_config_check = 0; static timeout_t pingtimer; static timeout_t periodictimer; -/* Purge edges and subnets of unreachable nodes. Use carefully. */ +/* Purge edges of unreachable nodes. Use carefully. */ +// TODO: remove void purge(void) { logger(DEBUG_PROTOCOL, LOG_DEBUG, "Purging unreachable nodes"); - /* Remove all edges and subnets owned by unreachable nodes. */ + /* Remove all edges owned by unreachable nodes. */ for splay_each(node_t, n, node_tree) { if(!n->status.reachable) { logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Purging node %s (%s)", n->name, n->hostname); - for splay_each(subnet_t, s, n->subnet_tree) { - send_del_subnet(everyone, s); - if(!strictsubnets) - subnet_del(n, s); - } - for splay_each(edge_t, e, n->edge_tree) { if(!tunnelserver) send_del_edge(everyone, e); @@ -74,10 +68,6 @@ void purge(void) { for splay_each(edge_t, e, edge_weight_tree) if(e->to == n) return; - - if(!autoconnect && (!strictsubnets || !n->subnet_tree->head)) - /* in strictsubnets mode do not delete nodes with subnets */ - node_del(n); } } } @@ -335,64 +325,6 @@ int reload_configuration(void) { setup_myself_reloadable(); - /* If StrictSubnet is set, expire deleted Subnets and read new ones in */ - - if(strictsubnets) { - for splay_each(subnet_t, subnet, subnet_tree) - subnet->expires = 1; - - load_all_subnets(); - - for splay_each(subnet_t, subnet, subnet_tree) { - if(subnet->expires == 1) { - send_del_subnet(everyone, subnet); - if(subnet->owner->status.reachable) - subnet_update(subnet->owner, subnet, false); - subnet_del(subnet->owner, subnet); - } else if(subnet->expires == -1) { - subnet->expires = 0; - } else { - send_add_subnet(everyone, subnet); - if(subnet->owner->status.reachable) - subnet_update(subnet->owner, subnet, true); - } - } - } else { /* Only read our own subnets back in */ - for splay_each(subnet_t, subnet, myself->subnet_tree) - if(!subnet->expires) - subnet->expires = 1; - - config_t *cfg = lookup_config(config_tree, "Subnet"); - - while(cfg) { - subnet_t *subnet, *s2; - - if(!get_config_subnet(cfg, &subnet)) - continue; - - if((s2 = lookup_subnet(myself, subnet))) { - if(s2->expires == 1) - s2->expires = 0; - - free_subnet(subnet); - } else { - subnet_add(myself, subnet); - send_add_subnet(everyone, subnet); - subnet_update(myself, subnet, true); - } - - cfg = lookup_config_next(config_tree, cfg); - } - - for splay_each(subnet_t, subnet, myself->subnet_tree) { - if(subnet->expires == 1) { - send_del_subnet(everyone, subnet); - subnet_update(myself, subnet, false); - subnet_del(myself, subnet); - } - } - } - /* Try to make outgoing connections */ try_outgoing_connections(); diff --git a/src/net_setup.c b/src/net_setup.c index b344eebc..b311ecad 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -38,7 +38,6 @@ #include "route.h" #include "rsa.h" #include "script.h" -#include "subnet.h" #include "utils.h" #include "xalloc.h" @@ -310,62 +309,6 @@ void regenerate_key(void) { send_key_changed(); } -/* - Read Subnets from all host config files -*/ -void load_all_subnets(void) { - DIR *dir; - struct dirent *ent; - char *dname; - - xasprintf(&dname, "%s" SLASH "hosts", confbase); - dir = opendir(dname); - if(!dir) { - logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno)); - free(dname); - return; - } - - while((ent = readdir(dir))) { - if(!check_id(ent->d_name)) - continue; - - node_t *n = lookup_node(ent->d_name); - #ifdef _DIRENT_HAVE_D_TYPE - //if(ent->d_type != DT_REG) - // continue; - #endif - - splay_tree_t *config_tree; - init_configuration(&config_tree); - read_config_options(config_tree, ent->d_name); - read_host_config(config_tree, ent->d_name); - - if(!n) { - n = new_node(); - n->name = xstrdup(ent->d_name); - node_add(n); - } - - for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) { - subnet_t *s, *s2; - - if(!get_config_subnet(cfg, &s)) - continue; - - if((s2 = lookup_subnet(n, s))) { - s2->expires = -1; - } else { - subnet_add(n, s); - } - } - - exit_configuration(&config_tree); - } - - closedir(dir); -} - void load_all_nodes(void) { DIR *dir; struct dirent *ent; @@ -771,25 +714,12 @@ bool setup_myself(void) { sockaddr2str(&sa, NULL, &myport); } - /* Read in all the subnets specified in the host configuration file */ - - for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) { - subnet_t *subnet; - - if(!get_config_subnet(cfg, &subnet)) - return false; - - subnet_add(myself, subnet); - } - /* Check some options */ if(!setup_myself_reloadable()) return false; - get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets); get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver); - strictsubnets |= tunnelserver; if(get_config_int(lookup_config(config_tree, "MaxConnectionBurst"), &max_connection_burst)) { if(max_connection_burst <= 0) { @@ -883,9 +813,7 @@ bool setup_myself(void) { graph(); - if(strictsubnets) - load_all_subnets(); - else if(autoconnect) + if(autoconnect) load_all_nodes(); /* Open sockets */ @@ -986,7 +914,6 @@ bool setup_myself(void) { */ bool setup_network(void) { init_connections(); - init_subnets(); init_nodes(); init_edges(); init_requests(); @@ -1023,10 +950,6 @@ bool setup_network(void) { for(int i = 0; i < 4; i++) free(envp[i]); - /* Run subnet-up scripts for our own subnets */ - - subnet_update(myself, NULL, true); - return true; } @@ -1048,7 +971,6 @@ void close_network_connections(void) { list_delete_list(outgoing_list); if(myself && myself->connection) { - subnet_update(myself, NULL, false); terminate_connection(myself->connection, false); free_connection(myself->connection); } @@ -1066,7 +988,6 @@ void close_network_connections(void) { exit_requests(); exit_edges(); - exit_subnets(); exit_nodes(); exit_connections(); diff --git a/src/node.c b/src/node.c index aab83ca7..42eb25cb 100644 --- a/src/node.c +++ b/src/node.c @@ -53,7 +53,6 @@ node_t *new_node(void) { node_t *n = xzalloc(sizeof *n); if(replaywin) n->late = xzalloc(replaywin); - n->subnet_tree = new_subnet_tree(); n->edge_tree = new_edge_tree(); n->mtu = MTU; n->maxmtu = MTU; @@ -62,9 +61,6 @@ node_t *new_node(void) { } void free_node(node_t *n) { - if(n->subnet_tree) - free_subnet_tree(n->subnet_tree); - if(n->edge_tree) free_edge_tree(n->edge_tree); @@ -97,9 +93,6 @@ void node_add(node_t *n) { } void node_del(node_t *n) { - for splay_each(subnet_t, s, n->subnet_tree) - subnet_del(n, s); - for splay_each(edge_t, e, n->edge_tree) edge_del(e); diff --git a/src/node.h b/src/node.h index 1c9f230a..a1f2ff7d 100644 --- a/src/node.h +++ b/src/node.h @@ -26,7 +26,6 @@ #include "connection.h" #include "digest.h" #include "event.h" -#include "subnet.h" typedef struct node_status_t { unsigned int unused_active:1; /* 1 if active (not used for nodes) */ @@ -70,8 +69,6 @@ typedef struct node_t { struct edge_t *prevedge; /* nearest node from him to us */ struct node_t *via; /* next hop for UDP packets */ - splay_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */ - splay_tree_t *edge_tree; /* Edges with this node as one of the endpoints */ struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */ diff --git a/src/process.c b/src/process.c index eb084f4e..f2969163 100644 --- a/src/process.c +++ b/src/process.c @@ -30,7 +30,6 @@ #include "net.h" #include "node.h" #include "process.h" -#include "subnet.h" #include "utils.h" #include "xalloc.h" diff --git a/src/protocol.c b/src/protocol.c index 374c5229..8f6230f6 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -29,7 +29,6 @@ #include "xalloc.h" bool tunnelserver = false; -bool strictsubnets = false; bool experimental = true; /* Jumptable for the request handlers */ @@ -38,7 +37,7 @@ static bool (*request_handlers[])(connection_t *, const char *) = { id_h, metakey_h, challenge_h, chal_reply_h, ack_h, status_h, error_h, termreq_h, ping_h, pong_h, - add_subnet_h, del_subnet_h, + NULL, NULL, //add_subnet_h, del_subnet_h, add_edge_h, del_edge_h, key_changed_h, req_key_h, ans_key_h, tcppacket_h, control_h, }; diff --git a/src/protocol.h b/src/protocol.h index e771c545..663d5788 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -58,7 +58,6 @@ typedef struct past_request_t { } past_request_t; extern bool tunnelserver; -extern bool strictsubnets; extern bool experimental; extern ecdsa_t *invitation_key; @@ -74,7 +73,6 @@ extern ecdsa_t *invitation_key; #include "edge.h" #include "net.h" #include "node.h" -#include "subnet.h" /* Basic functions */ @@ -100,8 +98,6 @@ extern bool send_error(struct connection_t *, int, const char *); extern bool send_termreq(struct connection_t *); extern bool send_ping(struct connection_t *); extern bool send_pong(struct connection_t *); -extern bool send_add_subnet(struct connection_t *, const struct subnet_t *); -extern bool send_del_subnet(struct connection_t *, const struct subnet_t *); extern bool send_add_edge(struct connection_t *, const struct edge_t *); extern bool send_del_edge(struct connection_t *, const struct edge_t *); extern void send_key_changed(void); @@ -121,8 +117,6 @@ extern bool error_h(struct connection_t *, const char *); extern bool termreq_h(struct connection_t *, const char *); extern bool ping_h(struct connection_t *, const char *); extern bool pong_h(struct connection_t *, const char *); -extern bool add_subnet_h(struct connection_t *, const char *); -extern bool del_subnet_h(struct connection_t *, const char *); extern bool add_edge_h(struct connection_t *, const char *); extern bool del_edge_h(struct connection_t *, const char *); extern bool key_changed_h(struct connection_t *, const char *); diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 551bff60..a1395b71 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -678,6 +678,7 @@ bool send_ack(connection_t *c) { static void send_everything(connection_t *c) { /* Send all known subnets and edges */ + // TODO: remove this if(disablebuggypeers) { static struct { vpn_packet_t pkt; @@ -689,17 +690,7 @@ static void send_everything(connection_t *c) { send_tcppacket(c, &zeropkt.pkt); } - if(tunnelserver) { - for splay_each(subnet_t, s, myself->subnet_tree) - send_add_subnet(c, s); - - return; - } - for splay_each(node_t, n, node_tree) { - for splay_each(subnet_t, s, n->subnet_tree) - send_add_subnet(c, s); - for splay_each(edge_t, e, n->edge_tree) send_add_edge(c, e); } diff --git a/src/protocol_subnet.c b/src/protocol_subnet.c deleted file mode 100644 index 06dafbc7..00000000 --- a/src/protocol_subnet.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - protocol_subnet.c -- handle the meta-protocol, subnets - Copyright (C) 1999-2005 Ivo Timmermans, - 2000-2012 Guus Sliepen - 2009 Michael Tokarev - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "system.h" - -#include "conf.h" -#include "connection.h" -#include "logger.h" -#include "net.h" -#include "netutl.h" -#include "node.h" -#include "protocol.h" -#include "subnet.h" -#include "utils.h" -#include "xalloc.h" - -bool send_add_subnet(connection_t *c, const subnet_t *subnet) { - char netstr[MAXNETSTR]; - - if(!net2str(netstr, sizeof netstr, subnet)) - return false; - - return send_request(c, "%d %x %s %s", ADD_SUBNET, rand(), subnet->owner->name, netstr); -} - -bool add_subnet_h(connection_t *c, const char *request) { - char subnetstr[MAX_STRING_SIZE]; - char name[MAX_STRING_SIZE]; - node_t *owner; - subnet_t s = {NULL}, *new, *old; - - if(sscanf(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) { - logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name, - c->hostname); - return false; - } - - /* Check if owner name is valid */ - - if(!check_id(name)) { - logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name, - c->hostname, "invalid name"); - return false; - } - - /* Check if subnet string is valid */ - - if(!str2net(&s, subnetstr)) { - logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name, - c->hostname, "invalid subnet string"); - return false; - } - - if(seen_request(request)) - return true; - - /* Check if the owner of the new subnet is in the connection list */ - - owner = lookup_node(name); - - if(tunnelserver && owner != myself && owner != c->node) { - /* in case of tunnelserver, ignore indirect subnet registrations */ - logger(DEBUG_PROTOCOL, LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s", - "ADD_SUBNET", c->name, c->hostname, subnetstr); - return true; - } - - if(!owner) { - owner = new_node(); - owner->name = xstrdup(name); - node_add(owner); - } - - /* Check if we already know this subnet */ - - if(lookup_subnet(owner, &s)) - return true; - - /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */ - - if(owner == myself) { - logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself", - "ADD_SUBNET", c->name, c->hostname); - s.owner = myself; - send_del_subnet(c, &s); - return true; - } - - /* In tunnel server mode, we should already know all allowed subnets */ - - if(tunnelserver) { - logger(DEBUG_ALWAYS, LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s", - "ADD_SUBNET", c->name, c->hostname, subnetstr); - return true; - } - - /* Ignore if strictsubnets is true, but forward it to others */ - - if(strictsubnets) { - logger(DEBUG_ALWAYS, LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s", - "ADD_SUBNET", c->name, c->hostname, subnetstr); - forward_request(c, request); - return true; - } - - /* If everything is correct, add the subnet to the list of the owner */ - - *(new = new_subnet()) = s; - subnet_add(owner, new); - - if(owner->status.reachable) - subnet_update(owner, new, true); - - /* Tell the rest */ - - if(!tunnelserver) - forward_request(c, request); - - /* Fast handoff of roaming MAC addresses */ - - if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires) - old->expires = 1; - - return true; -} - -bool send_del_subnet(connection_t *c, const subnet_t *s) { - char netstr[MAXNETSTR]; - - if(!net2str(netstr, sizeof netstr, s)) - return false; - - return send_request(c, "%d %x %s %s", DEL_SUBNET, rand(), s->owner->name, netstr); -} - -bool del_subnet_h(connection_t *c, const char *request) { - char subnetstr[MAX_STRING_SIZE]; - char name[MAX_STRING_SIZE]; - node_t *owner; - subnet_t s = {NULL}, *find; - - if(sscanf(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) { - logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "DEL_SUBNET", c->name, - c->hostname); - return false; - } - - /* Check if owner name is valid */ - - if(!check_id(name)) { - logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name, - c->hostname, "invalid name"); - return false; - } - - /* Check if subnet string is valid */ - - if(!str2net(&s, subnetstr)) { - logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name, - c->hostname, "invalid subnet string"); - return false; - } - - if(seen_request(request)) - return true; - - /* Check if the owner of the subnet being deleted is in the connection list */ - - owner = lookup_node(name); - - if(tunnelserver && owner != myself && owner != c->node) { - /* in case of tunnelserver, ignore indirect subnet deletion */ - logger(DEBUG_PROTOCOL, LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s", - "DEL_SUBNET", c->name, c->hostname, subnetstr); - return true; - } - - if(!owner) { - logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for %s which is not in our node tree", - "DEL_SUBNET", c->name, c->hostname, name); - return true; - } - - /* If everything is correct, delete the subnet from the list of the owner */ - - s.owner = owner; - - find = lookup_subnet(owner, &s); - - if(!find) { - logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for %s which does not appear in his subnet tree", - "DEL_SUBNET", c->name, c->hostname, name); - if(strictsubnets) - forward_request(c, request); - return true; - } - - /* If we are the owner of this subnet, retaliate with an ADD_SUBNET */ - - if(owner == myself) { - logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself", - "DEL_SUBNET", c->name, c->hostname); - send_add_subnet(c, find); - return true; - } - - if(tunnelserver) - return true; - - /* Tell the rest */ - - if(!tunnelserver) - forward_request(c, request); - if(strictsubnets) - return true; - - /* Finally, delete it. */ - - if(owner->status.reachable) - subnet_update(owner, find, false); - - subnet_del(owner, find); - - return true; -} diff --git a/src/route.c b/src/route.c index 00ba4c05..5d967dc3 100644 --- a/src/route.c +++ b/src/route.c @@ -20,17 +20,9 @@ #include "system.h" -#include "connection.h" -#include "control_common.h" -#include "ethernet.h" -#include "ipv4.h" -#include "ipv6.h" #include "logger.h" -#include "meta.h" #include "net.h" -#include "protocol.h" #include "route.h" -#include "subnet.h" #include "utils.h" rmode_t routing_mode = RMODE_ROUTER; @@ -44,43 +36,6 @@ bool overwrite_mac = false; mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}}; bool pcap = false; -/* Sizes of various headers */ - -static const size_t ether_size = sizeof(struct ether_header); -static const size_t arp_size = sizeof(struct ether_arp); -static const size_t ip_size = sizeof(struct ip); -static const size_t icmp_size = sizeof(struct icmp) - sizeof(struct ip); -static const size_t ip6_size = sizeof(struct ip6_hdr); -static const size_t icmp6_size = sizeof(struct icmp6_hdr); -static const size_t ns_size = sizeof(struct nd_neighbor_solicit); -static const size_t opt_size = sizeof(struct nd_opt_hdr); - -#ifndef MAX -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#endif - -static timeout_t age_subnets_timeout; - -/* RFC 1071 */ - -static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { - uint16_t *p = data; - uint32_t checksum = prevsum ^ 0xFFFF; - - while(len >= 2) { - checksum += *p++; - len -= 2; - } - - if(len) - checksum += *(uint8_t *)p; - - while(checksum >> 16) - checksum = (checksum & 0xFFFF) + (checksum >> 16); - - return ~checksum; -} - static bool ratelimit(int frequency) { static time_t lasttime = 0; static int count = 0; @@ -105,891 +60,6 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) { return true; } -static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) { - if(!source || !via || !(via->options & OPTION_CLAMP_MSS)) - return; - - uint16_t mtu = source->mtu; - if(via != myself && via->mtu < mtu) - mtu = via->mtu; - - /* Find TCP header */ - int start = ether_size; - uint16_t type = packet->data[12] << 8 | packet->data[13]; - - if(type == ETH_P_8021Q) { - start += 4; - type = packet->data[16] << 8 | packet->data[17]; - } - - if(type == ETH_P_IP && packet->data[start + 9] == 6) - start += (packet->data[start] & 0xf) * 4; - else if(type == ETH_P_IPV6 && packet->data[start + 6] == 6) - start += 40; - else - return; - - if(packet->len <= start + 20) - return; - - /* Use data offset field to calculate length of options field */ - int len = ((packet->data[start + 12] >> 4) - 5) * 4; - - if(packet->len < start + 20 + len) - return; - - /* Search for MSS option header */ - for(int i = 0; i < len;) { - if(packet->data[start + 20 + i] == 0) - break; - - if(packet->data[start + 20 + i] == 1) { - i++; - continue; - } - - if(i > len - 2 || i > len - packet->data[start + 21 + i]) - break; - - if(packet->data[start + 20 + i] != 2) { - if(packet->data[start + 21 + i] < 2) - break; - i += packet->data[start + 21 + i]; - continue; - } - - if(packet->data[start + 21] != 4) - break; - - /* Found it */ - uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i]; - uint16_t newmss = mtu - start - 20; - uint16_t csum = packet->data[start + 16] << 8 | packet->data[start + 17]; - - if(oldmss <= newmss) - break; - - logger(DEBUG_TRAFFIC, LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss); - - /* Update the MSS value and the checksum */ - packet->data[start + 22 + i] = newmss >> 8; - packet->data[start + 23 + i] = newmss & 0xff; - csum ^= 0xffff; - csum -= oldmss; - csum += newmss; - csum ^= 0xffff; - packet->data[start + 16] = csum >> 8; - packet->data[start + 17] = csum & 0xff; - break; - } -} - -static void swap_mac_addresses(vpn_packet_t *packet) { - mac_t tmp; - memcpy(&tmp, &packet->data[0], sizeof tmp); - memcpy(&packet->data[0], &packet->data[6], sizeof tmp); - memcpy(&packet->data[6], &tmp, sizeof tmp); -} - -static void age_subnets(void *data) { - bool left = false; - - for splay_each(subnet_t, s, myself->subnet_tree) { - if(s->expires && s->expires < now.tv_sec) { - if(debug_level >= DEBUG_TRAFFIC) { - char netstr[MAXNETSTR]; - if(net2str(netstr, sizeof netstr, s)) - logger(DEBUG_TRAFFIC, LOG_INFO, "Subnet %s expired", netstr); - } - - for list_each(connection_t, c, connection_list) - if(c->status.active) - send_del_subnet(c, s); - - subnet_del(myself, s); - } else { - if(s->expires) - left = true; - } - } - - if(left) - timeout_set(&age_subnets_timeout, &(struct timeval){10, rand() % 100000}); -} - -static void learn_mac(mac_t *address) { - subnet_t *subnet = lookup_subnet_mac(myself, address); - - /* If we don't know this MAC address yet, store it */ - - if(!subnet) { - logger(DEBUG_TRAFFIC, LOG_INFO, "Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx", - address->x[0], address->x[1], address->x[2], address->x[3], - address->x[4], address->x[5]); - - subnet = new_subnet(); - subnet->type = SUBNET_MAC; - subnet->expires = now.tv_sec + macexpire; - subnet->net.mac.address = *address; - subnet->weight = 10; - subnet_add(myself, subnet); - subnet_update(myself, subnet, true); - - /* And tell all other tinc daemons it's our MAC */ - - for list_each(connection_t, c, connection_list) - if(c->status.active) - send_add_subnet(c, subnet); - - timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval){10, rand() % 100000}); - } else { - if(subnet->expires) - subnet->expires = now.tv_sec + macexpire; - } -} - -/* RFC 792 */ - -static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { - struct ip ip = {0}; - struct icmp icmp = {0}; - - struct in_addr ip_src; - struct in_addr ip_dst; - uint32_t oldlen; - - if(ratelimit(3)) - return; - - /* Swap Ethernet source and destination addresses */ - - swap_mac_addresses(packet); - - /* Copy headers from packet into properly aligned structs on the stack */ - - memcpy(&ip, packet->data + ether_size, ip_size); - - /* Remember original source and destination */ - - ip_src = ip.ip_src; - ip_dst = ip.ip_dst; - - oldlen = packet->len - ether_size; - - if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) - icmp.icmp_nextmtu = htons(packet->len - ether_size); - - if(oldlen >= IP_MSS - ip_size - icmp_size) - oldlen = IP_MSS - ip_size - icmp_size; - - /* Copy first part of original contents to ICMP message */ - - memmove(packet->data + ether_size + ip_size + icmp_size, packet->data + ether_size, oldlen); - - /* Fill in IPv4 header */ - - ip.ip_v = 4; - ip.ip_hl = ip_size / 4; - ip.ip_tos = 0; - ip.ip_len = htons(ip_size + icmp_size + oldlen); - ip.ip_id = 0; - ip.ip_off = 0; - ip.ip_ttl = 255; - ip.ip_p = IPPROTO_ICMP; - ip.ip_sum = 0; - ip.ip_src = ip_dst; - ip.ip_dst = ip_src; - - ip.ip_sum = inet_checksum(&ip, ip_size, ~0); - - /* Fill in ICMP header */ - - icmp.icmp_type = type; - icmp.icmp_code = code; - icmp.icmp_cksum = 0; - - icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0); - icmp.icmp_cksum = inet_checksum(packet->data + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum); - - /* Copy structs on stack back to packet */ - - memcpy(packet->data + ether_size, &ip, ip_size); - memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size); - - packet->len = ether_size + ip_size + icmp_size + oldlen; - - send_packet(source, packet); -} - -/* RFC 791 */ - -static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t ether_size) { - struct ip ip; - vpn_packet_t fragment; - int len, maxlen, todo; - uint8_t *offset; - uint16_t ip_off, origf; - - memcpy(&ip, packet->data + ether_size, ip_size); - fragment.priority = packet->priority; - - if(ip.ip_hl != ip_size / 4) - return; - - todo = ntohs(ip.ip_len) - ip_size; - - if(ether_size + ip_size + todo != packet->len) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Length of packet (%d) doesn't match length in IPv4 header (%d)", packet->len, (int)(ether_size + ip_size + todo)); - return; - } - - logger(DEBUG_TRAFFIC, LOG_INFO, "Fragmenting packet of %d bytes to %s (%s)", packet->len, dest->name, dest->hostname); - - offset = packet->data + ether_size + ip_size; - maxlen = (dest->mtu - ether_size - ip_size) & ~0x7; - ip_off = ntohs(ip.ip_off); - origf = ip_off & ~IP_OFFMASK; - ip_off &= IP_OFFMASK; - - while(todo) { - len = todo > maxlen ? maxlen : todo; - memcpy(fragment.data + ether_size + ip_size, offset, len); - todo -= len; - offset += len; - - ip.ip_len = htons(ip_size + len); - ip.ip_off = htons(ip_off | origf | (todo ? IP_MF : 0)); - ip.ip_sum = 0; - ip.ip_sum = inet_checksum(&ip, ip_size, ~0); - memcpy(fragment.data, packet->data, ether_size); - memcpy(fragment.data + ether_size, &ip, ip_size); - fragment.len = ether_size + ip_size + len; - - send_packet(dest, &fragment); - - ip_off += len / 8; - } -} - -static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { - subnet_t *subnet; - node_t *via; - ipv4_t dest; - - memcpy(&dest, &packet->data[30], sizeof dest); - subnet = lookup_subnet_ipv4(&dest); - - if(!subnet) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv4 destination address %d.%d.%d.%d", - source->name, source->hostname, - dest.x[0], - dest.x[1], - dest.x[2], - dest.x[3]); - - route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN); - return; - } - - if(subnet->owner == source) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname); - return; - } - - if(!subnet->owner->status.reachable) - return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNREACH); - - if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) - return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO); - - if(priorityinheritance) - packet->priority = packet->data[15]; - - via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; - - if(via == source) { - logger(DEBUG_TRAFFIC, LOG_ERR, "Routing loop for packet from %s (%s)!", source->name, source->hostname); - return; - } - - if(directonly && subnet->owner != via) - return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO); - - if(via && packet->len > MAX(via->mtu, 590) && via != myself) { - logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); - if(packet->data[20] & 0x40) { - packet->len = MAX(via->mtu, 590); - route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED); - } else { - fragment_ipv4_packet(via, packet, ether_size); - } - - return; - } - - clamp_mss(source, via, packet); - - send_packet(subnet->owner, packet); -} - -static void route_ipv4(node_t *source, vpn_packet_t *packet) { - if(!checklength(source, packet, ether_size + ip_size)) - return; - - if(broadcast_mode && (((packet->data[30] & 0xf0) == 0xe0) || ( - packet->data[30] == 255 && - packet->data[31] == 255 && - packet->data[32] == 255 && - packet->data[33] == 255))) - broadcast_packet(source, packet); - else - route_ipv4_unicast(source, packet); -} - -/* RFC 2463 */ - -static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { - struct ip6_hdr ip6; - struct icmp6_hdr icmp6 = {0}; - uint16_t checksum; - - struct { - struct in6_addr ip6_src; /* source address */ - struct in6_addr ip6_dst; /* destination address */ - uint32_t length; - uint32_t next; - } pseudo; - - if(ratelimit(3)) - return; - - /* Swap Ethernet source and destination addresses */ - - swap_mac_addresses(packet); - - /* Copy headers from packet to structs on the stack */ - - memcpy(&ip6, packet->data + ether_size, ip6_size); - - /* Remember original source and destination */ - - pseudo.ip6_src = ip6.ip6_dst; - pseudo.ip6_dst = ip6.ip6_src; - - pseudo.length = packet->len - ether_size; - - if(type == ICMP6_PACKET_TOO_BIG) - icmp6.icmp6_mtu = htonl(pseudo.length); - - if(pseudo.length >= IP_MSS - ip6_size - icmp6_size) - pseudo.length = IP_MSS - ip6_size - icmp6_size; - - /* Copy first part of original contents to ICMP message */ - - memmove(packet->data + ether_size + ip6_size + icmp6_size, packet->data + ether_size, pseudo.length); - - /* Fill in IPv6 header */ - - ip6.ip6_flow = htonl(0x60000000UL); - ip6.ip6_plen = htons(icmp6_size + pseudo.length); - ip6.ip6_nxt = IPPROTO_ICMPV6; - ip6.ip6_hlim = 255; - ip6.ip6_src = pseudo.ip6_src; - ip6.ip6_dst = pseudo.ip6_dst; - - /* Fill in ICMP header */ - - icmp6.icmp6_type = type; - icmp6.icmp6_code = code; - icmp6.icmp6_cksum = 0; - - /* Create pseudo header */ - - pseudo.length = htonl(icmp6_size + pseudo.length); - pseudo.next = htonl(IPPROTO_ICMPV6); - - /* Generate checksum */ - - checksum = inet_checksum(&pseudo, sizeof pseudo, ~0); - checksum = inet_checksum(&icmp6, icmp6_size, checksum); - checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum); - - icmp6.icmp6_cksum = checksum; - - /* Copy structs on stack back to packet */ - - memcpy(packet->data + ether_size, &ip6, ip6_size); - memcpy(packet->data + ether_size + ip6_size, &icmp6, icmp6_size); - - packet->len = ether_size + ip6_size + ntohl(pseudo.length); - - send_packet(source, packet); -} - -static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { - subnet_t *subnet; - node_t *via; - ipv6_t dest; - - memcpy(&dest, &packet->data[38], sizeof dest); - subnet = lookup_subnet_ipv6(&dest); - - if(!subnet) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", - source->name, source->hostname, - ntohs(dest.x[0]), - ntohs(dest.x[1]), - ntohs(dest.x[2]), - ntohs(dest.x[3]), - ntohs(dest.x[4]), - ntohs(dest.x[5]), - ntohs(dest.x[6]), - ntohs(dest.x[7])); - - route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR); - return; - } - - if(subnet->owner == source) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname); - return; - } - - if(!subnet->owner->status.reachable) - return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE); - - if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) - return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); - - via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; - - if(via == source) { - logger(DEBUG_TRAFFIC, LOG_ERR, "Routing loop for packet from %s (%s)!", source->name, source->hostname); - return; - } - - if(directonly && subnet->owner != via) - return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); - - if(via && packet->len > MAX(via->mtu, 1294) && via != myself) { - logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); - packet->len = MAX(via->mtu, 1294); - route_ipv6_unreachable(source, packet, ether_size, ICMP6_PACKET_TOO_BIG, 0); - return; - } - - clamp_mss(source, via, packet); - - send_packet(subnet->owner, packet); -} - -/* RFC 2461 */ - -static void route_neighborsol(node_t *source, vpn_packet_t *packet) { - struct ip6_hdr ip6; - struct nd_neighbor_solicit ns; - struct nd_opt_hdr opt; - subnet_t *subnet; - uint16_t checksum; - bool has_opt; - - struct { - struct in6_addr ip6_src; - struct in6_addr ip6_dst; - uint32_t length; - uint32_t next; - } pseudo; - - if(!checklength(source, packet, ether_size + ip6_size + ns_size)) - return; - - has_opt = packet->len >= ether_size + ip6_size + ns_size + opt_size + ETH_ALEN; - - if(source != myself) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Got neighbor solicitation request from %s (%s) while in router mode!", source->name, source->hostname); - return; - } - - /* Copy headers from packet to structs on the stack */ - - memcpy(&ip6, packet->data + ether_size, ip6_size); - memcpy(&ns, packet->data + ether_size + ip6_size, ns_size); - if(has_opt) - memcpy(&opt, packet->data + ether_size + ip6_size + ns_size, opt_size); - - /* First, snatch the source address from the neighbor solicitation packet */ - - if(overwrite_mac) - memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN); - - /* Check if this is a valid neighbor solicitation request */ - - if(ns.nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT || - (has_opt && opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR)) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet: received unknown type neighbor solicitation request"); - return; - } - - /* Create pseudo header */ - - pseudo.ip6_src = ip6.ip6_src; - pseudo.ip6_dst = ip6.ip6_dst; - if(has_opt) - pseudo.length = htonl(ns_size + opt_size + ETH_ALEN); - else - pseudo.length = htonl(ns_size); - pseudo.next = htonl(IPPROTO_ICMPV6); - - /* Generate checksum */ - - checksum = inet_checksum(&pseudo, sizeof pseudo, ~0); - checksum = inet_checksum(&ns, ns_size, checksum); - if(has_opt) { - checksum = inet_checksum(&opt, opt_size, checksum); - checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum); - } - - if(checksum) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet: checksum error for neighbor solicitation request"); - return; - } - - /* Check if the IPv6 address exists on the VPN */ - - subnet = lookup_subnet_ipv6((ipv6_t *) &ns.nd_ns_target); - - if(!subnet) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", - ntohs(((uint16_t *) &ns.nd_ns_target)[0]), - ntohs(((uint16_t *) &ns.nd_ns_target)[1]), - ntohs(((uint16_t *) &ns.nd_ns_target)[2]), - ntohs(((uint16_t *) &ns.nd_ns_target)[3]), - ntohs(((uint16_t *) &ns.nd_ns_target)[4]), - ntohs(((uint16_t *) &ns.nd_ns_target)[5]), - ntohs(((uint16_t *) &ns.nd_ns_target)[6]), - ntohs(((uint16_t *) &ns.nd_ns_target)[7])); - - return; - } - - /* Check if it is for our own subnet */ - - if(subnet->owner == myself) - return; /* silently ignore */ - - /* Create neighbor advertation reply */ - - memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ - packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ - - ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */ - ip6.ip6_src = ns.nd_ns_target; - - if(has_opt) - memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ - - ns.nd_ns_cksum = 0; - ns.nd_ns_type = ND_NEIGHBOR_ADVERT; - ns.nd_ns_reserved = htonl(0x40000000UL); /* Set solicited flag */ - opt.nd_opt_type = ND_OPT_TARGET_LINKADDR; - - /* Create pseudo header */ - - pseudo.ip6_src = ip6.ip6_src; - pseudo.ip6_dst = ip6.ip6_dst; - if(has_opt) - pseudo.length = htonl(ns_size + opt_size + ETH_ALEN); - else - pseudo.length = htonl(ns_size); - pseudo.next = htonl(IPPROTO_ICMPV6); - - /* Generate checksum */ - - checksum = inet_checksum(&pseudo, sizeof pseudo, ~0); - checksum = inet_checksum(&ns, ns_size, checksum); - if(has_opt) { - checksum = inet_checksum(&opt, opt_size, checksum); - checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum); - } - - ns.nd_ns_hdr.icmp6_cksum = checksum; - - /* Copy structs on stack back to packet */ - - memcpy(packet->data + ether_size, &ip6, ip6_size); - memcpy(packet->data + ether_size + ip6_size, &ns, ns_size); - if(has_opt) - memcpy(packet->data + ether_size + ip6_size + ns_size, &opt, opt_size); - - send_packet(source, packet); -} - -static void route_ipv6(node_t *source, vpn_packet_t *packet) { - if(!checklength(source, packet, ether_size + ip6_size)) - return; - - if(packet->data[20] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + icmp6_size) && packet->data[54] == ND_NEIGHBOR_SOLICIT) { - route_neighborsol(source, packet); - return; - } - - if(broadcast_mode && packet->data[38] == 255) - broadcast_packet(source, packet); - else - route_ipv6_unicast(source, packet); -} - -/* RFC 826 */ - -static void route_arp(node_t *source, vpn_packet_t *packet) { - struct ether_arp arp; - subnet_t *subnet; - struct in_addr addr; - - if(!checklength(source, packet, ether_size + arp_size)) - return; - - if(source != myself) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Got ARP request from %s (%s) while in router mode!", source->name, source->hostname); - return; - } - - /* First, snatch the source address from the ARP packet */ - - if(overwrite_mac) - memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN); - - /* Copy headers from packet to structs on the stack */ - - memcpy(&arp, packet->data + ether_size, arp_size); - - /* Check if this is a valid ARP request */ - - if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP || - arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof addr || ntohs(arp.arp_op) != ARPOP_REQUEST) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet: received unknown type ARP request"); - return; - } - - /* Check if the IPv4 address exists on the VPN */ - - subnet = lookup_subnet_ipv4((ipv4_t *) &arp.arp_tpa); - - if(!subnet) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet: ARP request for unknown address %d.%d.%d.%d", - arp.arp_tpa[0], arp.arp_tpa[1], arp.arp_tpa[2], - arp.arp_tpa[3]); - return; - } - - /* Check if it is for our own subnet */ - - if(subnet->owner == myself) - return; /* silently ignore */ - - memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ - packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ - - memcpy(&addr, arp.arp_tpa, sizeof addr); /* save protocol addr */ - memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr); /* swap destination and source protocol address */ - memcpy(arp.arp_spa, &addr, sizeof addr); /* ... */ - - memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */ - memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ - arp.arp_op = htons(ARPOP_REPLY); - - /* Copy structs on stack back to packet */ - - memcpy(packet->data + ether_size, &arp, arp_size); - - send_packet(source, packet); -} - -static void route_mac(node_t *source, vpn_packet_t *packet) { - subnet_t *subnet; - mac_t dest; - - /* Learn source address */ - - if(source == myself) { - mac_t src; - memcpy(&src, &packet->data[6], sizeof src); - learn_mac(&src); - } - - /* Lookup destination address */ - - memcpy(&dest, &packet->data[0], sizeof dest); - subnet = lookup_subnet_mac(NULL, &dest); - - if(!subnet) { - broadcast_packet(source, packet); - return; - } - - if(subnet->owner == source) { - logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname); - return; - } - - if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) - return; - - uint16_t type = packet->data[12] << 8 | packet->data[13]; - - if(priorityinheritance && type == ETH_P_IP && packet->len >= ether_size + ip_size) - packet->priority = packet->data[15]; - - // Handle packets larger than PMTU - - node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; - - if(directonly && subnet->owner != via) - return; - - if(via && packet->len > via->mtu && via != myself) { - logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); - length_t ethlen = 14; - - if(type == ETH_P_8021Q) { - type = packet->data[16] << 8 | packet->data[17]; - ethlen += 4; - } - - if(type == ETH_P_IP && packet->len > 576 + ethlen) { - if(packet->data[6 + ethlen] & 0x40) { - packet->len = via->mtu; - route_ipv4_unreachable(source, packet, ethlen, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED); - } else { - fragment_ipv4_packet(via, packet, ethlen); - } - return; - } else if(type == ETH_P_IPV6 && packet->len > 1280 + ethlen) { - packet->len = via->mtu; - route_ipv6_unreachable(source, packet, ethlen, ICMP6_PACKET_TOO_BIG, 0); - return; - } - } - - clamp_mss(source, via, packet); - - send_packet(subnet->owner, packet); -} - -static void send_pcap(vpn_packet_t *packet) { - pcap = false; - - for list_each(connection_t, c, connection_list) { - if(!c->status.pcap) - continue; - - pcap = true; - int len = packet->len; - if(c->outmaclength && c->outmaclength < len) - len = c->outmaclength; - - if(send_request(c, "%d %d %d", CONTROL, REQ_PCAP, len)) - send_meta(c, (char *)packet->data, len); - } -} - -static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) { - uint16_t type = packet->data[12] << 8 | packet->data[13]; - length_t ethlen = ether_size; - - if(type == ETH_P_8021Q) { - type = packet->data[16] << 8 | packet->data[17]; - ethlen += 4; - } - - switch (type) { - case ETH_P_IP: - if(!checklength(source, packet, ethlen + ip_size)) - return false; - - if(packet->data[ethlen + 8] < 1) { - if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED) - route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL); - return false; - } - - uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9]; - packet->data[ethlen + 8]--; - uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9]; - - uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11]; - checksum += old + (~new & 0xFFFF); - while(checksum >> 16) - checksum = (checksum & 0xFFFF) + (checksum >> 16); - packet->data[ethlen + 10] = checksum >> 8; - packet->data[ethlen + 11] = checksum & 0xff; - - return true; - - case ETH_P_IPV6: - if(!checklength(source, packet, ethlen + ip6_size)) - return false; - - if(packet->data[ethlen + 7] < 1) { - if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED) - route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT); - return false; - } - - packet->data[ethlen + 7]--; - - return true; - - default: - return true; - } -} - void route(node_t *source, vpn_packet_t *packet) { - if(pcap) - send_pcap(packet); - - if(forwarding_mode == FMODE_KERNEL && source != myself) { - send_packet(myself, packet); - return; - } - - if(!checklength(source, packet, ether_size)) - return; - - if(decrement_ttl && source != myself) - if(!do_decrement_ttl(source, packet)) - return; - - uint16_t type = packet->data[12] << 8 | packet->data[13]; - - switch (routing_mode) { - case RMODE_ROUTER: - switch (type) { - case ETH_P_ARP: - route_arp(source, packet); - break; - - case ETH_P_IP: - route_ipv4(source, packet); - break; - - case ETH_P_IPV6: - route_ipv6(source, packet); - break; - - default: - logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot route packet from %s (%s): unknown type %hx", source->name, source->hostname, type); - break; - } - break; - - case RMODE_SWITCH: - route_mac(source, packet); - break; - - case RMODE_HUB: - broadcast_packet(source, packet); - break; - } + // TODO: route on name or key } diff --git a/src/script.c b/src/script.c index 9a43d531..e441dcf5 100644 --- a/src/script.c +++ b/src/script.c @@ -23,6 +23,7 @@ #include "conf.h" #include "logger.h" #include "names.h" +#include "net.h" #include "script.h" #include "xalloc.h" diff --git a/src/subnet.c b/src/subnet.c deleted file mode 100644 index e45d0045..00000000 --- a/src/subnet.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - subnet.c -- handle subnet lookups and lists - Copyright (C) 2000-2013 Guus Sliepen , - 2000-2005 Ivo Timmermans - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "system.h" - -#include "splay_tree.h" -#include "control_common.h" -#include "hash.h" -#include "logger.h" -#include "names.h" -#include "net.h" -#include "netutl.h" -#include "node.h" -#include "script.h" -#include "subnet.h" -#include "utils.h" -#include "xalloc.h" - -/* lists type of subnet */ - -splay_tree_t *subnet_tree; - -/* Subnet lookup cache */ - -hash_t *ipv4_cache; -hash_t *ipv6_cache; -hash_t *mac_cache; - -void subnet_cache_flush(void) { - hash_clear(ipv4_cache); - hash_clear(ipv6_cache); - hash_clear(mac_cache); -} - -/* Initialising trees */ - -void init_subnets(void) { - subnet_tree = splay_alloc_tree((splay_compare_t) subnet_compare, (splay_action_t) free_subnet); - - ipv4_cache = hash_alloc(0x100, sizeof(ipv4_t)); - ipv6_cache = hash_alloc(0x100, sizeof(ipv6_t)); - mac_cache = hash_alloc(0x100, sizeof(mac_t)); -} - -void exit_subnets(void) { - splay_delete_tree(subnet_tree); - - hash_free(ipv4_cache); - hash_free(ipv6_cache); - hash_free(mac_cache); -} - -splay_tree_t *new_subnet_tree(void) { - return splay_alloc_tree((splay_compare_t) subnet_compare, NULL); -} - -void free_subnet_tree(splay_tree_t *subnet_tree) { - splay_delete_tree(subnet_tree); -} - -/* Allocating and freeing space for subnets */ - -subnet_t *new_subnet(void) { - return xzalloc(sizeof(subnet_t)); -} - -void free_subnet(subnet_t *subnet) { - free(subnet); -} - -/* Adding and removing subnets */ - -void subnet_add(node_t *n, subnet_t *subnet) { - subnet->owner = n; - - splay_insert(subnet_tree, subnet); - splay_insert(n->subnet_tree, subnet); - - subnet_cache_flush(); -} - -void subnet_del(node_t *n, subnet_t *subnet) { - splay_delete(n->subnet_tree, subnet); - splay_delete(subnet_tree, subnet); - - subnet_cache_flush(); -} - -/* Subnet lookup routines */ - -subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) { - return splay_search(owner->subnet_tree, subnet); -} - -subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) { - subnet_t *r = NULL; - - // Check if this address is cached - - if((r = hash_search(mac_cache, address))) - return r; - - // Search all subnets for a matching one - - for splay_each(subnet_t, p, owner ? owner->subnet_tree : subnet_tree) { - if(!p || p->type != SUBNET_MAC) - continue; - - if(!memcmp(address, &p->net.mac.address, sizeof *address)) { - r = p; - if(p->owner->status.reachable) - break; - } - } - - // Cache the result - - if(r) - hash_insert(mac_cache, address, r); - - return r; -} - -subnet_t *lookup_subnet_ipv4(const ipv4_t *address) { - subnet_t *r = NULL; - - // Check if this address is cached - - if((r = hash_search(ipv4_cache, address))) - return r; - - // Search all subnets for a matching one - - for splay_each(subnet_t, p, subnet_tree) { - if(!p || p->type != SUBNET_IPV4) - continue; - - if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) { - r = p; - if(p->owner->status.reachable) - break; - } - } - - // Cache the result - - if(r) - hash_insert(ipv4_cache, address, r); - - return r; -} - -subnet_t *lookup_subnet_ipv6(const ipv6_t *address) { - subnet_t *r = NULL; - - // Check if this address is cached - - if((r = hash_search(ipv6_cache, address))) - return r; - - // Search all subnets for a matching one - - for splay_each(subnet_t, p, subnet_tree) { - if(!p || p->type != SUBNET_IPV6) - continue; - - if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) { - r = p; - if(p->owner->status.reachable) - break; - } - } - - // Cache the result - - if(r) - hash_insert(ipv6_cache, address, r); - - return r; -} - -void subnet_update(node_t *owner, subnet_t *subnet, bool up) { - char netstr[MAXNETSTR]; - char *name, *address, *port; - char empty[] = ""; - - // Prepare environment variables to be passed to the script - - char *envp[10] = {NULL}; - xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); - xasprintf(&envp[3], "NODE=%s", owner->name); - - if(owner != myself) { - sockaddr2str(&owner->address, &address, &port); - // 4 and 5 are reserved for SUBNET and WEIGHT - xasprintf(&envp[6], "REMOTEADDRESS=%s", address); - xasprintf(&envp[7], "REMOTEPORT=%s", port); - free(port); - free(address); - } - - xasprintf(&envp[8], "NAME=%s", myself->name); - - name = up ? "subnet-up" : "subnet-down"; - - if(!subnet) { - for splay_each(subnet_t, subnet, owner->subnet_tree) { - if(!net2str(netstr, sizeof netstr, subnet)) - continue; - - // Strip the weight from the subnet, and put it in its own environment variable - char *weight = strchr(netstr, '#'); - if(weight) - *weight++ = 0; - else - weight = empty; - - // Prepare the SUBNET and WEIGHT variables - if(envp[4]) - free(envp[4]); - if(envp[5]) - free(envp[5]); - xasprintf(&envp[4], "SUBNET=%s", netstr); - xasprintf(&envp[5], "WEIGHT=%s", weight); - - execute_script(name, envp); - } - } else { - if(net2str(netstr, sizeof netstr, subnet)) { - // Strip the weight from the subnet, and put it in its own environment variable - char *weight = strchr(netstr, '#'); - if(weight) - *weight++ = 0; - else - weight = empty; - - // Prepare the SUBNET and WEIGHT variables - xasprintf(&envp[4], "SUBNET=%s", netstr); - xasprintf(&envp[5], "WEIGHT=%s", weight); - - execute_script(name, envp); - } - } - - for(int i = 0; envp[i] && i < 9; i++) - free(envp[i]); -} - -bool dump_subnets(connection_t *c) { - for splay_each(subnet_t, subnet, subnet_tree) { - char netstr[MAXNETSTR]; - - if(!net2str(netstr, sizeof netstr, subnet)) - continue; - - send_request(c, "%d %d %s %s", - CONTROL, REQ_DUMP_SUBNETS, - netstr, subnet->owner->name); - } - - return send_request(c, "%d %d", CONTROL, REQ_DUMP_SUBNETS); -} diff --git a/src/subnet.h b/src/subnet.h deleted file mode 100644 index 9fd95b64..00000000 --- a/src/subnet.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - subnet.h -- header for subnet.c - Copyright (C) 2000-2012 Guus Sliepen , - 2000-2005 Ivo Timmermans - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#ifndef __TINC_SUBNET_H__ -#define __TINC_SUBNET_H__ - -#include "net.h" - -typedef enum subnet_type_t { - SUBNET_MAC = 0, - SUBNET_IPV4, - SUBNET_IPV6, - SUBNET_TYPES /* Guardian */ -} subnet_type_t; - -typedef struct subnet_mac_t { - mac_t address; -} subnet_mac_t; - -typedef struct subnet_ipv4_t { - ipv4_t address; - int prefixlength; -} subnet_ipv4_t; - -typedef struct subnet_ipv6_t { - ipv6_t address; - int prefixlength; -} subnet_ipv6_t; - -#include "node.h" - -typedef struct subnet_t { - struct node_t *owner; /* the owner of this subnet */ - - subnet_type_t type; /* subnet type (IPv4? IPv6? MAC? something even weirder?) */ - time_t expires; /* expiry time */ - int weight; /* weight (higher value is higher priority) */ - - /* And now for the actual subnet: */ - - union net { - subnet_mac_t mac; - subnet_ipv4_t ipv4; - subnet_ipv6_t ipv6; - } net; -} subnet_t; - -#define MAXNETSTR 64 - -extern splay_tree_t *subnet_tree; - -extern int subnet_compare(const struct subnet_t *, const struct subnet_t *); -extern subnet_t *new_subnet(void) __attribute__ ((__malloc__)); -extern void free_subnet(subnet_t *); -extern void init_subnets(void); -extern void exit_subnets(void); -extern splay_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__)); -extern void free_subnet_tree(splay_tree_t *); -extern void subnet_add(struct node_t *, subnet_t *); -extern void subnet_del(struct node_t *, subnet_t *); -extern void subnet_update(struct node_t *, subnet_t *, bool); -extern int maskcmp(const void *, const void *, int); -extern void maskcpy(void *, const void *, int, int); -extern void mask(void *, int, int); -extern bool maskcheck(const void *, int, int); -extern bool net2str(char *, int, const subnet_t *); -extern bool str2net(subnet_t *, const char *); -extern subnet_t *lookup_subnet(const struct node_t *, const subnet_t *); -extern subnet_t *lookup_subnet_mac(const struct node_t *, const mac_t *); -extern subnet_t *lookup_subnet_ipv4(const ipv4_t *); -extern subnet_t *lookup_subnet_ipv6(const ipv6_t *); -extern bool dump_subnets(struct connection_t *); -extern void subnet_cache_flush(void); - -#endif /* __TINC_SUBNET_H__ */ diff --git a/src/subnet_parse.c b/src/subnet_parse.c deleted file mode 100644 index f9801800..00000000 --- a/src/subnet_parse.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - subnet_parse.c -- handle subnet parsing - Copyright (C) 2000-2012 Guus Sliepen , - 2000-2005 Ivo Timmermans - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "system.h" - -#include "logger.h" -#include "net.h" -#include "netutl.h" -#include "subnet.h" -#include "utils.h" -#include "xalloc.h" - -/* Subnet mask handling */ - -int maskcmp(const void *va, const void *vb, int masklen) { - int i, m, result; - const char *a = va; - const char *b = vb; - - for(m = masklen, i = 0; m >= 8; m -= 8, i++) { - result = a[i] - b[i]; - if(result) - return result; - } - - if(m) - return (a[i] & (0x100 - (1 << (8 - m)))) - - (b[i] & (0x100 - (1 << (8 - m)))); - - return 0; -} - -void mask(void *va, int masklen, int len) { - int i; - char *a = va; - - i = masklen / 8; - masklen %= 8; - - if(masklen) - a[i++] &= (0x100 - (1 << (8 - masklen))); - - for(; i < len; i++) - a[i] = 0; -} - -void maskcpy(void *va, const void *vb, int masklen, int len) { - int i, m; - char *a = va; - const char *b = vb; - - for(m = masklen, i = 0; m >= 8; m -= 8, i++) - a[i] = b[i]; - - if(m) { - a[i] = b[i] & (0x100 - (1 << (8 - m))); - i++; - } - - for(; i < len; i++) - a[i] = 0; -} - -bool maskcheck(const void *va, int masklen, int len) { - int i; - const char *a = va; - - i = masklen / 8; - masklen %= 8; - - if(masklen && a[i++] & (0xff >> masklen)) - return false; - - for(; i < len; i++) - if(a[i] != 0) - return false; - - return true; -} - -/* Subnet comparison */ - -static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) { - int result; - - result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof a->net.mac.address); - - if(result) - return result; - - result = a->weight - b->weight; - - if(result || !a->owner || !b->owner) - return result; - - return strcmp(a->owner->name, b->owner->name); -} - -static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b) { - int result; - - result = b->net.ipv4.prefixlength - a->net.ipv4.prefixlength; - - if(result) - return result; - - result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t)); - - if(result) - return result; - - result = a->weight - b->weight; - - if(result || !a->owner || !b->owner) - return result; - - return strcmp(a->owner->name, b->owner->name); -} - -static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b) { - int result; - - result = b->net.ipv6.prefixlength - a->net.ipv6.prefixlength; - - if(result) - return result; - - result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t)); - - if(result) - return result; - - result = a->weight - b->weight; - - if(result || !a->owner || !b->owner) - return result; - - return strcmp(a->owner->name, b->owner->name); -} - -int subnet_compare(const subnet_t *a, const subnet_t *b) { - int result; - - result = a->type - b->type; - - if(result) - return result; - - switch (a->type) { - case SUBNET_MAC: - return subnet_compare_mac(a, b); - case SUBNET_IPV4: - return subnet_compare_ipv4(a, b); - case SUBNET_IPV6: - return subnet_compare_ipv6(a, b); - default: - logger(DEBUG_ALWAYS, LOG_ERR, "subnet_compare() was called with unknown subnet type %d, exitting!", a->type); - exit(1); - } - - return 0; -} - -/* Ascii representation of subnets */ - -bool str2net(subnet_t *subnet, const char *subnetstr) { - int i, l; - uint16_t x[8]; - int weight = 10; - - if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d#%d", - &x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) { - if(l < 0 || l > 32) - return false; - - subnet->type = SUBNET_IPV4; - subnet->net.ipv4.prefixlength = l; - subnet->weight = weight; - - for(int i = 0; i < 4; i++) { - if(x[i] > 255) - return false; - subnet->net.ipv4.address.x[i] = x[i]; - } - - return true; - } - - if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d", - &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], - &l, &weight) >= 9) { - if(l < 0 || l > 128) - return false; - - subnet->type = SUBNET_IPV6; - subnet->net.ipv6.prefixlength = l; - subnet->weight = weight; - - for(i = 0; i < 8; i++) - subnet->net.ipv6.address.x[i] = htons(x[i]); - - return true; - } - - if(sscanf(subnetstr, "%hu.%hu.%hu.%hu#%d", &x[0], &x[1], &x[2], &x[3], &weight) >= 4) { - subnet->type = SUBNET_IPV4; - subnet->net.ipv4.prefixlength = 32; - subnet->weight = weight; - - for(i = 0; i < 4; i++) { - if(x[i] > 255) - return false; - subnet->net.ipv4.address.x[i] = x[i]; - } - - return true; - } - - if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx#%d", - &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &weight) >= 8) { - subnet->type = SUBNET_IPV6; - subnet->net.ipv6.prefixlength = 128; - subnet->weight = weight; - - for(i = 0; i < 8; i++) - subnet->net.ipv6.address.x[i] = htons(x[i]); - - return true; - } - - if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx#%d", - &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &weight) >= 6) { - subnet->type = SUBNET_MAC; - subnet->weight = weight; - - for(i = 0; i < 6; i++) - subnet->net.mac.address.x[i] = x[i]; - - return true; - } - - // IPv6 short form - if(strstr(subnetstr, "::")) { - const char *p; - char *q; - int colons = 0; - - // Count number of colons - for(p = subnetstr; *p; p++) - if(*p == ':') - colons++; - - if(colons > 7) - return false; - - // Scan numbers before the double colon - p = subnetstr; - for(i = 0; i < colons; i++) { - if(*p == ':') - break; - x[i] = strtoul(p, &q, 0x10); - if(!q || p == q || *q != ':') - return false; - p = ++q; - } - - p++; - colons -= i; - if(!i) { - p++; - colons--; - } - - if(!*p || *p == '/' || *p == '#') - colons--; - - // Fill in the blanks - for(; i < 8 - colons; i++) - x[i] = 0; - - // Scan the remaining numbers - for(; i < 8; i++) { - x[i] = strtoul(p, &q, 0x10); - if(!q || p == q) - return false; - if(i == 7) { - p = q; - break; - } - if(*q != ':') - return false; - p = ++q; - } - - l = 128; - if(*p == '/') - sscanf(p, "/%d#%d", &l, &weight); - else if(*p == '#') - sscanf(p, "#%d", &weight); - - if(l < 0 || l > 128) - return false; - - subnet->type = SUBNET_IPV6; - subnet->net.ipv6.prefixlength = l; - subnet->weight = weight; - - for(i = 0; i < 8; i++) - subnet->net.ipv6.address.x[i] = htons(x[i]); - - return true; - } - - return false; -} - -bool net2str(char *netstr, int len, const subnet_t *subnet) { - if(!netstr || !subnet) { - logger(DEBUG_ALWAYS, LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!", netstr, subnet); - return false; - } - - switch (subnet->type) { - case SUBNET_MAC: - snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx#%d", - subnet->net.mac.address.x[0], - subnet->net.mac.address.x[1], - subnet->net.mac.address.x[2], - subnet->net.mac.address.x[3], - subnet->net.mac.address.x[4], - subnet->net.mac.address.x[5], - subnet->weight); - break; - - case SUBNET_IPV4: - snprintf(netstr, len, "%hu.%hu.%hu.%hu/%d#%d", - subnet->net.ipv4.address.x[0], - subnet->net.ipv4.address.x[1], - subnet->net.ipv4.address.x[2], - subnet->net.ipv4.address.x[3], - subnet->net.ipv4.prefixlength, - subnet->weight); - break; - - case SUBNET_IPV6: - snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d", - ntohs(subnet->net.ipv6.address.x[0]), - ntohs(subnet->net.ipv6.address.x[1]), - ntohs(subnet->net.ipv6.address.x[2]), - ntohs(subnet->net.ipv6.address.x[3]), - ntohs(subnet->net.ipv6.address.x[4]), - ntohs(subnet->net.ipv6.address.x[5]), - ntohs(subnet->net.ipv6.address.x[6]), - ntohs(subnet->net.ipv6.address.x[7]), - subnet->net.ipv6.prefixlength, - subnet->weight); - break; - - default: - logger(DEBUG_ALWAYS, LOG_ERR, "net2str() was called with unknown subnet type %d, exiting!", subnet->type); - exit(1); - } - - return true; -} -- 2.39.5