diff --git a/src/edge.c b/src/edge.c index ea7ecd3..2346ffc 100644 --- a/src/edge.c +++ b/src/edge.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -21,10 +21,10 @@ /* *************************************************** */ /** maximum length of command line arguments */ -#define MAX_CMDLINE_BUFFER_LENGTH 4096 +#define MAX_CMDLINE_BUFFER_LENGTH 4096 /** maximum length of a line in the configuration file */ -#define MAX_CONFFILE_LINE_LENGTH 1024 +#define MAX_CONFFILE_LINE_LENGTH 1024 /* ***************************************************** */ @@ -35,8 +35,8 @@ #include "network_traffic_filter.h" static cap_value_t cap_values[] = { - //CAP_NET_RAW, /* Use RAW and PACKET sockets */ - CAP_NET_ADMIN /* Needed to performs routes cleanup at exit */ + //CAP_NET_RAW, /* Use RAW and PACKET sockets */ + CAP_NET_ADMIN /* Needed to performs routes cleanup at exit */ }; int num_cap = sizeof(cap_values)/sizeof(cap_value_t); @@ -46,658 +46,664 @@ int num_cap = sizeof(cap_values)/sizeof(cap_value_t); /** Find the address and IP mode for the tuntap device. * - * s is of the form: + * s is of the form: * * ["static"|"dhcp",":"] (|) [/] * - * for example static:192.168.8.5/24 + * for example static:192.168.8.5/24 * * Fill the parts of the string into the fileds, ip_mode only if * present. All strings are NULL terminated. * - * return 0 on success and -1 on error + * return 0 on success and -1 on error */ static int scan_address (char * ip_addr, size_t addr_size, char * netmask, size_t netmask_size, char * ip_mode, size_t mode_size, char * s) { - int retval = -1; - char * start; - char * end; - int bitlen = N2N_EDGE_DEFAULT_CIDR_NM; + int retval = -1; + char * start; + char * end; + int bitlen = N2N_EDGE_DEFAULT_CIDR_NM; - if((NULL == s) || (NULL == ip_addr) || (NULL == netmask)) { - return -1; - } + if((NULL == s) || (NULL == ip_addr) || (NULL == netmask)) { + return -1; + } - memset(ip_addr, 0, addr_size); - memset(netmask, 0, netmask_size); + memset(ip_addr, 0, addr_size); + memset(netmask, 0, netmask_size); - start = s; - end = strpbrk(s, ":"); + start = s; + end = strpbrk(s, ":"); - if(end) { - // colon is present - if(ip_mode) { - memset(ip_mode, 0, mode_size); - strncpy(ip_mode, start, (size_t)MIN(end - start, mode_size - 1)); + if(end) { + // colon is present + if(ip_mode) { + memset(ip_mode, 0, mode_size); + strncpy(ip_mode, start, (size_t)MIN(end - start, mode_size - 1)); + } + start = end + 1; + } else { + // colon is not present } - start = end + 1; - } else { - // colon is not present - } - // start now points to first address character - retval = 0; // we have got an address + // start now points to first address character + retval = 0; // we have got an address - end = strpbrk(start, "/"); + end = strpbrk(start, "/"); - if(!end) - // no slash present -- default end - end = s + strlen(s); + if(!end) + // no slash present -- default end + end = s + strlen(s); - strncpy(ip_addr, start, (size_t)MIN(end - start, addr_size - 1)); // ensure NULL term + strncpy(ip_addr, start, (size_t)MIN(end - start, addr_size - 1)); // ensure NULL term - if(end) { - // slash is present + if(end) { + // slash is present - // now, handle the sub-network address - sscanf(end + 1, "%u", &bitlen); - bitlen = htobe32(bitlen2mask(bitlen)); - inet_ntop(AF_INET, &bitlen, netmask, netmask_size); - } + // now, handle the sub-network address + sscanf(end + 1, "%u", &bitlen); + bitlen = htobe32(bitlen2mask(bitlen)); + inet_ntop(AF_INET, &bitlen, netmask, netmask_size); + } - return retval; + return retval; } /* *************************************************** */ -static void help() { - print_n2n_version(); +static void help () { + print_n2n_version(); - printf("edge (see edge.conf)\n" - "or\n" - ); - printf("edge " + printf("edge (see edge.conf)\n" + "or\n" + ); + printf("edge " #if defined(N2N_CAN_NAME_IFACE) - "-d " + "-d " #endif /* #if defined(N2N_CAN_NAME_IFACE) */ - "-a [static:|dhcp:][/nn] " - "-c " - "[-k ]\n" - " " + "-a [static:|dhcp:][/nn] " + "-c " + "[-k ]\n" + " " #ifndef WIN32 - "[-u -g ]" + "[-u -g ]" #endif /* #ifndef WIN32 */ #ifndef WIN32 - "[-f]" + "[-f]" #endif /* #ifndef WIN32 */ #ifdef __linux__ - "[-T ]" + "[-T ]" #endif - "[-n cidr:gateway] " - "[-m ] " - "-l \n" - " " - "[-p ] [-M ] " + "[-n cidr:gateway] " + "[-m ] " + "-l \n" + " " + "[-p ] [-M ] " #ifndef __APPLE__ - "[-D] " + "[-D] " #endif - "[-r] [-E] [-v] [-i ] [-L ] [-t ] [-A[]] [-H] [-z[]] " - "[-R ] " - "[-h]\n\n"); + "[-r] [-E] [-v] [-i ] [-L ] [-t ] [-A[]] [-H] [-z[]] " + "[-R ] " + "[-h]\n\n"); #if defined(N2N_CAN_NAME_IFACE) - printf("-d | tap device name\n"); + printf("-d | tap device name\n"); #endif - printf("-a [mode:]
[/nn] | Interface address and optional subnet (cidr, default /24). For DHCP use '-r -a dhcp:0.0.0.0'\n"); - printf("-c | n2n community name the edge belongs to.\n"); - printf("-k | Encryption key (ASCII) - also N2N_KEY=.\n"); - printf("-l | Supernode IP:port\n"); - printf("-i | Registration interval, for NAT hole punching (default 20 seconds)\n"); - printf("-I | Annotate the edge's description (hint), identified in the manage port\n"); - printf("-L | TTL for registration packet when UDP NAT hole punching through supernode (default 0 for not set )\n"); - printf("-p | Fixed local UDP port.\n"); + printf("-a [mode:]
[/nn] | Interface address and optional subnet (cidr, default /24). For DHCP use '-r -a dhcp:0.0.0.0'\n"); + printf("-c | n2n community name the edge belongs to.\n"); + printf("-k | Encryption key (ASCII) - also N2N_KEY=.\n"); + printf("-l | Supernode IP:port\n"); + printf("-i | Registration interval, for NAT hole punching (default 20 seconds)\n"); + printf("-I | Annotate the edge's description (hint), identified in the manage port\n"); + printf("-L | TTL for registration packet when UDP NAT hole punching through supernode (default 0 for not set )\n"); + printf("-p | Fixed local UDP port.\n"); #ifndef WIN32 - printf("-u | User ID (numeric) to use when privileges are dropped.\n"); - printf("-g | Group ID (numeric) to use when privileges are dropped.\n"); + printf("-u | User ID (numeric) to use when privileges are dropped.\n"); + printf("-g | Group ID (numeric) to use when privileges are dropped.\n"); #endif /* ifndef WIN32 */ #ifndef WIN32 - printf("-f | Do not fork and run as a daemon; rather run in foreground.\n"); + printf("-f | Do not fork and run as a daemon; rather run in foreground.\n"); #endif /* #ifndef WIN32 */ - printf("-m | Fix MAC address for the TAP interface (otherwise it may be random)\n" - " | eg. -m 01:02:03:04:05:06\n"); - printf("-M | Specify n2n MTU of edge interface (default %d).\n", DEFAULT_MTU); + printf("-m | Fix MAC address for the TAP interface (otherwise it may be random)\n" + " | eg. -m 01:02:03:04:05:06\n"); + printf("-M | Specify n2n MTU of edge interface (default %d).\n", DEFAULT_MTU); #ifndef __APPLE__ - printf("-D | Enable PMTU discovery. PMTU discovery can reduce fragmentation but\n" - " | causes connections stall when not properly supported.\n"); + printf("-D | Enable PMTU discovery. PMTU discovery can reduce fragmentation but\n" + " | causes connections stall when not properly supported.\n"); #endif - printf("-r | Enable packet forwarding through n2n community.\n"); - printf("-A1 | Disable payload encryption. Do not use with key (defaulting to Twofish then).\n"); - printf("-A2 ... -A5 or -A | Choose a cipher for payload encryption, requires a key: -A2 = Twofish (default),\n"); - printf(" | -A3 or -A (deprecated) = AES, " - "-A4 = ChaCha20, " - "-A5 = Speck-CTR.\n"); - printf("-H | Enable full header encryption. Requires supernode with fixed community.\n"); - printf("-z1 ... -z2 or -z | Enable compression for outgoing data packets: -z1 or -z = lzo1x" + printf("-r | Enable packet forwarding through n2n community.\n"); + printf("-A1 | Disable payload encryption. Do not use with key (defaulting to Twofish then).\n"); + printf("-A2 ... -A5 or -A | Choose a cipher for payload encryption, requires a key: -A2 = Twofish (default),\n"); + printf(" | -A3 or -A (deprecated) = AES, " + "-A4 = ChaCha20, " + "-A5 = Speck-CTR.\n"); + printf("-H | Enable full header encryption. Requires supernode with fixed community.\n"); + printf("-z1 ... -z2 or -z | Enable compression for outgoing data packets: -z1 or -z = lzo1x" #ifdef N2N_HAVE_ZSTD - ", -z2 = zstd" + ", -z2 = zstd" #endif - " (default=disabled).\n"); - printf("-E | Accept multicast MAC addresses (default=drop).\n"); - printf("-S | Do not connect P2P. Always use the supernode.\n"); + " (default=disabled).\n"); + printf("-E | Accept multicast MAC addresses (default=drop).\n"); + printf("-S | Do not connect P2P. Always use the supernode.\n"); #ifdef __linux__ - printf("-T | TOS for packets (e.g. 0x48 for SSH like priority)\n"); + printf("-T | TOS for packets (e.g. 0x48 for SSH like priority)\n"); #endif - printf("-n | Route an IPv4 network via the gw. Use 0.0.0.0/0 for the default gw. Can be set multiple times.\n"); - printf("-v | Make more verbose. Repeat as required.\n"); - printf("-R | Drop or accept packets by rules. Can be set multiple times. \n"); - printf(" | Rule format: src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/- \n"); - printf("-t | Management UDP Port (for multiple edges on a machine).\n"); + printf("-n | Route an IPv4 network via the gw. Use 0.0.0.0/0 for the default gw. Can be set multiple times.\n"); + printf("-v | Make more verbose. Repeat as required.\n"); + printf("-R | Drop or accept packets by rules. Can be set multiple times. \n"); + printf(" | Rule format: src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/- \n"); + printf("-t | Management UDP Port (for multiple edges on a machine).\n"); - printf("\nEnvironment variables:\n"); - printf(" N2N_KEY | Encryption key (ASCII). Not with -k.\n"); + printf("\nEnvironment variables:\n"); + printf(" N2N_KEY | Encryption key (ASCII). Not with -k.\n"); #ifdef WIN32 - printf("\nAvailable TAP adapters:\n"); - win_print_available_adapters(); + printf("\nAvailable TAP adapters:\n"); + win_print_available_adapters(); #endif - exit(0); + exit(0); } /* *************************************************** */ static void setPayloadCompression (n2n_edge_conf_t *conf, int compression) { - /* even though 'compression' and 'conf->compression' share the same encoding scheme, - * a switch-statement under conditional compilation is used to sort out the - * unsupported optarguments */ - switch (compression) { - case 1: { - conf->compression = N2N_COMPRESSION_ID_LZO; - break; - } + + /* even though 'compression' and 'conf->compression' share the same encoding scheme, + * a switch-statement under conditional compilation is used to sort out the + * unsupported optarguments */ + switch (compression) { + case 1: { + conf->compression = N2N_COMPRESSION_ID_LZO; + break; + } #ifdef N2N_HAVE_ZSTD - case 2: { - conf->compression = N2N_COMPRESSION_ID_ZSTD; - break; - } + case 2: { + conf->compression = N2N_COMPRESSION_ID_ZSTD; + break; + } #endif - default: { - conf->compression = N2N_COMPRESSION_ID_NONE; - // internal comrpession scheme numbering differs from cli counting by one, hence plus one - // (internal: 0 == invalid, 1 == none, 2 == lzo, 3 == zstd) - traceEvent(TRACE_NORMAL, "the %s compression given by -z_ option is not supported in this version.", compression_str(compression + 1)); - exit(1); // to make the user aware + default: { + conf->compression = N2N_COMPRESSION_ID_NONE; + // internal comrpession scheme numbering differs from cli counting by one, hence plus one + // (internal: 0 == invalid, 1 == none, 2 == lzo, 3 == zstd) + traceEvent(TRACE_NORMAL, "the %s compression given by -z_ option is not supported in this version.", compression_str(compression + 1)); + exit(1); // to make the user aware + } } - } } /* *************************************************** */ static void setPayloadEncryption (n2n_edge_conf_t *conf, int cipher) { - /* even though 'cipher' and 'conf->transop_id' share the same encoding scheme, - * a switch-statement under conditional compilation is used to sort out the - * unsupported ciphers */ - switch (cipher) { - case 1: { - conf->transop_id = N2N_TRANSFORM_ID_NULL; - break; - } - case 2: { - conf->transop_id = N2N_TRANSFORM_ID_TWOFISH; - break; - } + /* even though 'cipher' and 'conf->transop_id' share the same encoding scheme, + * a switch-statement under conditional compilation is used to sort out the + * unsupported ciphers */ + switch (cipher) { + case 1: { + conf->transop_id = N2N_TRANSFORM_ID_NULL; + break; + } - case 3: { - conf->transop_id = N2N_TRANSFORM_ID_AES; - break; - } + case 2: { + conf->transop_id = N2N_TRANSFORM_ID_TWOFISH; + break; + } - case 4: { - conf->transop_id = N2N_TRANSFORM_ID_CHACHA20; - break; - } + case 3: { + conf->transop_id = N2N_TRANSFORM_ID_AES; + break; + } - case 5: { - conf->transop_id = N2N_TRANSFORM_ID_SPECK; - break; - } + case 4: { + conf->transop_id = N2N_TRANSFORM_ID_CHACHA20; + break; + } - default: { - conf->transop_id = N2N_TRANSFORM_ID_INVAL; - traceEvent(TRACE_NORMAL, "the %s cipher given by -A_ option is not supported in this version.", transop_str(cipher)); - exit(1); + case 5: { + conf->transop_id = N2N_TRANSFORM_ID_SPECK; + break; + } + + default: { + conf->transop_id = N2N_TRANSFORM_ID_INVAL; + traceEvent(TRACE_NORMAL, "the %s cipher given by -A_ option is not supported in this version.", transop_str(cipher)); + exit(1); + } } - } } /* *************************************************** */ static int setOption (int optkey, char *optargument, n2n_tuntap_priv_config_t *ec, n2n_edge_conf_t *conf) { - /* traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, optargument ? optargument : ""); */ - - switch(optkey) { - case 'a': /* IP address and mode of TUNTAP interface */ { - scan_address(ec->ip_addr, N2N_NETMASK_STR_SIZE, - ec->netmask, N2N_NETMASK_STR_SIZE, - ec->ip_mode, N2N_IF_MODE_SIZE, - optargument); - break; - } - case 'c': /* community as a string */ { - memset(conf->community_name, 0, N2N_COMMUNITY_SIZE); - strncpy((char *)conf->community_name, optargument, N2N_COMMUNITY_SIZE); - conf->community_name[N2N_COMMUNITY_SIZE - 1] = '\0'; - break; - } + /* traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, optargument ? optargument : ""); */ - case 'E': /* multicast ethernet addresses accepted. */ { - conf->drop_multicast = 0; - traceEvent(TRACE_DEBUG, "Enabling ethernet multicast traffic"); - break; - } + switch(optkey) { + case 'a': /* IP address and mode of TUNTAP interface */ { + scan_address(ec->ip_addr, N2N_NETMASK_STR_SIZE, + ec->netmask, N2N_NETMASK_STR_SIZE, + ec->ip_mode, N2N_IF_MODE_SIZE, + optargument); + break; + } + + case 'c': /* community as a string */ { + memset(conf->community_name, 0, N2N_COMMUNITY_SIZE); + strncpy((char *)conf->community_name, optargument, N2N_COMMUNITY_SIZE); + conf->community_name[N2N_COMMUNITY_SIZE - 1] = '\0'; + break; + } + + case 'E': /* multicast ethernet addresses accepted. */ { + conf->drop_multicast = 0; + traceEvent(TRACE_DEBUG, "Enabling ethernet multicast traffic"); + break; + } #ifndef WIN32 - case 'u': /* unprivileged uid */ { - ec->userid = atoi(optargument); - break; - } + case 'u': /* unprivileged uid */ { + ec->userid = atoi(optargument); + break; + } - case 'g': /* unprivileged uid */ { - ec->groupid = atoi(optargument); - break; - } + case 'g': /* unprivileged uid */ { + ec->groupid = atoi(optargument); + break; + } #endif #ifndef WIN32 - case 'f' : /* do not fork as daemon */ { - ec->daemon = 0; - break; - } + case 'f' : /* do not fork as daemon */ { + ec->daemon = 0; + break; + } #endif /* #ifndef WIN32 */ - case 'm' : /* TUNTAP MAC address */ { - strncpy(ec->device_mac, optargument, N2N_MACNAMSIZ); - ec->device_mac[N2N_MACNAMSIZ - 1] = '\0'; - break; - } + case 'm' : /* TUNTAP MAC address */ { + strncpy(ec->device_mac, optargument, N2N_MACNAMSIZ); + ec->device_mac[N2N_MACNAMSIZ - 1] = '\0'; + break; + } - case 'M' : /* TUNTAP MTU */ { - ec->mtu = atoi(optargument); - break; - } + case 'M' : /* TUNTAP MTU */ { + ec->mtu = atoi(optargument); + break; + } #ifndef __APPLE__ - case 'D' : /* enable PMTU discovery */ { - conf->disable_pmtu_discovery = 0; - break; - } + case 'D' : /* enable PMTU discovery */ { + conf->disable_pmtu_discovery = 0; + break; + } #endif - case 'k': /* encrypt key */ { - if(conf->encrypt_key) free(conf->encrypt_key); - conf->encrypt_key = strdup(optargument); - traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", conf->encrypt_key); - break; - } - - case 'r': /* enable packet routing across n2n endpoints */ { - conf->allow_routing = 1; - break; - } + case 'k': /* encrypt key */ { + if(conf->encrypt_key) free(conf->encrypt_key); + conf->encrypt_key = strdup(optargument); + traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", conf->encrypt_key); + break; + } - case 'A': { - int cipher; + case 'r': /* enable packet routing across n2n endpoints */ { + conf->allow_routing = 1; + break; + } - if(optargument) { - cipher = atoi(optargument); - } else { - traceEvent(TRACE_NORMAL, "the use of the solitary -A switch is deprecated and might not be supported in future versions. " - "please use -A3 instead to choose a the AES cipher for payload encryption."); + case 'A': { + int cipher; - cipher = N2N_TRANSFORM_ID_AES; // default, if '-A' only - } + if(optargument) { + cipher = atoi(optargument); + } else { + traceEvent(TRACE_NORMAL, "the use of the solitary -A switch is deprecated and might not be supported in future versions. " + "please use -A3 instead to choose a the AES cipher for payload encryption."); - setPayloadEncryption(conf, cipher); - break; - } + cipher = N2N_TRANSFORM_ID_AES; // default, if '-A' only + } - case 'H': /* indicate header encryption */ { - /* we cannot be sure if this gets parsed before the community name is set. - * so, only an indicator is set, action is taken later*/ - conf->header_encryption = HEADER_ENCRYPTION_ENABLED; - break; - } + setPayloadEncryption(conf, cipher); + break; + } - case 'z': { - int compression; + case 'H': /* indicate header encryption */ { + /* we cannot be sure if this gets parsed before the community name is set. + * so, only an indicator is set, action is taken later*/ + conf->header_encryption = HEADER_ENCRYPTION_ENABLED; + break; + } - if(optargument) { - compression = atoi(optargument); - } else - compression = 1; // default, if '-z' only, equals -z1 + case 'z': { + int compression; - setPayloadCompression(conf, compression); - break; - } + if(optargument) { + compression = atoi(optargument); + } else + compression = 1; // default, if '-z' only, equals -z1 - case 'l': /* supernode-list */ - if(optargument) { - if(edge_conf_add_supernode(conf, optargument) != 0) { - traceEvent(TRACE_WARNING, "Too many supernodes!"); - exit(1); + setPayloadCompression(conf, compression); + break; } - break; - } - case 'i': /* supernode registration interval */ - conf->register_interval = atoi(optargument); - break; + case 'l': /* supernode-list */ + if(optargument) { + if(edge_conf_add_supernode(conf, optargument) != 0) { + traceEvent(TRACE_WARNING, "Too many supernodes!"); + exit(1); + } + break; + } - case 'L': /* supernode registration interval */ - conf->register_ttl = atoi(optarg); - break; + case 'i': /* supernode registration interval */ + conf->register_interval = atoi(optargument); + break; + + case 'L': /* supernode registration interval */ + conf->register_ttl = atoi(optarg); + break; #if defined(N2N_CAN_NAME_IFACE) - case 'd': /* TUNTAP name */ { - strncpy(ec->tuntap_dev_name, optargument, N2N_IFNAMSIZ); - ec->tuntap_dev_name[N2N_IFNAMSIZ - 1] = '\0'; - break; - } + case 'd': /* TUNTAP name */ { + strncpy(ec->tuntap_dev_name, optargument, N2N_IFNAMSIZ); + ec->tuntap_dev_name[N2N_IFNAMSIZ - 1] = '\0'; + break; + } #endif - case 'I': /* Device Description (hint) */ { - memset(conf->dev_desc, 0, N2N_DESC_SIZE); - /* reserve possible last char as null terminator. */ - strncpy((char *)conf->dev_desc, optargument, N2N_DESC_SIZE-1); - break; - } + case 'I': /* Device Description (hint) */ { + memset(conf->dev_desc, 0, N2N_DESC_SIZE); + /* reserve possible last char as null terminator. */ + strncpy((char *)conf->dev_desc, optargument, N2N_DESC_SIZE-1); + break; + } - case 'p': { - conf->local_port = atoi(optargument); + case 'p': { + conf->local_port = atoi(optargument); - if(conf->local_port == 0) { - traceEvent(TRACE_WARNING, "Bad local port format"); - break; - } + if(conf->local_port == 0) { + traceEvent(TRACE_WARNING, "Bad local port format"); + break; + } - break; - } + break; + } - case 't': { - conf->mgmt_port = atoi(optargument); - break; - } + case 't': { + conf->mgmt_port = atoi(optargument); + break; + } #ifdef __linux__ - case 'T': { - if((optargument[0] == '0') && (optargument[1] == 'x')) - conf->tos = strtol(&optargument[2], NULL, 16); - else - conf->tos = atoi(optargument); + case 'T': { + if((optargument[0] == '0') && (optargument[1] == 'x')) + conf->tos = strtol(&optargument[2], NULL, 16); + else + conf->tos = atoi(optargument); - break; - } + break; + } #endif - case 'n': { - char cidr_net[64], gateway[64]; - n2n_route_t route; + case 'n': { + char cidr_net[64], gateway[64]; + n2n_route_t route; - if(sscanf(optargument, "%63[^/]/%hhd:%63s", cidr_net, &route.net_bitlen, gateway) != 3) { - traceEvent(TRACE_WARNING, "Bad cidr/gateway format '%d'. See -h.", optargument); - break; - } + if(sscanf(optargument, "%63[^/]/%hhd:%63s", cidr_net, &route.net_bitlen, gateway) != 3) { + traceEvent(TRACE_WARNING, "Bad cidr/gateway format '%d'. See -h.", optargument); + break; + } - route.net_addr = inet_addr(cidr_net); - route.gateway = inet_addr(gateway); + route.net_addr = inet_addr(cidr_net); + route.gateway = inet_addr(gateway); - if((route.net_bitlen < 0) || (route.net_bitlen > 32)) { - traceEvent(TRACE_WARNING, "Bad prefix '%d' in '%s'", route.net_bitlen, optargument); - break; - } + if((route.net_bitlen < 0) || (route.net_bitlen > 32)) { + traceEvent(TRACE_WARNING, "Bad prefix '%d' in '%s'", route.net_bitlen, optargument); + break; + } - if(route.net_addr == INADDR_NONE) { - traceEvent(TRACE_WARNING, "Bad network '%s' in '%s'", cidr_net, optargument); - break; - } + if(route.net_addr == INADDR_NONE) { + traceEvent(TRACE_WARNING, "Bad network '%s' in '%s'", cidr_net, optargument); + break; + } - if(route.gateway == INADDR_NONE) { - traceEvent(TRACE_WARNING, "Bad gateway '%s' in '%s'", gateway, optargument); - break; - } + if(route.gateway == INADDR_NONE) { + traceEvent(TRACE_WARNING, "Bad gateway '%s' in '%s'", gateway, optargument); + break; + } - traceEvent(TRACE_DEBUG, "Adding %s/%d via %s", cidr_net, route.net_bitlen, gateway); + traceEvent(TRACE_DEBUG, "Adding %s/%d via %s", cidr_net, route.net_bitlen, gateway); - conf->routes = realloc(conf->routes, sizeof(struct n2n_route) * (conf->num_routes + 1)); - conf->routes[conf->num_routes] = route; - conf->num_routes++; + conf->routes = realloc(conf->routes, sizeof(struct n2n_route) * (conf->num_routes + 1)); + conf->routes[conf->num_routes] = route; + conf->num_routes++; - break; - } + break; + } - case 'S': { - conf->allow_p2p = 0; - break; - } + case 'S': { + conf->allow_p2p = 0; + break; + } - case 'h': /* help */ { - help(); - break; - } + case 'h': /* help */ { + help(); + break; + } - case 'v': /* verbose */ - setTraceLevel(getTraceLevel() + 1); - break; - - case 'R': /* network traffic filter */ { - filter_rule_t *new_rule = malloc(sizeof(filter_rule_t)); - memset(new_rule, 0, sizeof(filter_rule_t)); - - if(process_traffic_filter_rule_str(optargument, new_rule)) { - HASH_ADD(hh, conf->network_traffic_filter_rules, key, sizeof(filter_rule_key_t), new_rule); - } else { - free(new_rule); - traceEvent(TRACE_WARNING, "Invalid filter rule: %s", optargument); - return(-1); - } - break; - } + case 'v': /* verbose */ + setTraceLevel(getTraceLevel() + 1); + break; + + case 'R': /* network traffic filter */ { + filter_rule_t *new_rule = malloc(sizeof(filter_rule_t)); + memset(new_rule, 0, sizeof(filter_rule_t)); + + if(process_traffic_filter_rule_str(optargument, new_rule)) { + HASH_ADD(hh, conf->network_traffic_filter_rules, key, sizeof(filter_rule_key_t), new_rule); + } else { + free(new_rule); + traceEvent(TRACE_WARNING, "Invalid filter rule: %s", optargument); + return(-1); + } + break; + } - default: { - traceEvent(TRACE_WARNING, "Unknown option -%c: Ignored", (char)optkey); - return(-1); + default: { + traceEvent(TRACE_WARNING, "Unknown option -%c: Ignored", (char)optkey); + return(-1); + } } - } - return(0); + return(0); } /* *********************************************** */ static const struct option long_options[] = - { - { "community", required_argument, NULL, 'c' }, - { "supernode-list", required_argument, NULL, 'l' }, - { "tap-device", required_argument, NULL, 'd' }, - { "euid", required_argument, NULL, 'u' }, - { "egid", required_argument, NULL, 'g' }, - { "help" , no_argument, NULL, 'h' }, - { "verbose", no_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } - }; + { + { "community", required_argument, NULL, 'c' }, + { "supernode-list", required_argument, NULL, 'l' }, + { "tap-device", required_argument, NULL, 'd' }, + { "euid", required_argument, NULL, 'u' }, + { "egid", required_argument, NULL, 'g' }, + { "help" , no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 } + }; /* *************************************************** */ /* read command line options */ static int loadFromCLI (int argc, char *argv[], n2n_edge_conf_t *conf, n2n_tuntap_priv_config_t *ec) { - u_char c; - while ((c = getopt_long(argc, argv, - "k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:I:SDL:z::A::Hn:R:" + u_char c; + + while ((c = getopt_long(argc, argv, + "k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:I:SDL:z::A::Hn:R:" #ifdef __linux__ - "T:" + "T:" #endif - , - long_options, NULL)) != '?') { - if(c == 255) break; - setOption(c, optarg, ec, conf); - } + , + long_options, NULL)) != '?') { + if(c == 255) break; + setOption(c, optarg, ec, conf); + } - return 0; + return 0; } /* *************************************************** */ static char *trim (char *s) { - char *end; - while(isspace(s[0]) || (s[0] == '"') || (s[0] == '\'')) s++; - if(s[0] == 0) return s; + char *end; + + while(isspace(s[0]) || (s[0] == '"') || (s[0] == '\'')) s++; + if(s[0] == 0) return s; - end = &s[strlen(s) - 1]; - while(end > s - && (isspace(end[0])|| (end[0] == '"') || (end[0] == '\''))) - end--; - end[1] = 0; + end = &s[strlen(s) - 1]; + while(end > s + && (isspace(end[0])|| (end[0] == '"') || (end[0] == '\''))) + end--; + end[1] = 0; - return s; + return s; } /* *************************************************** */ /* parse the configuration file */ static int loadFromFile (const char *path, n2n_edge_conf_t *conf, n2n_tuntap_priv_config_t *ec) { - char buffer[4096], *line, *key, *value; - u_int line_len, opt_name_len; - FILE *fd; - const struct option *opt; - fd = fopen(path, "r"); + char buffer[4096], *line, *key, *value; + u_int line_len, opt_name_len; + FILE *fd; + const struct option *opt; - if(fd == NULL) { - traceEvent(TRACE_WARNING, "Config file %s not found", path); - return -1; - } + fd = fopen(path, "r"); - while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { - line = trim(line); - value = NULL; - - if((line_len = strlen(line)) < 2 || line[0] == '#') - continue; - - if(!strncmp(line, "--", 2)) { /* long opt */ - key = &line[2], line_len -= 2; - - opt = long_options; - while(opt->name != NULL) { - opt_name_len = strlen(opt->name); - - if(!strncmp(key, opt->name, opt_name_len) - && (line_len <= opt_name_len - || key[opt_name_len] == '\0' - || key[opt_name_len] == ' ' - || key[opt_name_len] == '=')) { - if(line_len > opt_name_len) key[opt_name_len] = '\0'; - if(line_len > opt_name_len + 1) value = trim(&key[opt_name_len + 1]); - - // traceEvent(TRACE_NORMAL, "long key: %s value: %s", key, value); - setOption(opt->val, value, ec, conf); - break; - } - - opt++; - } - } else if(line[0] == '-') { /* short opt */ - char *equal; - - key = &line[1], line_len--; - - equal = strchr(line, '='); - - if(equal) { - equal[0] = '\0'; - value = &equal[1]; + if(fd == NULL) { + traceEvent(TRACE_WARNING, "Config file %s not found", path); + return -1; + } - if((value[0] == '\0') && (key[1] != '\0')) - value = &key[1]; - } else { + while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { + line = trim(line); value = NULL; - /* Adding an exception for -A_ -z_ which can come - without '=' and even without any further data */ - - if(key[0] == 'z') { - if(key[1]) value = &key[1]; - key = "z"; - } else if(key[0] == 'A') { - if(key[1]) value = &key[1]; - key = "A"; + if((line_len = strlen(line)) < 2 || line[0] == '#') + continue; + + if(!strncmp(line, "--", 2)) { /* long opt */ + key = &line[2], line_len -= 2; + + opt = long_options; + while(opt->name != NULL) { + opt_name_len = strlen(opt->name); + + if(!strncmp(key, opt->name, opt_name_len) + && (line_len <= opt_name_len + || key[opt_name_len] == '\0' + || key[opt_name_len] == ' ' + || key[opt_name_len] == '=')) { + if(line_len > opt_name_len) key[opt_name_len] = '\0'; + if(line_len > opt_name_len + 1) value = trim(&key[opt_name_len + 1]); + + // traceEvent(TRACE_NORMAL, "long key: %s value: %s", key, value); + setOption(opt->val, value, ec, conf); + break; + } + + opt++; + } + } else if(line[0] == '-') { /* short opt */ + char *equal; + + key = &line[1], line_len--; + + equal = strchr(line, '='); + + if(equal) { + equal[0] = '\0'; + value = &equal[1]; + + if((value[0] == '\0') && (key[1] != '\0')) + value = &key[1]; + } else { + value = NULL; + + /* Adding an exception for -A_ -z_ which can come + without '=' and even without any further data */ + + if(key[0] == 'z') { + if(key[1]) value = &key[1]; + key = "z"; + } else if(key[0] == 'A') { + if(key[1]) value = &key[1]; + key = "A"; + } + } + // traceEvent(TRACE_NORMAL, "key: %c value: %s", key[0], value); + setOption(key[0], value, ec, conf); + } else { + traceEvent(TRACE_WARNING, "Skipping unrecognized line: %s", line); + continue; } - } - // traceEvent(TRACE_NORMAL, "key: %c value: %s", key[0], value); - setOption(key[0], value, ec, conf); - } else { - traceEvent(TRACE_WARNING, "Skipping unrecognized line: %s", line); - continue; } - } - fclose(fd); + fclose(fd); - return 0; + return 0; } /* ************************************** */ static void daemonize () { #ifndef WIN32 - int childpid; - - traceEvent(TRACE_NORMAL, "Parent process is exiting (this is normal)"); - - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, SIG_IGN); - signal(SIGCHLD, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - - if((childpid = fork()) < 0) - traceEvent(TRACE_ERROR, "Occurred while daemonizing (errno=%d)", - errno); - else { - if(!childpid) { /* child */ - int rc; - - //traceEvent(TRACE_NORMAL, "Bye bye: I'm becoming a daemon..."); - rc = chdir("/"); - if(rc != 0) - traceEvent(TRACE_ERROR, "Error while moving to / directory"); - - setsid(); /* detach from the terminal */ - - fclose(stdin); - fclose(stdout); - /* fclose(stderr); */ - - /* - * clear any inherited file mode creation mask - */ - //umask(0); - - /* - * Use line buffered stdout - */ - /* setlinebuf (stdout); */ - setvbuf(stdout, (char *)NULL, _IOLBF, 0); - } else /* father */ - exit(0); - } + int childpid; + + traceEvent(TRACE_NORMAL, "Parent process is exiting (this is normal)"); + + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + + if((childpid = fork()) < 0) + traceEvent(TRACE_ERROR, "Occurred while daemonizing (errno=%d)", + errno); + else { + if(!childpid) { /* child */ + int rc; + + //traceEvent(TRACE_NORMAL, "Bye bye: I'm becoming a daemon..."); + rc = chdir("/"); + if(rc != 0) + traceEvent(TRACE_ERROR, "Error while moving to / directory"); + + setsid(); /* detach from the terminal */ + + fclose(stdin); + fclose(stdout); + /* fclose(stderr); */ + + /* + * clear any inherited file mode creation mask + */ + //umask(0); + + /* + * Use line buffered stdout + */ + /* setlinebuf (stdout); */ + setvbuf(stdout, (char *)NULL, _IOLBF, 0); + } else /* father */ + exit(0); + } #endif } @@ -709,22 +715,22 @@ static int keep_on_running; #ifdef WIN32 BOOL WINAPI term_handler(DWORD sig) #else - static void term_handler(int sig) + static void term_handler(int sig) #endif { - static int called = 0; + static int called = 0; - if(called) { - traceEvent(TRACE_NORMAL, "Ok I am leaving now"); - _exit(0); - } else { - traceEvent(TRACE_NORMAL, "Shutting down..."); - called = 1; - } + if(called) { + traceEvent(TRACE_NORMAL, "Ok I am leaving now"); + _exit(0); + } else { + traceEvent(TRACE_NORMAL, "Shutting down..."); + called = 1; + } - keep_on_running = 0; + keep_on_running = 0; #ifdef WIN32 - return(TRUE); + return(TRUE); #endif } #endif /* defined(__linux__) || defined(WIN32) */ @@ -733,209 +739,210 @@ BOOL WINAPI term_handler(DWORD sig) /** Entry point to program from kernel. */ int main (int argc, char* argv[]) { - int rc; - tuntap_dev tuntap; /* a tuntap device */ - n2n_edge_t *eee; /* single instance for this program */ - n2n_edge_conf_t conf; /* generic N2N edge config */ - n2n_tuntap_priv_config_t ec; /* config used for standalone program execution */ + + int rc; + tuntap_dev tuntap; /* a tuntap device */ + n2n_edge_t *eee; /* single instance for this program */ + n2n_edge_conf_t conf; /* generic N2N edge config */ + n2n_tuntap_priv_config_t ec; /* config used for standalone program execution */ #ifndef WIN32 - struct passwd *pw = NULL; + struct passwd *pw = NULL; #endif #ifdef HAVE_LIBCAP - cap_t caps; + cap_t caps; #endif #ifdef WIN32 - initWin32(); + initWin32(); #endif - /* Defaults */ - edge_init_conf_defaults(&conf); - memset(&ec, 0, sizeof(ec)); - ec.mtu = DEFAULT_MTU; - ec.daemon = 1; /* By default run in daemon mode. */ + /* Defaults */ + edge_init_conf_defaults(&conf); + memset(&ec, 0, sizeof(ec)); + ec.mtu = DEFAULT_MTU; + ec.daemon = 1; /* By default run in daemon mode. */ #ifndef WIN32 - if(((pw = getpwnam("n2n")) != NULL) || - ((pw = getpwnam("nobody")) != NULL)) { - ec.userid = pw->pw_uid; - ec.groupid = pw->pw_gid; - } + if(((pw = getpwnam("n2n")) != NULL) || + ((pw = getpwnam("nobody")) != NULL)) { + ec.userid = pw->pw_uid; + ec.groupid = pw->pw_gid; + } #endif #ifdef WIN32 - ec.tuntap_dev_name[0] = '\0'; + ec.tuntap_dev_name[0] = '\0'; #else - snprintf(ec.tuntap_dev_name, sizeof(ec.tuntap_dev_name), N2N_EDGE_DEFAULT_DEV_NAME); + snprintf(ec.tuntap_dev_name, sizeof(ec.tuntap_dev_name), N2N_EDGE_DEFAULT_DEV_NAME); #endif - snprintf(ec.netmask, sizeof(ec.netmask), N2N_EDGE_DEFAULT_NETMASK); - - if((argc >= 2) && (argv[1][0] != '-')) { - rc = loadFromFile(argv[1], &conf, &ec); - if(argc > 2) - rc = loadFromCLI(argc, argv, &conf, &ec); - } else if(argc > 1) - rc = loadFromCLI(argc, argv, &conf, &ec); - else + snprintf(ec.netmask, sizeof(ec.netmask), N2N_EDGE_DEFAULT_NETMASK); + + if((argc >= 2) && (argv[1][0] != '-')) { + rc = loadFromFile(argv[1], &conf, &ec); + if(argc > 2) + rc = loadFromCLI(argc, argv, &conf, &ec); + } else if(argc > 1) + rc = loadFromCLI(argc, argv, &conf, &ec); + else #ifdef WIN32 - /* Load from current directory */ - rc = loadFromFile("edge.conf", &conf, &ec); + /* Load from current directory */ + rc = loadFromFile("edge.conf", &conf, &ec); #else - rc = -1; + rc = -1; #endif - if(conf.transop_id == N2N_TRANSFORM_ID_NULL) { - if(conf.encrypt_key) { - /* make sure that Twofish is default cipher if key only (and no cipher) is specified */ - traceEvent(TRACE_WARNING, "Switching to Twofish as key was provided."); - conf.transop_id = N2N_TRANSFORM_ID_TWOFISH; + if(conf.transop_id == N2N_TRANSFORM_ID_NULL) { + if(conf.encrypt_key) { + /* make sure that Twofish is default cipher if key only (and no cipher) is specified */ + traceEvent(TRACE_WARNING, "Switching to Twofish as key was provided."); + conf.transop_id = N2N_TRANSFORM_ID_TWOFISH; + } } - } - if(rc < 0) - help(); + if(rc < 0) + help(); - if(edge_verify_conf(&conf) != 0) - help(); + if(edge_verify_conf(&conf) != 0) + help(); - traceEvent(TRACE_NORMAL, "Starting n2n edge %s %s", PACKAGE_VERSION, PACKAGE_BUILDDATE); + traceEvent(TRACE_NORMAL, "Starting n2n edge %s %s", PACKAGE_VERSION, PACKAGE_BUILDDATE); #if defined(HAVE_OPENSSL_1_1) - traceEvent(TRACE_NORMAL, "Using %s", OpenSSL_version(0)); + traceEvent(TRACE_NORMAL, "Using %s", OpenSSL_version(0)); #endif - traceEvent(TRACE_NORMAL, "Using compression: %s.", compression_str(conf.compression)); - traceEvent(TRACE_NORMAL, "Using %s cipher.", transop_str(conf.transop_id)); + traceEvent(TRACE_NORMAL, "Using compression: %s.", compression_str(conf.compression)); + traceEvent(TRACE_NORMAL, "Using %s cipher.", transop_str(conf.transop_id)); - /* Random seed */ - n2n_srand (n2n_seed()); + /* Random seed */ + n2n_srand (n2n_seed()); #ifndef WIN32 - /* If running suid root then we need to setuid before using the force. */ - if(setuid(0) != 0) - traceEvent(TRACE_ERROR, "Unable to become root [%u/%s]", errno, strerror(errno)); - /* setgid(0); */ + /* If running suid root then we need to setuid before using the force. */ + if(setuid(0) != 0) + traceEvent(TRACE_ERROR, "Unable to become root [%u/%s]", errno, strerror(errno)); + /* setgid(0); */ #endif - if(conf.encrypt_key && !strcmp((char*)conf.community_name, conf.encrypt_key)) - traceEvent(TRACE_WARNING, "Community and encryption key must differ, otherwise security will be compromised"); - - if((eee = edge_init(&conf, &rc)) == NULL) { - traceEvent(TRACE_ERROR, "Failed in edge_init"); - exit(1); - } - memcpy(&(eee->tuntap_priv_conf), &ec, sizeof(ec)); - - if((0 == strcmp("static", eee->tuntap_priv_conf.ip_mode)) || - ((eee->tuntap_priv_conf.ip_mode[0] == '\0') && (eee->tuntap_priv_conf.ip_addr[0] != '\0'))) { - traceEvent(TRACE_NORMAL, "Use manually set IP address."); - eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_STATIC; - } else if(0 == strcmp("dhcp", eee->tuntap_priv_conf.ip_mode)) { - traceEvent(TRACE_NORMAL, "Obtain IP from other edge DHCP services."); - eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_DHCP; - } else { - traceEvent(TRACE_NORMAL, "Automatically assign IP address by supernode."); - eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; - do { - fd_set socket_mask; - struct timeval wait_time; - - update_supernode_reg(eee, time(NULL)); - FD_ZERO(&socket_mask); - FD_SET(eee->udp_sock, &socket_mask); - wait_time.tv_sec = SOCKET_TIMEOUT_INTERVAL_SECS; - wait_time.tv_usec = 0; - - if(select(eee->udp_sock + 1, &socket_mask, NULL, NULL, &wait_time) > 0) { - if(FD_ISSET(eee->udp_sock, &socket_mask)) { - readFromIPSocket(eee, eee->udp_sock); - } - } - } while(eee->sn_wait); - eee->last_register_req = 0; - } - - if(tuntap_open(&tuntap, eee->tuntap_priv_conf.tuntap_dev_name, eee->tuntap_priv_conf.ip_mode, - eee->tuntap_priv_conf.ip_addr, eee->tuntap_priv_conf.netmask, - eee->tuntap_priv_conf.device_mac, eee->tuntap_priv_conf.mtu) < 0) exit(1); - traceEvent(TRACE_NORMAL, "Local tap IP: %s, Mask: %s", - eee->tuntap_priv_conf.ip_addr, eee->tuntap_priv_conf.netmask); - memcpy(&eee->device, &tuntap, sizeof(tuntap)); - // hexdump((unsigned char*)&tuntap,sizeof(tuntap_dev)); + if(conf.encrypt_key && !strcmp((char*)conf.community_name, conf.encrypt_key)) + traceEvent(TRACE_WARNING, "Community and encryption key must differ, otherwise security will be compromised"); + + if((eee = edge_init(&conf, &rc)) == NULL) { + traceEvent(TRACE_ERROR, "Failed in edge_init"); + exit(1); + } + memcpy(&(eee->tuntap_priv_conf), &ec, sizeof(ec)); + + if((0 == strcmp("static", eee->tuntap_priv_conf.ip_mode)) || + ((eee->tuntap_priv_conf.ip_mode[0] == '\0') && (eee->tuntap_priv_conf.ip_addr[0] != '\0'))) { + traceEvent(TRACE_NORMAL, "Use manually set IP address."); + eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_STATIC; + } else if(0 == strcmp("dhcp", eee->tuntap_priv_conf.ip_mode)) { + traceEvent(TRACE_NORMAL, "Obtain IP from other edge DHCP services."); + eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_DHCP; + } else { + traceEvent(TRACE_NORMAL, "Automatically assign IP address by supernode."); + eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; + do { + fd_set socket_mask; + struct timeval wait_time; + + update_supernode_reg(eee, time(NULL)); + FD_ZERO(&socket_mask); + FD_SET(eee->udp_sock, &socket_mask); + wait_time.tv_sec = SOCKET_TIMEOUT_INTERVAL_SECS; + wait_time.tv_usec = 0; + + if(select(eee->udp_sock + 1, &socket_mask, NULL, NULL, &wait_time) > 0) { + if(FD_ISSET(eee->udp_sock, &socket_mask)) { + readFromIPSocket(eee, eee->udp_sock); + } + } + } while(eee->sn_wait); + eee->last_register_req = 0; + } + + if(tuntap_open(&tuntap, eee->tuntap_priv_conf.tuntap_dev_name, eee->tuntap_priv_conf.ip_mode, + eee->tuntap_priv_conf.ip_addr, eee->tuntap_priv_conf.netmask, + eee->tuntap_priv_conf.device_mac, eee->tuntap_priv_conf.mtu) < 0) exit(1); + traceEvent(TRACE_NORMAL, "Local tap IP: %s, Mask: %s", + eee->tuntap_priv_conf.ip_addr, eee->tuntap_priv_conf.netmask); + memcpy(&eee->device, &tuntap, sizeof(tuntap)); + //hexdump((unsigned char*)&tuntap,sizeof(tuntap_dev)); #ifndef WIN32 - if(eee->tuntap_priv_conf.daemon) { - setUseSyslog(1); /* traceEvent output now goes to syslog. */ - daemonize(); - } + if(eee->tuntap_priv_conf.daemon) { + setUseSyslog(1); /* traceEvent output now goes to syslog. */ + daemonize(); + } #endif /* #ifndef WIN32 */ #ifndef WIN32 #ifdef HAVE_LIBCAP - /* Before dropping the privileges, retain capabilities to regain them in future. */ - caps = cap_get_proc(); + /* Before dropping the privileges, retain capabilities to regain them in future. */ + caps = cap_get_proc(); - cap_set_flag(caps, CAP_PERMITTED, num_cap, cap_values, CAP_SET); - cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET); + cap_set_flag(caps, CAP_PERMITTED, num_cap, cap_values, CAP_SET); + cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET); - if((cap_set_proc(caps) != 0) || (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0)) - traceEvent(TRACE_WARNING, "Unable to retain permitted capabilities [%s]\n", strerror(errno)); + if((cap_set_proc(caps) != 0) || (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0)) + traceEvent(TRACE_WARNING, "Unable to retain permitted capabilities [%s]\n", strerror(errno)); #else #ifndef __APPLE__ - traceEvent(TRACE_WARNING, "n2n has not been compiled with libcap-dev. Some commands may fail."); + traceEvent(TRACE_WARNING, "n2n has not been compiled with libcap-dev. Some commands may fail."); #endif #endif /* HAVE_LIBCAP */ - if((eee->tuntap_priv_conf.userid != 0) || (eee->tuntap_priv_conf.groupid != 0)) { - traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d", - (signed int)eee->tuntap_priv_conf.userid, (signed int)eee->tuntap_priv_conf.groupid); + if((eee->tuntap_priv_conf.userid != 0) || (eee->tuntap_priv_conf.groupid != 0)) { + traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d", + (signed int)eee->tuntap_priv_conf.userid, (signed int)eee->tuntap_priv_conf.groupid); - /* Finished with the need for root privileges. Drop to unprivileged user. */ - if((setgid(eee->tuntap_priv_conf.groupid) != 0) - || (setuid(eee->tuntap_priv_conf.userid) != 0)) { - traceEvent(TRACE_ERROR, "Unable to drop privileges [%u/%s]", errno, strerror(errno)); - exit(1); + /* Finished with the need for root privileges. Drop to unprivileged user. */ + if((setgid(eee->tuntap_priv_conf.groupid) != 0) + || (setuid(eee->tuntap_priv_conf.userid) != 0)) { + traceEvent(TRACE_ERROR, "Unable to drop privileges [%u/%s]", errno, strerror(errno)); + exit(1); + } } - } - if((getuid() == 0) || (getgid() == 0)) - traceEvent(TRACE_WARNING, "Running as root is discouraged, check out the -u/-g options"); + if((getuid() == 0) || (getgid() == 0)) + traceEvent(TRACE_WARNING, "Running as root is discouraged, check out the -u/-g options"); #endif #ifdef __linux__ - signal(SIGTERM, term_handler); - signal(SIGINT, term_handler); + signal(SIGTERM, term_handler); + signal(SIGINT, term_handler); #endif #ifdef WIN32 - SetConsoleCtrlHandler(term_handler, TRUE); + SetConsoleCtrlHandler(term_handler, TRUE); #endif - keep_on_running = 1; - traceEvent(TRACE_NORMAL, "edge started"); - rc = run_edge_loop(eee, &keep_on_running); - print_edge_stats(eee); + keep_on_running = 1; + traceEvent(TRACE_NORMAL, "edge started"); + rc = run_edge_loop(eee, &keep_on_running); + print_edge_stats(eee); #ifdef HAVE_LIBCAP - /* Before completing the cleanup, regain the capabilities as some - * cleanup tasks require them (e.g. routes cleanup). */ - cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET); + /* Before completing the cleanup, regain the capabilities as some + * cleanup tasks require them (e.g. routes cleanup). */ + cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET); - if(cap_set_proc(caps) != 0) - traceEvent(TRACE_WARNING, "Could not regain the capabilities [%s]\n", strerror(errno)); + if(cap_set_proc(caps) != 0) + traceEvent(TRACE_WARNING, "Could not regain the capabilities [%s]\n", strerror(errno)); - cap_free(caps); + cap_free(caps); #endif - /* Cleanup */ - edge_term_conf(&eee->conf); - tuntap_close(&eee->device); - edge_term(eee); + /* Cleanup */ + edge_term_conf(&eee->conf); + tuntap_close(&eee->device); + edge_term(eee); #ifdef WIN32 - destroyWin32(); + destroyWin32(); #endif - return(rc); + return(rc); } /* ************************************** */ diff --git a/src/edge_utils.c b/src/edge_utils.c index 94964be..1a1a74d 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -52,23 +52,23 @@ static void check_known_peer_sock_change (n2n_edge_t *eee, int edge_verify_conf (const n2n_edge_conf_t *conf) { - if(conf->community_name[0] == 0) - return(-1); + if(conf->community_name[0] == 0) + return(-1); - if(conf->sn_num == 0) - return(-2); + if(conf->sn_num == 0) + return(-2); - if(conf->register_interval < 1) - return(-3); + if(conf->register_interval < 1) + return(-3); - if(((conf->encrypt_key == NULL) && (conf->transop_id != N2N_TRANSFORM_ID_NULL)) || - ((conf->encrypt_key != NULL) && (conf->transop_id == N2N_TRANSFORM_ID_NULL))) - return(-4); + if(((conf->encrypt_key == NULL) && (conf->transop_id != N2N_TRANSFORM_ID_NULL)) || + ((conf->encrypt_key != NULL) && (conf->transop_id == N2N_TRANSFORM_ID_NULL))) + return(-4); - if(HASH_COUNT(conf->supernodes) == 0) - return(-5); + if(HASH_COUNT(conf->supernodes) == 0) + return(-5); - return(0); + return(0); } @@ -76,61 +76,61 @@ int edge_verify_conf (const n2n_edge_conf_t *conf) { void edge_set_callbacks (n2n_edge_t *eee, const n2n_edge_callbacks_t *callbacks) { - memcpy(&eee->cb, callbacks, sizeof(n2n_edge_callbacks_t)); + memcpy(&eee->cb, callbacks, sizeof(n2n_edge_callbacks_t)); } /* ************************************** */ void edge_set_userdata (n2n_edge_t *eee, void *user_data) { - eee->user_data = user_data; + eee->user_data = user_data; } /* ************************************** */ void* edge_get_userdata (n2n_edge_t *eee) { - return(eee->user_data); + return(eee->user_data); } /* ************************************** */ int edge_get_n2n_socket (n2n_edge_t *eee) { - return(eee->udp_sock); + return(eee->udp_sock); } /* ************************************** */ int edge_get_management_socket (n2n_edge_t *eee) { - return(eee->udp_mgmt_sock); + return(eee->udp_mgmt_sock); } /* ************************************** */ const char* transop_str (enum n2n_transform tr) { - switch(tr) { - case N2N_TRANSFORM_ID_NULL: return("null"); - case N2N_TRANSFORM_ID_TWOFISH: return("Twofish"); - case N2N_TRANSFORM_ID_AES: return("AES"); - case N2N_TRANSFORM_ID_CHACHA20:return("ChaCha20"); - case N2N_TRANSFORM_ID_SPECK :return("Speck"); - default: return("invalid"); - }; + switch(tr) { + case N2N_TRANSFORM_ID_NULL: return("null"); + case N2N_TRANSFORM_ID_TWOFISH: return("Twofish"); + case N2N_TRANSFORM_ID_AES: return("AES"); + case N2N_TRANSFORM_ID_CHACHA20:return("ChaCha20"); + case N2N_TRANSFORM_ID_SPECK: return("Speck"); + default: return("invalid"); + }; } /* ************************************** */ const char* compression_str (uint8_t cmpr) { - switch(cmpr) { - case N2N_COMPRESSION_ID_NONE: return("none"); - case N2N_COMPRESSION_ID_LZO: return("lzo1x"); - case N2N_COMPRESSION_ID_ZSTD: return("zstd"); - default: return("invalid"); - }; + switch(cmpr) { + case N2N_COMPRESSION_ID_NONE: return("none"); + case N2N_COMPRESSION_ID_LZO: return("lzo1x"); + case N2N_COMPRESSION_ID_ZSTD: return("zstd"); + default: return("invalid"); + }; } /* ************************************** */ @@ -139,188 +139,189 @@ const char* compression_str (uint8_t cmpr) { */ static int is_ethMulticast (const void * buf, size_t bufsize) { - int retval = 0; + int retval = 0; - /* Match 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF */ - if(bufsize >= sizeof(ether_hdr_t)) { - /* copy to aligned memory */ - ether_hdr_t eh; - memcpy(&eh, buf, sizeof(ether_hdr_t)); + /* Match 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF */ + if(bufsize >= sizeof(ether_hdr_t)) { + /* copy to aligned memory */ + ether_hdr_t eh; + memcpy(&eh, buf, sizeof(ether_hdr_t)); - if((0x01 == eh.dhost[0]) && - (0x00 == eh.dhost[1]) && - (0x5E == eh.dhost[2]) && - (0 == (0x80 & eh.dhost[3]))) - retval = 1; /* This is an ethernet multicast packet [RFC1112]. */ - } + if((0x01 == eh.dhost[0]) && + (0x00 == eh.dhost[1]) && + (0x5E == eh.dhost[2]) && + (0 == (0x80 & eh.dhost[3]))) + retval = 1; /* This is an ethernet multicast packet [RFC1112]. */ + } - return retval; + return retval; } /* ************************************** */ /** Destination MAC 33:33:0:00:00:00 - 33:33:FF:FF:FF:FF is reserved for IPv6 - * neighbour discovery. + * neighbour discovery. */ static int is_ip6_discovery (const void * buf, size_t bufsize) { - int retval = 0; + int retval = 0; - if(bufsize >= sizeof(ether_hdr_t)) { - /* copy to aligned memory */ - ether_hdr_t eh; + if(bufsize >= sizeof(ether_hdr_t)) { + /* copy to aligned memory */ + ether_hdr_t eh; - memcpy(&eh, buf, sizeof(ether_hdr_t)); + memcpy(&eh, buf, sizeof(ether_hdr_t)); - if((0x33 == eh.dhost[0]) && (0x33 == eh.dhost[1])) - retval = 1; /* This is an IPv6 multicast packet [RFC2464]. */ - } + if((0x33 == eh.dhost[0]) && (0x33 == eh.dhost[1])) + retval = 1; /* This is an IPv6 multicast packet [RFC2464]. */ + } - return retval; + return retval; } /* ************************************** */ /** Initialise an edge to defaults. * - * This also initialises the NULL transform operation opstruct. + * This also initialises the NULL transform operation opstruct. */ n2n_edge_t* edge_init (const n2n_edge_conf_t *conf, int *rv) { - n2n_transform_t transop_id = conf->transop_id; - n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t)); - int rc = -1, i = 0; - struct peer_info *scan, *tmp; - size_t idx = 0; + n2n_transform_t transop_id = conf->transop_id; + n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t)); + int rc = -1, i = 0; + struct peer_info *scan, *tmp; + size_t idx = 0; - if((rc = edge_verify_conf(conf)) != 0) { - traceEvent(TRACE_ERROR, "Invalid configuration"); - goto edge_init_error; - } + if((rc = edge_verify_conf(conf)) != 0) { + traceEvent(TRACE_ERROR, "Invalid configuration"); + goto edge_init_error; + } - if(!eee) { - traceEvent(TRACE_ERROR, "Cannot allocate memory"); - goto edge_init_error; - } + if(!eee) { + traceEvent(TRACE_ERROR, "Cannot allocate memory"); + goto edge_init_error; + } - memcpy(&eee->conf, conf, sizeof(*conf)); - eee->curr_sn = eee->conf.supernodes; - eee->start_time = time(NULL); + memcpy(&eee->conf, conf, sizeof(*conf)); + eee->curr_sn = eee->conf.supernodes; + eee->start_time = time(NULL); - eee->known_peers = NULL; - eee->pending_peers = NULL; - eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; - eee->sn_last_valid_time_stamp = initial_time_stamp (); - sn_selection_criterion_common_data_default(eee); + eee->known_peers = NULL; + eee->pending_peers = NULL; + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; + eee->sn_last_valid_time_stamp = initial_time_stamp (); + sn_selection_criterion_common_data_default(eee); - pearson_hash_init(); + pearson_hash_init(); - if(eee->conf.compression == N2N_COMPRESSION_ID_LZO) - if(lzo_init() != LZO_E_OK) { - traceEvent(TRACE_ERROR, "LZO compression error"); - goto edge_init_error; - } + if(eee->conf.compression == N2N_COMPRESSION_ID_LZO) + if(lzo_init() != LZO_E_OK) { + traceEvent(TRACE_ERROR, "LZO compression error"); + goto edge_init_error; + } #ifdef N2N_HAVE_ZSTD - // zstd does not require initialization. if it were required, this would be a good place + // zstd does not require initialization. if it were required, this would be a good place #endif - traceEvent(TRACE_NORMAL, "Number of supernodes in the list: %d\n", HASH_COUNT(eee->conf.supernodes)); - HASH_ITER(hh, eee->conf.supernodes, scan, tmp) { - traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (scan->ip_addr)); - i++; - } + traceEvent(TRACE_NORMAL, "Number of supernodes in the list: %d\n", HASH_COUNT(eee->conf.supernodes)); + HASH_ITER(hh, eee->conf.supernodes, scan, tmp) { + traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (scan->ip_addr)); + i++; + } - /* Set active transop */ - switch(transop_id) { - case N2N_TRANSFORM_ID_TWOFISH: - rc = n2n_transop_tf_init(&eee->conf, &eee->transop); - break; + /* Set active transop */ + switch(transop_id) { + case N2N_TRANSFORM_ID_TWOFISH: + rc = n2n_transop_tf_init(&eee->conf, &eee->transop); + break; - case N2N_TRANSFORM_ID_AES: - rc = n2n_transop_aes_init(&eee->conf, &eee->transop); - break; + case N2N_TRANSFORM_ID_AES: + rc = n2n_transop_aes_init(&eee->conf, &eee->transop); + break; - case N2N_TRANSFORM_ID_CHACHA20: - rc = n2n_transop_cc20_init(&eee->conf, &eee->transop); - break; + case N2N_TRANSFORM_ID_CHACHA20: + rc = n2n_transop_cc20_init(&eee->conf, &eee->transop); + break; - case N2N_TRANSFORM_ID_SPECK: - rc = n2n_transop_speck_init(&eee->conf, &eee->transop); - break; + case N2N_TRANSFORM_ID_SPECK: + rc = n2n_transop_speck_init(&eee->conf, &eee->transop); + break; - default: - rc = n2n_transop_null_init(&eee->conf, &eee->transop); - } + default: + rc = n2n_transop_null_init(&eee->conf, &eee->transop); + } - if((rc < 0) || (eee->transop.fwd == NULL) || (eee->transop.transform_id != transop_id)) { - traceEvent(TRACE_ERROR, "Transop init failed"); - goto edge_init_error; - } + if((rc < 0) || (eee->transop.fwd == NULL) || (eee->transop.transform_id != transop_id)) { + traceEvent(TRACE_ERROR, "Transop init failed"); + goto edge_init_error; + } - /* Set the key schedule (context) for header encryption if enabled */ - if(conf->header_encryption == HEADER_ENCRYPTION_ENABLED) { - traceEvent(TRACE_NORMAL, "Header encryption is enabled."); - packet_header_setup_key((char *)(eee->conf.community_name), &(eee->conf.header_encryption_ctx),&(eee->conf.header_iv_ctx)); - } + /* Set the key schedule (context) for header encryption if enabled */ + if(conf->header_encryption == HEADER_ENCRYPTION_ENABLED) { + traceEvent(TRACE_NORMAL, "Header encryption is enabled."); + packet_header_setup_key((char *)(eee->conf.community_name), &(eee->conf.header_encryption_ctx),&(eee->conf.header_iv_ctx)); + } - if(eee->transop.no_encryption) - traceEvent(TRACE_WARNING, "Encryption is disabled in edge"); + if(eee->transop.no_encryption) + traceEvent(TRACE_WARNING, "Encryption is disabled in edge"); - // first time calling edge_init_sockets needs -1 in the sockets for it does throw an error - // on trying to close them (open_sockets does so for also being able to RE-open the sockets - // if called in-between, see "Supernode not responding" in update_supernode_reg(...) - eee->udp_sock = -1; - eee->udp_mgmt_sock = -1; + // first time calling edge_init_sockets needs -1 in the sockets for it does throw an error + // on trying to close them (open_sockets does so for also being able to RE-open the sockets + // if called in-between, see "Supernode not responding" in update_supernode_reg(...) + eee->udp_sock = -1; + eee->udp_mgmt_sock = -1; - eee->conf.auth.scheme = n2n_auth_simple_id; + eee->conf.auth.scheme = n2n_auth_simple_id; - for (idx = 0; idx < N2N_AUTH_TOKEN_SIZE; ++idx) - eee->conf.auth.token[idx] = n2n_rand() % 0xff; + for(idx = 0; idx < N2N_AUTH_TOKEN_SIZE; ++idx) { + eee->conf.auth.token[idx] = n2n_rand() % 0xff; + } - eee->conf.auth.toksize = sizeof(eee->conf.auth.token); + eee->conf.auth.toksize = sizeof(eee->conf.auth.token); #ifndef SKIP_MULTICAST_PEERS_DISCOVERY - eee->udp_multicast_sock = -1; + eee->udp_multicast_sock = -1; #endif - if(edge_init_sockets(eee, eee->conf.local_port, eee->conf.mgmt_port, eee->conf.tos) < 0) { - traceEvent(TRACE_ERROR, "socket setup failed"); - goto edge_init_error; - } + if(edge_init_sockets(eee, eee->conf.local_port, eee->conf.mgmt_port, eee->conf.tos) < 0) { + traceEvent(TRACE_ERROR, "socket setup failed"); + goto edge_init_error; + } - if(edge_init_routes(eee, eee->conf.routes, eee->conf.num_routes) < 0) { - traceEvent(TRACE_ERROR, "routes setup failed"); - goto edge_init_error; - } + if(edge_init_routes(eee, eee->conf.routes, eee->conf.num_routes) < 0) { + traceEvent(TRACE_ERROR, "routes setup failed"); + goto edge_init_error; + } - eee->network_traffic_filter = create_network_traffic_filter(); - network_traffic_filter_add_rule(eee->network_traffic_filter, eee->conf.network_traffic_filter_rules); + eee->network_traffic_filter = create_network_traffic_filter(); + network_traffic_filter_add_rule(eee->network_traffic_filter, eee->conf.network_traffic_filter_rules); - //edge_init_success: - *rv = 0; - return(eee); + //edge_init_success: + *rv = 0; + return(eee); edge_init_error: - if(eee) - free(eee); - *rv = rc; - return(NULL); + if(eee) + free(eee); + *rv = rc; + return(NULL); } /* ************************************** */ static int find_and_remove_peer (struct peer_info **head, const n2n_mac_t mac) { - struct peer_info *peer; + struct peer_info *peer; - HASH_FIND_PEER(*head, mac, peer); - if(peer) { - HASH_DEL(*head, peer); - free(peer); - return(1); - } + HASH_FIND_PEER(*head, mac, peer); + if(peer) { + HASH_DEL(*head, peer); + free(peer); + return(1); + } - return(0); + return(0); } /* ************************************** */ @@ -333,22 +334,22 @@ static uint8_t localhost_v6[IPV6_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; */ static int is_valid_peer_sock (const n2n_sock_t *sock) { - switch(sock->family) { - case AF_INET: { - uint32_t *a = (uint32_t*)sock->addr.v4; + switch(sock->family) { + case AF_INET: { + uint32_t *a = (uint32_t*)sock->addr.v4; - if(*a != htonl(localhost_v4)) - return(1); - } - break; + if(*a != htonl(localhost_v4)) + return(1); + } + break; - case AF_INET6: - if(memcmp(sock->addr.v6, localhost_v6, IPV6_SIZE)) - return(1); - break; - } + case AF_INET6: + if(memcmp(sock->addr.v6, localhost_v6, IPV6_SIZE)) + return(1); + break; + } - return(0); + return(0); } /* ***************************************************** */ @@ -364,28 +365,28 @@ static int find_peer_time_stamp_and_verify (n2n_edge_t * eee, int from_supernode, const n2n_mac_t mac, uint64_t stamp, int allow_jitter) { - uint64_t * previous_stamp = NULL; + uint64_t * previous_stamp = NULL; - if(from_supernode) { - // from supernode - previous_stamp = &(eee->sn_last_valid_time_stamp); - } else { - // from (peer) edge - struct peer_info *peer; - HASH_FIND_PEER(eee->pending_peers, mac, peer); - if(!peer) { - HASH_FIND_PEER(eee->known_peers, mac, peer); - } + if(from_supernode) { + // from supernode + previous_stamp = &(eee->sn_last_valid_time_stamp); + } else { + // from (peer) edge + struct peer_info *peer; + HASH_FIND_PEER(eee->pending_peers, mac, peer); + if(!peer) { + HASH_FIND_PEER(eee->known_peers, mac, peer); + } - if(peer) { - // time_stamp_verify_and_update allows the pointer a previous stamp to be NULL - // if it is a (so far) unknown peer - previous_stamp = &(peer->last_valid_time_stamp); + if(peer) { + // time_stamp_verify_and_update allows the pointer a previous stamp to be NULL + // if it is a (so far) unknown peer + previous_stamp = &(peer->last_valid_time_stamp); + } } - } - // failure --> 0; success --> 1 - return (time_stamp_verify_and_update(stamp, previous_stamp, allow_jitter)); + // failure --> 0; success --> 1 + return (time_stamp_verify_and_update(stamp, previous_stamp, allow_jitter)); } /* ************************************** */ @@ -396,46 +397,46 @@ static int find_peer_time_stamp_and_verify (n2n_edge_t * eee, */ static void register_with_local_peers (n2n_edge_t * eee) { #ifndef SKIP_MULTICAST_PEERS_DISCOVERY - if(eee->multicast_joined && eee->conf.allow_p2p) { - /* send registration to the local multicast group */ - traceEvent(TRACE_DEBUG, "Registering with multicast group %s:%u", - N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); - send_register(eee, &(eee->multicast_peer), NULL); - } + if(eee->multicast_joined && eee->conf.allow_p2p) { + /* send registration to the local multicast group */ + traceEvent(TRACE_DEBUG, "Registering with multicast group %s:%u", + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); + send_register(eee, &(eee->multicast_peer), NULL); + } #else - traceEvent(TRACE_DEBUG, "Multicast peers discovery is disabled, skipping"); + traceEvent(TRACE_DEBUG, "Multicast peers discovery is disabled, skipping"); #endif } /* ************************************** */ static struct peer_info* find_peer_by_sock (const n2n_sock_t *sock, struct peer_info *peer_list) { - struct peer_info *scan, *tmp, *ret = NULL; + struct peer_info *scan, *tmp, *ret = NULL; - HASH_ITER(hh, peer_list, scan, tmp) { - if(memcmp(&(scan->sock), sock, sizeof(n2n_sock_t)) == 0) { - ret = scan; - break; + HASH_ITER(hh, peer_list, scan, tmp) { + if(memcmp(&(scan->sock), sock, sizeof(n2n_sock_t)) == 0) { + ret = scan; + break; + } } - } - return ret; + return ret; } /* ************************************** */ /** Start the registration process. * - * If the peer is already in pending_peers, ignore the request. - * If not in pending_peers, add it and send a REGISTER. + * If the peer is already in pending_peers, ignore the request. + * If not in pending_peers, add it and send a REGISTER. * - * If hdr is for a direct peer-to-peer packet, try to register back to sender - * even if the MAC is in pending_peers. This is because an incident direct - * packet indicates that peer-to-peer exchange should work so more aggressive - * registration can be permitted (once per incoming packet) as this should only - * last for a small number of packets.. + * If hdr is for a direct peer-to-peer packet, try to register back to sender + * even if the MAC is in pending_peers. This is because an incident direct + * packet indicates that peer-to-peer exchange should work so more aggressive + * registration can be permitted (once per incoming packet) as this should only + * last for a small number of packets.. * - * Called from the main loop when Rx a packet for our device mac. + * Called from the main loop when Rx a packet for our device mac. */ static void register_with_new_peer (n2n_edge_t *eee, uint8_t from_supernode, @@ -443,79 +444,79 @@ static void register_with_new_peer (n2n_edge_t *eee, const n2n_ip_subnet_t *dev_addr, const n2n_desc_t *dev_desc, const n2n_sock_t *peer) { - /* REVISIT: purge of pending_peers not yet done. */ - struct peer_info *scan; - macstr_t mac_buf; - n2n_sock_str_t sockbuf; - HASH_FIND_PEER(eee->pending_peers, mac, scan); - - /* NOTE: pending_peers are purged periodically with purge_expired_registrations */ - if(scan == NULL) { - scan = calloc(1, sizeof(struct peer_info)); - - memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); - scan->sock = *peer; - scan->timeout = eee->conf.register_interval; /* TODO: should correspond to the peer supernode registration timeout */ - scan->last_valid_time_stamp = initial_time_stamp(); - - HASH_ADD_PEER(eee->pending_peers, scan); - - traceEvent(TRACE_DEBUG, "=== new pending %s -> %s", - macaddr_str(mac_buf, scan->mac_addr), - sock_to_cstr(sockbuf, &(scan->sock))); - - traceEvent(TRACE_DEBUG, "Pending peers list size=%u", - HASH_COUNT(eee->pending_peers)); - - /* trace Sending REGISTER */ - if(from_supernode) { - /* UDP NAT hole punching through supernode. Send to peer first(punch local UDP hole) - * and then ask supernode to forward. Supernode then ask peer to ack. Some nat device - * drop and block ports with incoming UDP packet if out-come traffic does not exist. - * So we can alternatively set TTL so that the packet sent to peer never really reaches - * The register_ttl is basically nat level + 1. Set it to 1 means host like DMZ. - */ - if(eee->conf.register_ttl == 1) { - /* We are DMZ host or port is directly accessible. Just let peer to send back the ack */ + /* REVISIT: purge of pending_peers not yet done. */ + struct peer_info *scan; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + HASH_FIND_PEER(eee->pending_peers, mac, scan); + + /* NOTE: pending_peers are purged periodically with purge_expired_registrations */ + if(scan == NULL) { + scan = calloc(1, sizeof(struct peer_info)); + + memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); + scan->sock = *peer; + scan->timeout = eee->conf.register_interval; /* TODO: should correspond to the peer supernode registration timeout */ + scan->last_valid_time_stamp = initial_time_stamp(); + + HASH_ADD_PEER(eee->pending_peers, scan); + + traceEvent(TRACE_DEBUG, "=== new pending %s -> %s", + macaddr_str(mac_buf, scan->mac_addr), + sock_to_cstr(sockbuf, &(scan->sock))); + + traceEvent(TRACE_DEBUG, "Pending peers list size=%u", + HASH_COUNT(eee->pending_peers)); + /* trace Sending REGISTER */ + if(from_supernode) { + /* UDP NAT hole punching through supernode. Send to peer first(punch local UDP hole) + * and then ask supernode to forward. Supernode then ask peer to ack. Some nat device + * drop and block ports with incoming UDP packet if out-come traffic does not exist. + * So we can alternatively set TTL so that the packet sent to peer never really reaches + * The register_ttl is basically nat level + 1. Set it to 1 means host like DMZ. + */ + if(eee->conf.register_ttl == 1) { + /* We are DMZ host or port is directly accessible. Just let peer to send back the ack */ #ifndef WIN32 - } else if(eee->conf.register_ttl > 1) { - /* Setting register_ttl usually implies that the edge knows the internal net topology - * clearly, we can apply aggressive port prediction to support incoming Symmetric NAT - */ - int curTTL = 0; - socklen_t lenTTL = sizeof(int); - n2n_sock_t sock = scan->sock; - int alter = 16; /* TODO: set by command line or more reliable prediction method */ - - getsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, (void *) (char *) &curTTL, &lenTTL); - setsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, - (void *) (char *) &eee->conf.register_ttl, - sizeof(eee->conf.register_ttl)); - for(; alter > 0; alter--, sock.port++) { - send_register(eee, &sock, mac); - } - setsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, (void *) (char *) &curTTL, sizeof(curTTL)); + } else if(eee->conf.register_ttl > 1) { + /* Setting register_ttl usually implies that the edge knows the internal net topology + * clearly, we can apply aggressive port prediction to support incoming Symmetric NAT + */ + int curTTL = 0; + socklen_t lenTTL = sizeof(int); + n2n_sock_t sock = scan->sock; + int alter = 16; /* TODO: set by command line or more reliable prediction method */ + + getsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, (void *) (char *) &curTTL, &lenTTL); + setsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, + (void *) (char *) &eee->conf.register_ttl, + sizeof(eee->conf.register_ttl)); + for(; alter > 0; alter--, sock.port++) { + send_register(eee, &sock, mac); + } + setsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, (void *) (char *) &curTTL, sizeof(curTTL)); #endif - } else { /* eee->conf.register_ttl <= 0 */ - /* Normal STUN */ - send_register(eee, &(scan->sock), mac); - } - send_register(eee, &(eee->supernode), mac); - } else { - /* P2P register, send directly */ - send_register(eee, &(scan->sock), mac); - } + } else { /* eee->conf.register_ttl <= 0 */ + /* Normal STUN */ + send_register(eee, &(scan->sock), mac); + } + send_register(eee, &(eee->supernode), mac); + } else { + /* P2P register, send directly */ + send_register(eee, &(scan->sock), mac); + } - register_with_local_peers(eee); - } else{ - scan->sock = *peer; - } - scan->last_seen = time(NULL); - if(dev_addr != NULL) { - memcpy(&(scan->dev_addr), dev_addr, sizeof(n2n_ip_subnet_t)); - } - if(dev_desc) memcpy(scan->dev_desc, dev_desc, N2N_DESC_SIZE); + register_with_local_peers(eee); + } else{ + scan->sock = *peer; + } + scan->last_seen = time(NULL); + if(dev_addr != NULL) { + memcpy(&(scan->dev_addr), dev_addr, sizeof(n2n_ip_subnet_t)); + } + if(dev_desc) memcpy(scan->dev_desc, dev_desc, N2N_DESC_SIZE); } @@ -530,36 +531,36 @@ static void check_peer_registration_needed (n2n_edge_t *eee, const n2n_desc_t *dev_desc, const n2n_sock_t *peer) { - struct peer_info *scan; + struct peer_info *scan; - HASH_FIND_PEER(eee->known_peers, mac, scan); + HASH_FIND_PEER(eee->known_peers, mac, scan); - /* If we were not able to find it by MAC, we try to find it by socket. */ - if(scan == NULL ) { - scan = find_peer_by_sock(peer, eee->known_peers); + /* If we were not able to find it by MAC, we try to find it by socket. */ + if(scan == NULL ) { + scan = find_peer_by_sock(peer, eee->known_peers); - if(scan) { - HASH_DEL(eee->known_peers, scan); - memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); - HASH_ADD_PEER(eee->known_peers, scan); + if(scan) { + HASH_DEL(eee->known_peers, scan); + memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); + HASH_ADD_PEER(eee->known_peers, scan); + } } - } - if(scan == NULL) { - /* Not in known_peers - start the REGISTER process. */ - register_with_new_peer(eee, from_supernode, mac, dev_addr, dev_desc, peer); - } else { - /* Already in known_peers. */ - time_t now = time(NULL); + if(scan == NULL) { + /* Not in known_peers - start the REGISTER process. */ + register_with_new_peer(eee, from_supernode, mac, dev_addr, dev_desc, peer); + } else { + /* Already in known_peers. */ + time_t now = time(NULL); - if(!from_supernode) - scan->last_p2p = now; + if(!from_supernode) + scan->last_p2p = now; - if((now - scan->last_seen) > 0 /* >= 1 sec */) { - /* Don't register too often */ - check_known_peer_sock_change(eee, from_supernode, mac, dev_addr, dev_desc, peer, now); + if((now - scan->last_seen) > 0 /* >= 1 sec */) { + /* Don't register too often */ + check_known_peer_sock_change(eee, from_supernode, mac, dev_addr, dev_desc, peer, now); + } } - } } /* ************************************** */ @@ -573,73 +574,73 @@ static void peer_set_p2p_confirmed (n2n_edge_t * eee, const n2n_sock_t * peer, time_t now) { - struct peer_info *scan, *scan_tmp; - macstr_t mac_buf; - n2n_sock_str_t sockbuf; + struct peer_info *scan, *scan_tmp; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; - HASH_FIND_PEER(eee->pending_peers, mac, scan); - if(scan == NULL) { - scan = find_peer_by_sock(peer, eee->pending_peers); - } + HASH_FIND_PEER(eee->pending_peers, mac, scan); + if(scan == NULL) { + scan = find_peer_by_sock(peer, eee->pending_peers); + } - if(scan) { - HASH_DEL(eee->pending_peers, scan); + if(scan) { + HASH_DEL(eee->pending_peers, scan); - scan_tmp = find_peer_by_sock(peer, eee->known_peers); - if(scan_tmp != NULL) { - HASH_DEL(eee->known_peers, scan_tmp); - scan = scan_tmp; - memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); - } else { - scan->sock = *peer; - } + scan_tmp = find_peer_by_sock(peer, eee->known_peers); + if(scan_tmp != NULL) { + HASH_DEL(eee->known_peers, scan_tmp); + scan = scan_tmp; + memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); + } else { + scan->sock = *peer; + } - HASH_ADD_PEER(eee->known_peers, scan); - scan->last_p2p = now; + HASH_ADD_PEER(eee->known_peers, scan); + scan->last_p2p = now; - traceEvent(TRACE_DEBUG, "P2P connection established: %s [%s]", - macaddr_str(mac_buf, mac), - sock_to_cstr(sockbuf, peer)); + traceEvent(TRACE_DEBUG, "P2P connection established: %s [%s]", + macaddr_str(mac_buf, mac), + sock_to_cstr(sockbuf, peer)); - traceEvent(TRACE_DEBUG, "=== new peer %s -> %s", - macaddr_str(mac_buf, scan->mac_addr), - sock_to_cstr(sockbuf, &(scan->sock))); + traceEvent(TRACE_DEBUG, "=== new peer %s -> %s", + macaddr_str(mac_buf, scan->mac_addr), + sock_to_cstr(sockbuf, &(scan->sock))); - traceEvent(TRACE_DEBUG, "Pending peers list size=%u", - HASH_COUNT(eee->pending_peers)); + traceEvent(TRACE_DEBUG, "Pending peers list size=%u", + HASH_COUNT(eee->pending_peers)); - traceEvent(TRACE_DEBUG, "Known peers list size=%u", - HASH_COUNT(eee->known_peers)); + traceEvent(TRACE_DEBUG, "Known peers list size=%u", + HASH_COUNT(eee->known_peers)); - scan->last_seen = now; - } else - traceEvent(TRACE_DEBUG, "Failed to find sender in pending_peers."); + scan->last_seen = now; + } else + traceEvent(TRACE_DEBUG, "Failed to find sender in pending_peers."); } /* ************************************** */ int is_empty_ip_address (const n2n_sock_t * sock) { - const uint8_t * ptr = NULL; - size_t len = 0; - size_t i; + const uint8_t * ptr = NULL; + size_t len = 0; + size_t i; - if(AF_INET6 == sock->family) { - ptr = sock->addr.v6; - len = 16; - } else { - ptr = sock->addr.v4; - len = 4; - } + if(AF_INET6 == sock->family) { + ptr = sock->addr.v6; + len = 16; + } else { + ptr = sock->addr.v4; + len = 4; + } - for(i = 0; i < len; ++i) { - if(0 != ptr[i]) { - /* found a non-zero byte in address */ - return 0; + for(i = 0; i < len; ++i) { + if(0 != ptr[i]) { + /* found a non-zero byte in address */ + return 0; + } } - } - return 1; + return 1; } /* ************************************** */ @@ -657,41 +658,41 @@ static void check_known_peer_sock_change (n2n_edge_t *eee, const n2n_sock_t *peer, time_t when) { - struct peer_info *scan; - n2n_sock_str_t sockbuf1; - n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */ - macstr_t mac_buf; + struct peer_info *scan; + n2n_sock_str_t sockbuf1; + n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */ + macstr_t mac_buf; - if(is_empty_ip_address(peer)) - return; - - if(!memcmp(mac, broadcast_mac, N2N_MAC_SIZE)) - return; + if(is_empty_ip_address(peer)) + return; - /* Search the peer in known_peers */ - HASH_FIND_PEER(eee->known_peers, mac, scan); + if(!memcmp(mac, broadcast_mac, N2N_MAC_SIZE)) + return; - if(!scan) - /* Not in known_peers */ - return; + /* Search the peer in known_peers */ + HASH_FIND_PEER(eee->known_peers, mac, scan); - if(!sock_equal(&(scan->sock), peer)) { - if(!from_supernode) { - /* This is a P2P packet */ - traceEvent(TRACE_NORMAL, "Peer changed %s: %s -> %s", - macaddr_str(mac_buf, scan->mac_addr), - sock_to_cstr(sockbuf1, &(scan->sock)), - sock_to_cstr(sockbuf2, peer)); - /* The peer has changed public socket. It can no longer be assumed to be reachable. */ - HASH_DEL(eee->known_peers, scan); - free(scan); + if(!scan) + /* Not in known_peers */ + return; - register_with_new_peer(eee, from_supernode, mac, dev_addr, dev_desc, peer); - } else { - /* Don't worry about what the supernode reports, it could be seeing a different socket. */ - } - } else - scan->last_seen = when; + if(!sock_equal(&(scan->sock), peer)) { + if(!from_supernode) { + /* This is a P2P packet */ + traceEvent(TRACE_NORMAL, "Peer changed %s: %s -> %s", + macaddr_str(mac_buf, scan->mac_addr), + sock_to_cstr(sockbuf1, &(scan->sock)), + sock_to_cstr(sockbuf2, peer)); + /* The peer has changed public socket. It can no longer be assumed to be reachable. */ + HASH_DEL(eee->known_peers, scan); + free(scan); + + register_with_new_peer(eee, from_supernode, mac, dev_addr, dev_desc, peer); + } else { + /* Don't worry about what the supernode reports, it could be seeing a different socket. */ + } + } else + scan->last_seen = when; } /* ************************************** */ @@ -700,28 +701,28 @@ static void check_known_peer_sock_change (n2n_edge_t *eee, static ssize_t sendto_sock (int fd, const void * buf, size_t len, const n2n_sock_t * dest) { - struct sockaddr_in peer_addr; - ssize_t sent; + struct sockaddr_in peer_addr; + ssize_t sent; - if(!dest->family) - // Invalid socket - return 0; + if(!dest->family) + // Invalid socket + return 0; - fill_sockaddr((struct sockaddr *) &peer_addr, - sizeof(peer_addr), - dest); + fill_sockaddr((struct sockaddr *) &peer_addr, + sizeof(peer_addr), + dest); - sent = sendto(fd, buf, len, 0/*flags*/, - (struct sockaddr *)&peer_addr, sizeof(struct sockaddr_in)); + sent = sendto(fd, buf, len, 0/*flags*/, + (struct sockaddr *)&peer_addr, sizeof(struct sockaddr_in)); - if(sent < 0) { - char * c = strerror(errno); - traceEvent(TRACE_ERROR, "sendto failed (%d) %s", errno, c); - } else { - traceEvent(TRACE_DEBUG, "sendto sent=%d to ", (signed int)sent); - } + if(sent < 0) { + char * c = strerror(errno); + traceEvent(TRACE_ERROR, "sendto failed (%d) %s", errno, c); + } else { + traceEvent(TRACE_DEBUG, "sendto sent=%d to ", (signed int)sent); + } - return sent; + return sent; } /* ************************************** */ @@ -730,24 +731,24 @@ static ssize_t sendto_sock (int fd, const void * buf, static void check_join_multicast_group (n2n_edge_t *eee) { #ifndef SKIP_MULTICAST_PEERS_DISCOVERY - if(!eee->multicast_joined) { - struct ip_mreq mreq; - mreq.imr_multiaddr.s_addr = inet_addr(N2N_MULTICAST_GROUP); - mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if(!eee->multicast_joined) { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = inet_addr(N2N_MULTICAST_GROUP); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); - if(setsockopt(eee->udp_multicast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) { - traceEvent(TRACE_WARNING, "Failed to bind to local multicast group %s:%u [errno %u]", - N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT, errno); + if(setsockopt(eee->udp_multicast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) { + traceEvent(TRACE_WARNING, "Failed to bind to local multicast group %s:%u [errno %u]", + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT, errno); #ifdef WIN32 - traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); + traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); #endif - } else { - traceEvent(TRACE_NORMAL, "Successfully joined multicast group %s:%u", - N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); - eee->multicast_joined = 1; + } else { + traceEvent(TRACE_NORMAL, "Successfully joined multicast group %s:%u", + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); + eee->multicast_joined = 1; + } } - } #endif } @@ -757,52 +758,52 @@ static void check_join_multicast_group (n2n_edge_t *eee) { static void send_query_peer (n2n_edge_t * eee, const n2n_mac_t dstMac) { - uint8_t pktbuf[N2N_PKT_BUF_SIZE]; - size_t idx; - n2n_common_t cmn = {0}; - n2n_QUERY_PEER_t query = {{0}}; - struct peer_info *peer, *tmp; - uint8_t tmp_pkt[N2N_PKT_BUF_SIZE]; + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + n2n_common_t cmn = {0}; + n2n_QUERY_PEER_t query = {{0}}; + struct peer_info *peer, *tmp; + uint8_t tmp_pkt[N2N_PKT_BUF_SIZE]; - cmn.ttl = N2N_DEFAULT_TTL; - cmn.pc = n2n_query_peer; - cmn.flags = 0; - memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_query_peer; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - idx = 0; - encode_mac(query.srcMac, &idx, eee->device.mac_addr); + idx = 0; + encode_mac(query.srcMac, &idx, eee->device.mac_addr); - idx = 0; - encode_mac(query.targetMac, &idx, dstMac); + idx = 0; + encode_mac(query.targetMac, &idx, dstMac); - idx = 0; - encode_QUERY_PEER(pktbuf, &idx, &cmn, &query); + idx = 0; + encode_QUERY_PEER(pktbuf, &idx, &cmn, &query); - if(memcmp(dstMac, null_mac, sizeof(n2n_mac_t)) != 0) { + if(memcmp(dstMac, null_mac, sizeof(n2n_mac_t)) != 0) { - traceEvent(TRACE_DEBUG, "send QUERY_PEER to supernode"); + traceEvent(TRACE_DEBUG, "send QUERY_PEER to supernode"); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, - time_stamp (), pearson_hash_16 (pktbuf, idx)); - } + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, + eee->conf.header_iv_ctx, + time_stamp (), pearson_hash_16 (pktbuf, idx)); + } - sendto_sock(eee->udp_sock, pktbuf, idx, &(eee->supernode)); + sendto_sock(eee->udp_sock, pktbuf, idx, &(eee->supernode)); - } else { - traceEvent(TRACE_DEBUG, "send PING to supernodes"); + } else { + traceEvent(TRACE_DEBUG, "send PING to supernodes"); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, - time_stamp (), pearson_hash_16 (pktbuf, idx)); - } + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, + eee->conf.header_iv_ctx, + time_stamp (), pearson_hash_16 (pktbuf, idx)); + } - HASH_ITER(hh, eee->conf.supernodes, peer, tmp) { - sendto_sock(eee->udp_sock, pktbuf, idx, &(peer->sock)); + HASH_ITER(hh, eee->conf.supernodes, peer, tmp) { + sendto_sock(eee->udp_sock, pktbuf, idx, &(peer->sock)); + } } - } } /* ******************************************************** */ @@ -810,122 +811,123 @@ static void send_query_peer (n2n_edge_t * eee, /** Send a REGISTER_SUPER packet to the current supernode. */ static void send_register_super (n2n_edge_t *eee) { - uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; - size_t idx; - /* ssize_t sent; */ - n2n_common_t cmn; - n2n_REGISTER_SUPER_t reg; - n2n_sock_str_t sockbuf; + uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_REGISTER_SUPER_t reg; + n2n_sock_str_t sockbuf; - memset(&cmn, 0, sizeof(cmn)); - memset(®, 0, sizeof(reg)); + memset(&cmn, 0, sizeof(cmn)); + memset(®, 0, sizeof(reg)); - cmn.ttl = N2N_DEFAULT_TTL; - cmn.pc = n2n_register_super; - cmn.flags = 0; - memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_register_super; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - for(idx = 0; idx < N2N_COOKIE_SIZE; ++idx) - eee->curr_sn->last_cookie[idx] = n2n_rand() % 0xff; + for(idx = 0; idx < N2N_COOKIE_SIZE; ++idx) { + eee->curr_sn->last_cookie[idx] = n2n_rand() % 0xff; + } - memcpy(reg.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE); - reg.dev_addr.net_addr = ntohl(eee->device.ip_addr); - reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask)); - memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE); - memcpy(&(reg.auth), &(eee->conf.auth), sizeof(n2n_auth_t)); + memcpy(reg.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE); + reg.dev_addr.net_addr = ntohl(eee->device.ip_addr); + reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask)); + memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE); + memcpy(&(reg.auth), &(eee->conf.auth), sizeof(n2n_auth_t)); - idx = 0; - encode_mac(reg.edgeMac, &idx, eee->device.mac_addr); + idx = 0; + encode_mac(reg.edgeMac, &idx, eee->device.mac_addr); - idx = 0; - encode_REGISTER_SUPER(pktbuf, &idx, &cmn, ®); + idx = 0; + encode_REGISTER_SUPER(pktbuf, &idx, &cmn, ®); - traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s", - sock_to_cstr(sockbuf, &(eee->curr_sn->sock))); + traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s", + sock_to_cstr(sockbuf, &(eee->curr_sn->sock))); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) - packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, - time_stamp(), pearson_hash_16(pktbuf, idx)); + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) + packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, + eee->conf.header_iv_ctx, + time_stamp(), pearson_hash_16(pktbuf, idx)); - /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, &(eee->curr_sn->sock)); + /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, &(eee->curr_sn->sock)); } static void send_unregister_super (n2n_edge_t *eee) { - uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; - size_t idx; - /* ssize_t sent; */ - n2n_common_t cmn; - n2n_UNREGISTER_SUPER_t unreg; - n2n_sock_str_t sockbuf; + uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_UNREGISTER_SUPER_t unreg; + n2n_sock_str_t sockbuf; - memset(&cmn, 0, sizeof(cmn)); - memset(&unreg, 0, sizeof(unreg)); + memset(&cmn, 0, sizeof(cmn)); + memset(&unreg, 0, sizeof(unreg)); - cmn.ttl = N2N_DEFAULT_TTL; - cmn.pc = n2n_unregister_super; - cmn.flags = 0; - memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_unregister_super; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - memcpy(&(unreg.auth), &(eee->conf.auth), sizeof(n2n_auth_t)); + memcpy(&(unreg.auth), &(eee->conf.auth), sizeof(n2n_auth_t)); - idx = 0; - encode_mac(unreg.srcMac, &idx, eee->device.mac_addr); + idx = 0; + encode_mac(unreg.srcMac, &idx, eee->device.mac_addr); - idx = 0; - encode_UNREGISTER_SUPER(pktbuf, &idx, &cmn, &unreg); + idx = 0; + encode_UNREGISTER_SUPER(pktbuf, &idx, &cmn, &unreg); - traceEvent(TRACE_DEBUG, "send UNREGISTER_SUPER to %s", - sock_to_cstr(sockbuf, &(eee->curr_sn->sock))); + traceEvent(TRACE_DEBUG, "send UNREGISTER_SUPER to %s", + sock_to_cstr(sockbuf, &(eee->curr_sn->sock))); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) - packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, - time_stamp(), pearson_hash_16(pktbuf, idx)); + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) + packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, + eee->conf.header_iv_ctx, + time_stamp(), pearson_hash_16(pktbuf, idx)); - /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, &(eee->curr_sn->sock)); + /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, &(eee->curr_sn->sock)); } static int sort_supernodes (n2n_edge_t *eee, time_t now) { - struct peer_info *scan, *tmp; + struct peer_info *scan, *tmp; - if(eee->curr_sn != eee->conf.supernodes) { - send_unregister_super(eee); + if(eee->curr_sn != eee->conf.supernodes) { + send_unregister_super(eee); - eee->curr_sn = eee->conf.supernodes; - memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t)); - eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; + eee->curr_sn = eee->conf.supernodes; + memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t)); + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; - traceEvent(TRACE_INFO, "Registering with supernode [%s][number of supernodes %d][attempts left %u]", - supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts); + traceEvent(TRACE_INFO, "Registering with supernode [%s][number of supernodes %d][attempts left %u]", + supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts); - send_register_super(eee); - eee->sn_wait = 1; - } + send_register_super(eee); + eee->sn_wait = 1; + } - if(now - eee->last_sweep > SWEEP_TIME) { - if(eee->sn_wait == 0) { - // this routine gets periodically called - // it sorts supernodes in ascending order of their selection_criterion fields - sn_selection_sort(&(eee->conf.supernodes)); + if(now - eee->last_sweep > SWEEP_TIME) { + if(eee->sn_wait == 0) { + // this routine gets periodically called + // it sorts supernodes in ascending order of their selection_criterion fields + sn_selection_sort(&(eee->conf.supernodes)); - } + } - HASH_ITER(hh, eee->conf.supernodes, scan, tmp) { - sn_selection_criterion_default(&(scan->selection_criterion)); - } - sn_selection_criterion_common_data_default(eee); + HASH_ITER(hh, eee->conf.supernodes, scan, tmp) { + sn_selection_criterion_default(&(scan->selection_criterion)); + } + sn_selection_criterion_common_data_default(eee); - send_query_peer(eee, null_mac); - eee->last_sweep = now; - } + send_query_peer(eee, null_mac); + eee->last_sweep = now; + } - return 0; /* OK */ + return 0; /* OK */ } /** Send a REGISTER packet to another edge. */ @@ -933,52 +935,52 @@ static void send_register (n2n_edge_t * eee, const n2n_sock_t * remote_peer, const n2n_mac_t peer_mac) { - uint8_t pktbuf[N2N_PKT_BUF_SIZE]; - size_t idx; - /* ssize_t sent; */ - n2n_common_t cmn; - n2n_REGISTER_t reg; - n2n_sock_str_t sockbuf; - - if(!eee->conf.allow_p2p) { - traceEvent(TRACE_DEBUG, "Skipping register as P2P is disabled"); - return; - } - - memset(&cmn, 0, sizeof(cmn)); - memset(®, 0, sizeof(reg)); - cmn.ttl = N2N_DEFAULT_TTL; - cmn.pc = n2n_register; - cmn.flags = 0; - memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - - idx = 0; - encode_uint32(reg.cookie, &idx, 123456789); - idx = 0; - encode_mac(reg.srcMac, &idx, eee->device.mac_addr); - - if(peer_mac) { - /* Can be NULL for multicast registrations */ + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_REGISTER_t reg; + n2n_sock_str_t sockbuf; + + if(!eee->conf.allow_p2p) { + traceEvent(TRACE_DEBUG, "Skipping register as P2P is disabled"); + return; + } + + memset(&cmn, 0, sizeof(cmn)); + memset(®, 0, sizeof(reg)); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_register; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + + idx = 0; + encode_uint32(reg.cookie, &idx, 123456789); idx = 0; - encode_mac(reg.dstMac, &idx, peer_mac); - } - reg.dev_addr.net_addr = ntohl(eee->device.ip_addr); - reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask)); - memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE); + encode_mac(reg.srcMac, &idx, eee->device.mac_addr); + if(peer_mac) { + /* Can be NULL for multicast registrations */ + idx = 0; + encode_mac(reg.dstMac, &idx, peer_mac); + } + reg.dev_addr.net_addr = ntohl(eee->device.ip_addr); + reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask)); + memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE); - idx = 0; - encode_REGISTER(pktbuf, &idx, &cmn, ®); - traceEvent(TRACE_INFO, "Send REGISTER to %s", - sock_to_cstr(sockbuf, remote_peer)); + idx = 0; + encode_REGISTER(pktbuf, &idx, &cmn, ®); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) - packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, - time_stamp (), pearson_hash_16 (pktbuf, idx)); + traceEvent(TRACE_INFO, "Send REGISTER to %s", + sock_to_cstr(sockbuf, remote_peer)); - /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) + packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, + eee->conf.header_iv_ctx, + time_stamp(), pearson_hash_16(pktbuf, idx)); + + /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); } /* ************************************** */ @@ -988,146 +990,146 @@ static void send_register_ack (n2n_edge_t * eee, const n2n_sock_t * remote_peer, const n2n_REGISTER_t * reg) { - uint8_t pktbuf[N2N_PKT_BUF_SIZE]; - size_t idx; - /* ssize_t sent; */ - n2n_common_t cmn; - n2n_REGISTER_ACK_t ack; - n2n_sock_str_t sockbuf; - - if(!eee->conf.allow_p2p) { - traceEvent(TRACE_DEBUG, "Skipping register ACK as P2P is disabled"); - return; - } - - memset(&cmn, 0, sizeof(cmn)); - memset(&ack, 0, sizeof(reg)); - cmn.ttl = N2N_DEFAULT_TTL; - cmn.pc = n2n_register_ack; - cmn.flags = 0; - memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - - memset(&ack, 0, sizeof(ack)); - memcpy(ack.cookie, reg->cookie, N2N_COOKIE_SIZE); - memcpy(ack.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); - memcpy(ack.dstMac, reg->srcMac, N2N_MAC_SIZE); - - idx = 0; - encode_REGISTER_ACK(pktbuf, &idx, &cmn, &ack); - - traceEvent(TRACE_INFO, "send REGISTER_ACK %s", - sock_to_cstr(sockbuf, remote_peer)); - - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) - packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, - time_stamp (), pearson_hash_16 (pktbuf, idx)); - - /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_REGISTER_ACK_t ack; + n2n_sock_str_t sockbuf; + + if(!eee->conf.allow_p2p) { + traceEvent(TRACE_DEBUG, "Skipping register ACK as P2P is disabled"); + return; + } + + memset(&cmn, 0, sizeof(cmn)); + memset(&ack, 0, sizeof(reg)); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_register_ack; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + + memset(&ack, 0, sizeof(ack)); + memcpy(ack.cookie, reg->cookie, N2N_COOKIE_SIZE); + memcpy(ack.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); + memcpy(ack.dstMac, reg->srcMac, N2N_MAC_SIZE); + + idx = 0; + encode_REGISTER_ACK(pktbuf, &idx, &cmn, &ack); + + traceEvent(TRACE_INFO, "send REGISTER_ACK %s", + sock_to_cstr(sockbuf, remote_peer)); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) + packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx, + eee->conf.header_iv_ctx, + time_stamp(), pearson_hash_16(pktbuf, idx)); + + /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); } /* ************************************** */ static char gratuitous_arp[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* dest MAC */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* src MAC */ - 0x08, 0x06, /* ARP */ - 0x00, 0x01, /* ethernet */ - 0x08, 0x00, /* IP */ - 0x06, /* hw Size */ - 0x04, /* protocol Size */ - 0x00, 0x02, /* ARP reply */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* src MAC */ - 0x00, 0x00, 0x00, 0x00, /* src IP */ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* target MAC */ - 0x00, 0x00, 0x00, 0x00 /* target IP */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* dest MAC */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* src MAC */ + 0x08, 0x06, /* ARP */ + 0x00, 0x01, /* ethernet */ + 0x08, 0x00, /* IP */ + 0x06, /* hw Size */ + 0x04, /* protocol Size */ + 0x00, 0x02, /* ARP reply */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* src MAC */ + 0x00, 0x00, 0x00, 0x00, /* src IP */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* target MAC */ + 0x00, 0x00, 0x00, 0x00 /* target IP */ }; // build a gratuitous ARP packet */ static int build_gratuitous_arp (n2n_edge_t * eee, char *buffer, uint16_t buffer_len) { - if(buffer_len < sizeof(gratuitous_arp)) return(-1); + if(buffer_len < sizeof(gratuitous_arp)) return(-1); - memcpy(buffer, gratuitous_arp, sizeof(gratuitous_arp)); - memcpy(&buffer[6], eee->device.mac_addr, 6); - memcpy(&buffer[22], eee->device.mac_addr, 6); - memcpy(&buffer[28], &(eee->device.ip_addr), 4); - memcpy(&buffer[38], &(eee->device.ip_addr), 4); + memcpy(buffer, gratuitous_arp, sizeof(gratuitous_arp)); + memcpy(&buffer[6], eee->device.mac_addr, 6); + memcpy(&buffer[22], eee->device.mac_addr, 6); + memcpy(&buffer[28], &(eee->device.ip_addr), 4); + memcpy(&buffer[38], &(eee->device.ip_addr), 4); - return(sizeof(gratuitous_arp)); + return(sizeof(gratuitous_arp)); } /** Called from update_supernode_reg to periodically send gratuitous ARP - * broadcasts. */ + * broadcasts. */ static void send_grat_arps (n2n_edge_t * eee) { - uint8_t buffer[48]; - size_t len; + uint8_t buffer[48]; + size_t len; - traceEvent(TRACE_DEBUG, "Sending gratuitous ARP..."); - len = build_gratuitous_arp(eee, (char*)buffer, sizeof(buffer)); + traceEvent(TRACE_DEBUG, "Sending gratuitous ARP..."); + len = build_gratuitous_arp(eee, (char*)buffer, sizeof(buffer)); - edge_send_packet2net(eee, buffer, len); - edge_send_packet2net(eee, buffer, len); /* Two is better than one :-) */ + edge_send_packet2net(eee, buffer, len); + edge_send_packet2net(eee, buffer, len); /* Two is better than one :-) */ } /* ************************************** */ /** @brief Check to see if we should re-register with the supernode. * - * This is frequently called by the main loop. + * This is frequently called by the main loop. */ void update_supernode_reg (n2n_edge_t * eee, time_t nowTime) { - struct peer_info *scan, *tmp; + struct peer_info *scan, *tmp; - if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->conf.register_interval/10)))) { - /* fall through */ - traceEvent(TRACE_DEBUG, "update_supernode_reg: doing fast retry."); - } else if(nowTime < (eee->last_register_req + eee->conf.register_interval)) - return; /* Too early */ + if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->conf.register_interval/10)))) { + /* fall through */ + traceEvent(TRACE_DEBUG, "update_supernode_reg: doing fast retry."); + } else if(nowTime < (eee->last_register_req + eee->conf.register_interval)) + return; /* Too early */ - check_join_multicast_group(eee); + check_join_multicast_group(eee); - if(0 == eee->sup_attempts) { - /* Give up on that supernode and try the next one. */ - sn_selection_criterion_default(&(eee->curr_sn->selection_criterion)); - sn_selection_sort(&(eee->conf.supernodes)); - eee->curr_sn = eee->conf.supernodes; - memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t)); + if(0 == eee->sup_attempts) { + /* Give up on that supernode and try the next one. */ + sn_selection_criterion_default(&(eee->curr_sn->selection_criterion)); + sn_selection_sort(&(eee->conf.supernodes)); + eee->curr_sn = eee->conf.supernodes; + memcpy(&eee->supernode, &(eee->curr_sn->sock), sizeof(n2n_sock_t)); - traceEvent(TRACE_WARNING, "Supernode not responding, now trying %s", supernode_ip(eee)); + traceEvent(TRACE_WARNING, "Supernode not responding, now trying %s", supernode_ip(eee)); - eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; - // in some multi-NATed scenarios communication gets stuck on losing connection to supernode - // closing and re-opening the socket(s) allows for re-establishing communication - // this can only be done, if working on som eunprivileged port and/or having sufficent - // privileges. as we are not able to check for sufficent privileges here, we only do it - // if port is sufficently high or unset. uncovered: privileged port and sufficent privileges - if((eee->conf.local_port == 0) || (eee->conf.local_port > 1024)) { - if(edge_init_sockets(eee, eee->conf.local_port, eee->conf.mgmt_port, eee->conf.tos) < 0) { - traceEvent(TRACE_ERROR, "socket re-initiliaization failed"); - } - } + // in some multi-NATed scenarios communication gets stuck on losing connection to supernode + // closing and re-opening the socket(s) allows for re-establishing communication + // this can only be done, if working on som eunprivileged port and/or having sufficent + // privileges. as we are not able to check for sufficent privileges here, we only do it + // if port is sufficently high or unset. uncovered: privileged port and sufficent privileges + if((eee->conf.local_port == 0) || (eee->conf.local_port > 1024)) { + if(edge_init_sockets(eee, eee->conf.local_port, eee->conf.mgmt_port, eee->conf.tos) < 0) { + traceEvent(TRACE_ERROR, "socket re-initiliaization failed"); + } + } - } - else - --(eee->sup_attempts); + } else { + --(eee->sup_attempts); + } - if(supernode2sock(&(eee->supernode), eee->curr_sn->ip_addr) == 0) { - traceEvent(TRACE_INFO, "Registering with supernode [%s][number of supernodes %d][attempts left %u]", - supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts); + if(supernode2sock(&(eee->supernode), eee->curr_sn->ip_addr) == 0) { + traceEvent(TRACE_INFO, "Registering with supernode [%s][number of supernodes %d][attempts left %u]", + supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts); - send_register_super(eee); - } + send_register_super(eee); + } - register_with_local_peers(eee); + register_with_local_peers(eee); - eee->sn_wait = 1; + eee->sn_wait = 1; - eee->last_register_req = nowTime; + eee->last_register_req = nowTime; } /* ************************************** */ @@ -1135,13 +1137,13 @@ void update_supernode_reg (n2n_edge_t * eee, time_t nowTime) { /** Return the IP address of the current supernode in the ring. */ static const char * supernode_ip (const n2n_edge_t * eee) { - return (eee->curr_sn->ip_addr); + return (eee->curr_sn->ip_addr); } /* ************************************** */ /** A PACKET has arrived containing an encapsulated ethernet datagram - usually - * encrypted. */ + * encrypted. */ static int handle_PACKET (n2n_edge_t * eee, const uint8_t from_supernode, const n2n_PACKET_t * pkt, @@ -1149,149 +1151,149 @@ static int handle_PACKET (n2n_edge_t * eee, uint8_t * payload, size_t psize) { - ssize_t data_sent_len; - uint8_t * eth_payload = NULL; - int retval = -1; - time_t now; - ether_hdr_t * eh; - ipstr_t ip_buf; - macstr_t mac_buf; - n2n_sock_str_t sockbuf; + ssize_t data_sent_len; + uint8_t * eth_payload = NULL; + int retval = -1; + time_t now; + ether_hdr_t * eh; + ipstr_t ip_buf; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; - now = time(NULL); + now = time(NULL); - traceEvent(TRACE_DEBUG, "handle_PACKET size %u transform %u", - (unsigned int)psize, (unsigned int)pkt->transform); - /* hexdump(payload, psize); */ + traceEvent(TRACE_DEBUG, "handle_PACKET size %u transform %u", + (unsigned int)psize, (unsigned int)pkt->transform); + /* hexdump(payload, psize); */ - if(from_supernode) { - if(!memcmp(pkt->dstMac, broadcast_mac, N2N_MAC_SIZE)) - ++(eee->stats.rx_sup_broadcast); + if(from_supernode) { + if(!memcmp(pkt->dstMac, broadcast_mac, N2N_MAC_SIZE)) + ++(eee->stats.rx_sup_broadcast); - ++(eee->stats.rx_sup); - eee->last_sup=now; - } else { - ++(eee->stats.rx_p2p); - eee->last_p2p=now; - } - - /* Handle transform. */ - { - uint8_t decodebuf[N2N_PKT_BUF_SIZE]; - size_t eth_size; - n2n_transform_t rx_transop_id; - uint8_t rx_compression_id; - - rx_transop_id = (n2n_transform_t)pkt->transform; - rx_compression_id = pkt->compression; - - if(rx_transop_id == eee->conf.transop_id) { - uint8_t is_multicast; - eth_payload = decodebuf; - eh = (ether_hdr_t*)eth_payload; - eth_size = eee->transop.rev(&eee->transop, - eth_payload, N2N_PKT_BUF_SIZE, - payload, psize, pkt->srcMac); - ++(eee->transop.rx_cnt); /* stats */ - - /* decompress if necessary */ - uint8_t * deflation_buffer = 0; - lzo_uint deflated_len; - switch(rx_compression_id) { - case N2N_COMPRESSION_ID_NONE: - break; // continue afterwards - - case N2N_COMPRESSION_ID_LZO: - deflation_buffer = malloc(N2N_PKT_BUF_SIZE); - lzo1x_decompress(eth_payload, eth_size, deflation_buffer, &deflated_len, NULL); - break; + ++(eee->stats.rx_sup); + eee->last_sup = now; + } else { + ++(eee->stats.rx_p2p); + eee->last_p2p=now; + } + + /* Handle transform. */ + { + uint8_t decodebuf[N2N_PKT_BUF_SIZE]; + size_t eth_size; + n2n_transform_t rx_transop_id; + uint8_t rx_compression_id; + + rx_transop_id = (n2n_transform_t)pkt->transform; + rx_compression_id = pkt->compression; + + if(rx_transop_id == eee->conf.transop_id) { + uint8_t is_multicast; + eth_payload = decodebuf; + eh = (ether_hdr_t*)eth_payload; + eth_size = eee->transop.rev(&eee->transop, + eth_payload, N2N_PKT_BUF_SIZE, + payload, psize, pkt->srcMac); + ++(eee->transop.rx_cnt); /* stats */ + + /* decompress if necessary */ + uint8_t * deflation_buffer = 0; + lzo_uint deflated_len; + switch(rx_compression_id) { + case N2N_COMPRESSION_ID_NONE: + break; // continue afterwards + + case N2N_COMPRESSION_ID_LZO: + deflation_buffer = malloc(N2N_PKT_BUF_SIZE); + lzo1x_decompress(eth_payload, eth_size, deflation_buffer, &deflated_len, NULL); + break; #ifdef N2N_HAVE_ZSTD - case N2N_COMPRESSION_ID_ZSTD: - deflated_len = N2N_PKT_BUF_SIZE; - deflation_buffer = malloc(deflated_len); - deflated_len = ZSTD_decompress(deflation_buffer, deflated_len, eth_payload, eth_size); - if(ZSTD_isError(deflated_len)) { - traceEvent(TRACE_ERROR, "payload decompression failed with zstd error '%s'.", - ZSTD_getErrorName(deflated_len)); - free(deflation_buffer); - return(-1); // cannot help it - } - break; + case N2N_COMPRESSION_ID_ZSTD: + deflated_len = N2N_PKT_BUF_SIZE; + deflation_buffer = malloc(deflated_len); + deflated_len = ZSTD_decompress(deflation_buffer, deflated_len, eth_payload, eth_size); + if(ZSTD_isError(deflated_len)) { + traceEvent(TRACE_ERROR, "payload decompression failed with zstd error '%s'.", + ZSTD_getErrorName(deflated_len)); + free(deflation_buffer); + return(-1); // cannot help it + } + break; #endif - default: - traceEvent(TRACE_ERROR, "payload decompression failed: received packet indicating unsupported %s compression.", - compression_str(rx_compression_id)); - return(-1); // cannot handle it - } - - if(rx_compression_id != N2N_COMPRESSION_ID_NONE) { - traceEvent(TRACE_DEBUG, "payload decompression [%s]: deflated %u bytes to %u bytes", - compression_str(rx_compression_id), eth_size, (int)deflated_len); - memcpy(eth_payload ,deflation_buffer, deflated_len ); - eth_size = deflated_len; - free(deflation_buffer); - } - - is_multicast = (is_ip6_discovery(eth_payload, eth_size) || is_ethMulticast(eth_payload, eth_size)); - - if(eee->conf.drop_multicast && is_multicast) { - traceEvent(TRACE_INFO, "Dropping RX multicast"); - return(-1); - } else if((!eee->conf.allow_routing) && (!is_multicast)) { - /* Check if it is a routed packet */ - - if((ntohs(eh->type) == 0x0800) && (eth_size >= ETH_FRAMESIZE + IP4_MIN_SIZE)) { - uint32_t *dst = (uint32_t*)ð_payload[ETH_FRAMESIZE + IP4_DSTOFFSET]; - uint8_t *dst_mac = (uint8_t*)eth_payload; - - /* Note: all elements of the_ip are in network order */ - if(!memcmp(dst_mac, broadcast_mac, N2N_MAC_SIZE)) - traceEvent(TRACE_DEBUG, "Broadcast packet [%s]", - intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); - else if((*dst != eee->device.ip_addr)) { - /* This is a packet that needs to be routed */ - traceEvent(TRACE_INFO, "Discarding routed packet [%s]", - intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); - return(-1); - } else { - /* This packet is directed to us */ - /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ - } - } - } + default: + traceEvent(TRACE_ERROR, "payload decompression failed: received packet indicating unsupported %s compression.", + compression_str(rx_compression_id)); + return(-1); // cannot handle it + } - if(eee->network_traffic_filter->filter_packet_from_peer(eee->network_traffic_filter, eee, orig_sender, - eth_payload, eth_size) == N2N_DROP) { - traceEvent(TRACE_DEBUG, "Filtered packet %u", (unsigned int)eth_size); - return(0); - } + if(rx_compression_id != N2N_COMPRESSION_ID_NONE) { + traceEvent(TRACE_DEBUG, "payload decompression [%s]: deflated %u bytes to %u bytes", + compression_str(rx_compression_id), eth_size, (int)deflated_len); + memcpy(eth_payload ,deflation_buffer, deflated_len ); + eth_size = deflated_len; + free(deflation_buffer); + } - if(eee->cb.packet_from_peer) { - uint16_t tmp_eth_size = eth_size; - if(eee->cb.packet_from_peer(eee, orig_sender, eth_payload, &tmp_eth_size) == N2N_DROP) { - traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)eth_size); - return(0); - } - eth_size = tmp_eth_size; - } + is_multicast = (is_ip6_discovery(eth_payload, eth_size) || is_ethMulticast(eth_payload, eth_size)); + + if(eee->conf.drop_multicast && is_multicast) { + traceEvent(TRACE_INFO, "Dropping RX multicast"); + return(-1); + } else if((!eee->conf.allow_routing) && (!is_multicast)) { + /* Check if it is a routed packet */ + + if((ntohs(eh->type) == 0x0800) && (eth_size >= ETH_FRAMESIZE + IP4_MIN_SIZE)) { + uint32_t *dst = (uint32_t*)ð_payload[ETH_FRAMESIZE + IP4_DSTOFFSET]; + uint8_t *dst_mac = (uint8_t*)eth_payload; + + /* Note: all elements of the_ip are in network order */ + if(!memcmp(dst_mac, broadcast_mac, N2N_MAC_SIZE)) + traceEvent(TRACE_DEBUG, "Broadcast packet [%s]", + intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); + else if((*dst != eee->device.ip_addr)) { + /* This is a packet that needs to be routed */ + traceEvent(TRACE_INFO, "Discarding routed packet [%s]", + intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); + return(-1); + } else { + /* This packet is directed to us */ + /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ + } + } + } - /* Write ethernet packet to tap device. */ - traceEvent(TRACE_DEBUG, "sending to TAP %u", (unsigned int)eth_size); - data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size); + if(eee->network_traffic_filter->filter_packet_from_peer(eee->network_traffic_filter, eee, orig_sender, + eth_payload, eth_size) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "Filtered packet %u", (unsigned int)eth_size); + return(0); + } - if(data_sent_len == eth_size) { - retval = 0; - } - } else { - traceEvent(TRACE_ERROR, "invalid transop ID: expected %s(%u), got %s(%u) from %s [%s]", - transop_str(eee->conf.transop_id), eee->conf.transop_id, - transop_str(rx_transop_id), rx_transop_id, - sock_to_cstr(sockbuf, orig_sender), - macaddr_str(mac_buf, pkt->srcMac)); + if(eee->cb.packet_from_peer) { + uint16_t tmp_eth_size = eth_size; + if(eee->cb.packet_from_peer(eee, orig_sender, eth_payload, &tmp_eth_size) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)eth_size); + return(0); + } + eth_size = tmp_eth_size; + } + + /* Write ethernet packet to tap device. */ + traceEvent(TRACE_DEBUG, "sending to TAP %u", (unsigned int)eth_size); + data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size); + + if(data_sent_len == eth_size) { + retval = 0; + } + } else { + traceEvent(TRACE_ERROR, "invalid transop ID: expected %s(%u), got %s(%u) from %s [%s]", + transop_str(eee->conf.transop_id), eee->conf.transop_id, + transop_str(rx_transop_id), rx_transop_id, + sock_to_cstr(sockbuf, orig_sender), + macaddr_str(mac_buf, pkt->srcMac)); + } } - } - return retval; + return retval; } /* ************************************** */ @@ -1301,247 +1303,247 @@ static int handle_PACKET (n2n_edge_t * eee, static char *get_ip_from_arp (dec_ip_str_t buf, const n2n_mac_t req_mac) { - FILE *fd; - dec_ip_str_t ip_str = {'\0'}; - char dev_str[N2N_IFNAMSIZ] = {'\0'}; - macstr_t mac_str = {'\0'}; - n2n_mac_t mac = {'\0'}; + FILE *fd; + dec_ip_str_t ip_str = {'\0'}; + char dev_str[N2N_IFNAMSIZ] = {'\0'}; + macstr_t mac_str = {'\0'}; + n2n_mac_t mac = {'\0'}; - strncpy(buf, "0.0.0.0", N2N_NETMASK_STR_SIZE - 1); + strncpy(buf, "0.0.0.0", N2N_NETMASK_STR_SIZE - 1); - if(0 == memcmp(null_mac, req_mac, sizeof(n2n_mac_t))) { - traceEvent(TRACE_DEBUG, "MAC address is null."); - return buf; - } + if(0 == memcmp(null_mac, req_mac, sizeof(n2n_mac_t))) { + traceEvent(TRACE_DEBUG, "MAC address is null."); + return buf; + } - if(!(fd = fopen("/proc/net/arp", "r"))) { - traceEvent(TRACE_ERROR, "Could not open arp table. [%d]: %s", errno, strerror(errno)); - return buf; - } + if(!(fd = fopen("/proc/net/arp", "r"))) { + traceEvent(TRACE_ERROR, "Could not open arp table. [%d]: %s", errno, strerror(errno)); + return buf; + } - while(!feof(fd) && fgetc(fd) != '\n'); - while(!feof(fd) && (fscanf(fd, " %15[0-9.] %*s %*s %17[A-Fa-f0-9:] %*s %15s", ip_str, mac_str, dev_str) == 3)) { - str2mac(mac, mac_str); - if(0 == memcmp(mac, req_mac, sizeof(n2n_mac_t))) { - strncpy(buf, ip_str, N2N_NETMASK_STR_SIZE - 1); - break; + while(!feof(fd) && fgetc(fd) != '\n'); + while(!feof(fd) && (fscanf(fd, " %15[0-9.] %*s %*s %17[A-Fa-f0-9:] %*s %15s", ip_str, mac_str, dev_str) == 3)) { + str2mac(mac, mac_str); + if(0 == memcmp(mac, req_mac, sizeof(n2n_mac_t))) { + strncpy(buf, ip_str, N2N_NETMASK_STR_SIZE - 1); + break; + } } - } - fclose(fd); + fclose(fd); - return buf; + return buf; } #endif /** Read a datagram from the management UDP socket and take appropriate - * action. */ + * action. */ static void readFromMgmtSocket (n2n_edge_t *eee, int *keep_running) { - char udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ - ssize_t recvlen; - /* ssize_t sendlen; */ - struct sockaddr_in sender_sock; - socklen_t i; - size_t msg_len; - time_t now; - struct peer_info *peer, *tmpPeer; - macstr_t mac_buf; - /* dec_ip_bit_str_t ip_bit_str = {'\0'}; */ - /* dec_ip_str_t ip_str = {'\0'}; */ - in_addr_t net; - n2n_sock_str_t sockbuf; - uint32_t num_pending_peers = 0; - uint32_t num_known_peers = 0; - uint32_t num = 0; - selection_criterion_str_t sel_buf; - - - now = time(NULL); - i = sizeof(sender_sock); - recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, - (struct sockaddr *) &sender_sock, (socklen_t *) &i); - - if(recvlen < 0) { - traceEvent(TRACE_ERROR, "mgmt recvfrom failed with %s", strerror(errno)); - return; /* failed to receive data from UDP */ - } - - if((0 == memcmp(udp_buf, "help", 4)) || (0 == memcmp(udp_buf, "?", 1))) { - msg_len = 0; + char udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ + ssize_t recvlen; + /* ssize_t sendlen; */ + struct sockaddr_in sender_sock; + socklen_t i; + size_t msg_len; + time_t now; + struct peer_info *peer, *tmpPeer; + macstr_t mac_buf; + /* dec_ip_bit_str_t ip_bit_str = {'\0'}; */ + /* dec_ip_str_t ip_str = {'\0'}; */ + in_addr_t net; + n2n_sock_str_t sockbuf; + uint32_t num_pending_peers = 0; + uint32_t num_known_peers = 0; + uint32_t num = 0; + selection_criterion_str_t sel_buf; + + + now = time(NULL); + i = sizeof(sender_sock); + recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, + (struct sockaddr *) &sender_sock, (socklen_t *) &i); + + if(recvlen < 0) { + traceEvent(TRACE_ERROR, "mgmt recvfrom failed with %s", strerror(errno)); + return; /* failed to receive data from UDP */ + } - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "Help for edge management console:\n" - "\tstop | Gracefully exit edge\n" - "\thelp | This help message\n" - "\t+verb | Increase verbosity of logging\n" - "\t-verb | Decrease verbosity of logging\n" - "\t | Display statistics\n\n"); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - - return; - } - - if(0 == memcmp(udp_buf, "stop", 4)) { - traceEvent(TRACE_ERROR, "stop command received."); - *keep_running = 0; - return; - } - - if(0 == memcmp(udp_buf, "+verb", 5)) { - msg_len = 0; - setTraceLevel(getTraceLevel() + 1); + if((0 == memcmp(udp_buf, "help", 4)) || (0 == memcmp(udp_buf, "?", 1))) { + msg_len = 0; - traceEvent(TRACE_ERROR, "+verb traceLevel=%u", (unsigned int) getTraceLevel()); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "> +OK traceLevel=%u\n", (unsigned int) getTraceLevel()); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "Help for edge management console:\n" + "\tstop | Gracefully exit edge\n" + "\thelp | This help message\n" + "\t+verb | Increase verbosity of logging\n" + "\t-verb | Decrease verbosity of logging\n" + "\t | Display statistics\n\n"); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - return; - } + return; + } - if(0 == memcmp(udp_buf, "-verb", 5)) { - msg_len = 0; + if(0 == memcmp(udp_buf, "stop", 4)) { + traceEvent(TRACE_ERROR, "stop command received."); + *keep_running = 0; + return; + } + + if(0 == memcmp(udp_buf, "+verb", 5)) { + msg_len = 0; + setTraceLevel(getTraceLevel() + 1); + + traceEvent(TRACE_ERROR, "+verb traceLevel=%u", (unsigned int) getTraceLevel()); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "> +OK traceLevel=%u\n", (unsigned int) getTraceLevel()); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + + return; + } + + if(0 == memcmp(udp_buf, "-verb", 5)) { + msg_len = 0; + + if(getTraceLevel() > 0) { + setTraceLevel(getTraceLevel() - 1); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "> -OK traceLevel=%u\n", getTraceLevel()); + } else { + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "> -NOK traceLevel=%u\n", getTraceLevel()); + } + + traceEvent(TRACE_ERROR, "-verb traceLevel=%u", (unsigned int) getTraceLevel()); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + return; + } + + traceEvent(TRACE_DEBUG, "mgmt status rq"); - if(getTraceLevel() > 0) { - setTraceLevel(getTraceLevel() - 1); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "> -OK traceLevel=%u\n", getTraceLevel()); - } else { - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "> -NOK traceLevel=%u\n", getTraceLevel()); - } - - traceEvent(TRACE_ERROR, "-verb traceLevel=%u", (unsigned int) getTraceLevel()); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - return; - } - - traceEvent(TRACE_DEBUG, "mgmt status rq"); - - msg_len = 0; - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "community: %s\n", - eee->conf.community_name); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - " id tun_tap MAC edge hint last_seen\n"); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "-----------------------------------------------------------------------------------------------\n"); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "supernode_forward:\n"); - num = 0; - HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) { - ++num_pending_peers; - if(peer->dev_addr.net_addr == 0) continue; - net = htonl(peer->dev_addr.net_addr); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - " %-4u %-15s %-17s %-21s %-15s %lu\n", - ++num, inet_ntoa(*(struct in_addr *) &net), - macaddr_str(mac_buf, peer->mac_addr), - sock_to_cstr(sockbuf, &(peer->sock)), - peer->dev_desc, - now - peer->last_seen); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); msg_len = 0; - } - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "peer_to_peer:\n"); - num = 0; - HASH_ITER(hh, eee->known_peers, peer, tmpPeer) { - ++num_known_peers; - if(peer->dev_addr.net_addr == 0) continue; - net = htonl(peer->dev_addr.net_addr); msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - " %-4u %-15s %-17s %-21s %-15s %lu\n", - ++num, inet_ntoa(*(struct in_addr *) &net), - macaddr_str(mac_buf, peer->mac_addr), - sock_to_cstr(sockbuf, &(peer->sock)), - peer->dev_desc, - now - peer->last_seen); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - msg_len = 0; - } + "community: %s\n", + eee->conf.community_name); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + " id tun_tap MAC edge hint last_seen\n"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "-----------------------------------------------------------------------------------------------\n"); - // dump supernodes - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "-----------------------------------------------------------------------------------------------\n"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "supernode_forward:\n"); + num = 0; + HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) { + ++num_pending_peers; + if(peer->dev_addr.net_addr == 0) continue; + net = htonl(peer->dev_addr.net_addr); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + " %-4u %-15s %-17s %-21s %-15s %lu\n", + ++num, inet_ntoa(*(struct in_addr *) &net), + macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + peer->dev_desc, + now - peer->last_seen); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + msg_len = 0; + } - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "supernodes:\n"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "peer_to_peer:\n"); + num = 0; + HASH_ITER(hh, eee->known_peers, peer, tmpPeer) { + ++num_known_peers; + if(peer->dev_addr.net_addr == 0) continue; + net = htonl(peer->dev_addr.net_addr); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + " %-4u %-15s %-17s %-21s %-15s %lu\n", + ++num, inet_ntoa(*(struct in_addr *) &net), + macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + peer->dev_desc, + now - peer->last_seen); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + msg_len = 0; + } - HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) { - net = htonl(peer->dev_addr.net_addr); + // dump supernodes msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - " %-4u %-15s %-17s %-21s %-14s %lu\n", - ++num, - (peer->purgeable == SN_UNPURGEABLE)?"-l ":" ", - macaddr_str(mac_buf, peer->mac_addr), - sock_to_cstr(sockbuf, &(peer->sock)), - sn_selection_criterion_str(sel_buf, peer), - now - peer->last_seen); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - msg_len = 0; - } + "-----------------------------------------------------------------------------------------------\n"); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "supernodes:\n"); + + HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) { + net = htonl(peer->dev_addr.net_addr); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + " %-4u %-15s %-17s %-21s %-14s %lu\n", + ++num, + (peer->purgeable == SN_UNPURGEABLE) ? "-l " : " ", + macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + sn_selection_criterion_str(sel_buf, peer), + now - peer->last_seen); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + msg_len = 0; + } // end dump supernodes - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "-----------------------------------------------------------------------------------------------\n"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "-----------------------------------------------------------------------------------------------\n"); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "uptime %lu | ", - time(NULL) - eee->start_time); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "uptime %lu | ", + time(NULL) - eee->start_time); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "pend_peers %u | ", - num_pending_peers); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "pend_peers %u | ", + num_pending_peers); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "known_peers %u | ", - num_known_peers); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "known_peers %u | ", + num_known_peers); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "transop %u,%u\n", - (unsigned int) eee->transop.tx_cnt, - (unsigned int) eee->transop.rx_cnt); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "transop %u,%u\n", + (unsigned int) eee->transop.tx_cnt, + (unsigned int) eee->transop.rx_cnt); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "super %u,%u | ", - (unsigned int) eee->stats.tx_sup, - (unsigned int) eee->stats.rx_sup); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "super %u,%u | ", + (unsigned int) eee->stats.tx_sup, + (unsigned int) eee->stats.rx_sup); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "p2p %u,%u\n", - (unsigned int) eee->stats.tx_p2p, - (unsigned int) eee->stats.rx_p2p); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "p2p %u,%u\n", + (unsigned int) eee->stats.tx_p2p, + (unsigned int) eee->stats.rx_p2p); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "last_super %ld sec ago | ", - (now - eee->last_sup)); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "last_super %ld sec ago | ", + (now - eee->last_sup)); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "last_p2p %ld sec ago\n", - (now - eee->last_p2p)); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "last_p2p %ld sec ago\n", + (now - eee->last_p2p)); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "\nType \"help\" to see more commands.\n\n"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "\nType \"help\" to see more commands.\n\n"); - /* sendlen = */ sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + /* sendlen = */ sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); } @@ -1549,29 +1551,29 @@ static void readFromMgmtSocket (n2n_edge_t *eee, int *keep_running) { static int check_query_peer_info (n2n_edge_t *eee, time_t now, n2n_mac_t mac) { - struct peer_info *scan; + struct peer_info *scan; - HASH_FIND_PEER(eee->pending_peers, mac, scan); + HASH_FIND_PEER(eee->pending_peers, mac, scan); - if(!scan) { - scan = calloc(1, sizeof(struct peer_info)); + if(!scan) { + scan = calloc(1, sizeof(struct peer_info)); - memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); - scan->timeout = eee->conf.register_interval; /* TODO: should correspond to the peer supernode registration timeout */ - scan->last_seen = now; /* Don't change this it marks the pending peer for removal. */ - scan->last_valid_time_stamp = initial_time_stamp(); + memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); + scan->timeout = eee->conf.register_interval; /* TODO: should correspond to the peer supernode registration timeout */ + scan->last_seen = now; /* Don't change this it marks the pending peer for removal. */ + scan->last_valid_time_stamp = initial_time_stamp(); - HASH_ADD_PEER(eee->pending_peers, scan); - } + HASH_ADD_PEER(eee->pending_peers, scan); + } - if(now - scan->last_sent_query > eee->conf.register_interval) { - send_register(eee, &(eee->supernode), mac); - send_query_peer(eee, scan->mac_addr); - scan->last_sent_query = now; - return(0); - } + if(now - scan->last_sent_query > eee->conf.register_interval) { + send_register(eee, &(eee->supernode), mac); + send_query_peer(eee, scan->mac_addr); + scan->last_sent_query = now; + return(0); + } - return(1); + return(1); } /* ************************************** */ @@ -1581,90 +1583,90 @@ static int find_peer_destination (n2n_edge_t * eee, n2n_mac_t mac_address, n2n_sock_t * destination) { - struct peer_info *scan; - macstr_t mac_buf; - n2n_sock_str_t sockbuf; - int retval = 0; - time_t now = time(NULL); + struct peer_info *scan; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + int retval = 0; + time_t now = time(NULL); - if(!memcmp(mac_address, broadcast_mac, N2N_MAC_SIZE)) { - traceEvent(TRACE_DEBUG, "Broadcast destination peer, using supernode"); - memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in)); - return(0); - } - - traceEvent(TRACE_DEBUG, "Searching destination peer for MAC %02X:%02X:%02X:%02X:%02X:%02X", - mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF, - mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF); - - HASH_FIND_PEER(eee->known_peers, mac_address, scan); - - if(scan && (scan->last_seen > 0)) { - if((now - scan->last_p2p) >= (scan->timeout / 2)) { - /* Too much time passed since we saw the peer, need to register again - * since the peer address may have changed. */ - traceEvent(TRACE_DEBUG, "Refreshing idle known peer"); - HASH_DEL(eee->known_peers, scan); - free(scan); - /* NOTE: registration will be performed upon the receival of the next response packet */ - } else { - /* Valid known peer found */ - memcpy(destination, &scan->sock, sizeof(n2n_sock_t)); - retval = 1; + if(!memcmp(mac_address, broadcast_mac, N2N_MAC_SIZE)) { + traceEvent(TRACE_DEBUG, "Broadcast destination peer, using supernode"); + memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in)); + return(0); } - } - if(retval == 0) { - memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in)); - traceEvent(TRACE_DEBUG, "P2P Peer [MAC=%02X:%02X:%02X:%02X:%02X:%02X] not found, using supernode", + traceEvent(TRACE_DEBUG, "Searching destination peer for MAC %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF, mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF); - check_query_peer_info(eee, now, mac_address); - } + HASH_FIND_PEER(eee->known_peers, mac_address, scan); - traceEvent(TRACE_DEBUG, "find_peer_address (%s) -> [%s]", - macaddr_str(mac_buf, mac_address), - sock_to_cstr(sockbuf, destination)); + if(scan && (scan->last_seen > 0)) { + if((now - scan->last_p2p) >= (scan->timeout / 2)) { + /* Too much time passed since we saw the peer, need to register again + * since the peer address may have changed. */ + traceEvent(TRACE_DEBUG, "Refreshing idle known peer"); + HASH_DEL(eee->known_peers, scan); + free(scan); + /* NOTE: registration will be performed upon the receival of the next response packet */ + } else { + /* Valid known peer found */ + memcpy(destination, &scan->sock, sizeof(n2n_sock_t)); + retval = 1; + } + } + + if(retval == 0) { + memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in)); + traceEvent(TRACE_DEBUG, "P2P Peer [MAC=%02X:%02X:%02X:%02X:%02X:%02X] not found, using supernode", + mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF, + mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF); + + check_query_peer_info(eee, now, mac_address); + } - return retval; + traceEvent(TRACE_DEBUG, "find_peer_address (%s) -> [%s]", + macaddr_str(mac_buf, mac_address), + sock_to_cstr(sockbuf, destination)); + + return retval; } /* ***************************************************** */ /** Send an ecapsulated ethernet PACKET to a destination edge or broadcast MAC - * address. */ + * address. */ static int send_packet (n2n_edge_t * eee, n2n_mac_t dstMac, const uint8_t * pktbuf, size_t pktlen) { - int is_p2p; - /*ssize_t s; */ - n2n_sock_str_t sockbuf; - n2n_sock_t destination; - macstr_t mac_buf; + int is_p2p; + /*ssize_t s; */ + n2n_sock_str_t sockbuf; + n2n_sock_t destination; + macstr_t mac_buf; - /* hexdump(pktbuf, pktlen); */ + /* hexdump(pktbuf, pktlen); */ - is_p2p = find_peer_destination(eee, dstMac, &destination); + is_p2p = find_peer_destination(eee, dstMac, &destination); - if(is_p2p) - ++(eee->stats.tx_p2p); - else { - ++(eee->stats.tx_sup); + if(is_p2p) + ++(eee->stats.tx_p2p); + else { + ++(eee->stats.tx_sup); - if(!memcmp(dstMac, broadcast_mac, N2N_MAC_SIZE)) - ++(eee->stats.tx_sup_broadcast); - } + if(!memcmp(dstMac, broadcast_mac, N2N_MAC_SIZE)) + ++(eee->stats.tx_sup_broadcast); + } - traceEvent(TRACE_INFO, "Tx PACKET to %s (dest=%s) [%u B]", - sock_to_cstr(sockbuf, &destination), - macaddr_str(mac_buf, dstMac), pktlen); + traceEvent(TRACE_INFO, "Tx PACKET to %s (dest=%s) [%u B]", + sock_to_cstr(sockbuf, &destination), + macaddr_str(mac_buf, dstMac), pktlen); - /* s = */ sendto_sock(eee->udp_sock, pktbuf, pktlen, &destination); + /* s = */ sendto_sock(eee->udp_sock, pktbuf, pktlen, &destination); - return 0; + return 0; } /* ************************************** */ @@ -1673,195 +1675,195 @@ static int send_packet (n2n_edge_t * eee, void edge_send_packet2net (n2n_edge_t * eee, uint8_t *tap_pkt, size_t len) { - ipstr_t ip_buf; - n2n_mac_t destMac; - n2n_common_t cmn; - n2n_PACKET_t pkt; - uint8_t pktbuf[N2N_PKT_BUF_SIZE]; - size_t idx = 0; - n2n_transform_t tx_transop_idx = eee->transop.transform_id; - ether_hdr_t eh; - - /* tap_pkt is not aligned so we have to copy to aligned memory */ - memcpy(&eh, tap_pkt, sizeof(ether_hdr_t)); - - /* Discard IP packets that are not originated by this hosts */ - if(!(eee->conf.allow_routing)) { - if(ntohs(eh.type) == 0x0800) { - /* This is an IP packet from the local source address - not forwarded. */ - uint32_t *src = (uint32_t*)&tap_pkt[ETH_FRAMESIZE + IP4_SRCOFFSET]; - - /* Note: all elements of the_ip are in network order */ - if(*src != eee->device.ip_addr) { - /* This is a packet that needs to be routed */ - traceEvent(TRACE_INFO, "Discarding routed packet [%s]", - intoa(ntohl(*src), ip_buf, sizeof(ip_buf))); - return; - } else { - /* This packet is originated by us */ - /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ - } + ipstr_t ip_buf; + n2n_mac_t destMac; + n2n_common_t cmn; + n2n_PACKET_t pkt; + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx = 0; + n2n_transform_t tx_transop_idx = eee->transop.transform_id; + ether_hdr_t eh; + + /* tap_pkt is not aligned so we have to copy to aligned memory */ + memcpy(&eh, tap_pkt, sizeof(ether_hdr_t)); + + /* Discard IP packets that are not originated by this hosts */ + if(!(eee->conf.allow_routing)) { + if(ntohs(eh.type) == 0x0800) { + /* This is an IP packet from the local source address - not forwarded. */ + uint32_t *src = (uint32_t*)&tap_pkt[ETH_FRAMESIZE + IP4_SRCOFFSET]; + + /* Note: all elements of the_ip are in network order */ + if(*src != eee->device.ip_addr) { + /* This is a packet that needs to be routed */ + traceEvent(TRACE_INFO, "Discarding routed packet [%s]", + intoa(ntohl(*src), ip_buf, sizeof(ip_buf))); + return; + } else { + /* This packet is originated by us */ + /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ + } + } } - } - /* Optionally compress then apply transforms, eg encryption. */ + /* Optionally compress then apply transforms, eg encryption. */ - /* Once processed, send to destination in PACKET */ + /* Once processed, send to destination in PACKET */ - memcpy(destMac, tap_pkt, N2N_MAC_SIZE); /* dest MAC is first in ethernet header */ + memcpy(destMac, tap_pkt, N2N_MAC_SIZE); /* dest MAC is first in ethernet header */ - memset(&cmn, 0, sizeof(cmn)); - cmn.ttl = N2N_DEFAULT_TTL; - cmn.pc = n2n_packet; - cmn.flags = 0; /* no options, not from supernode, no socket */ - memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + memset(&cmn, 0, sizeof(cmn)); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_packet; + cmn.flags = 0; /* no options, not from supernode, no socket */ + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - memset(&pkt, 0, sizeof(pkt)); - memcpy(pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); - memcpy(pkt.dstMac, destMac, N2N_MAC_SIZE); + memset(&pkt, 0, sizeof(pkt)); + memcpy(pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); + memcpy(pkt.dstMac, destMac, N2N_MAC_SIZE); - pkt.sock.family = 0; /* do not encode sock */ - pkt.transform = tx_transop_idx; + pkt.sock.family = 0; /* do not encode sock */ + pkt.transform = tx_transop_idx; - // compression needs to be tried before encode_PACKET is called for compression indication gets encoded there - pkt.compression = N2N_COMPRESSION_ID_NONE; + // compression needs to be tried before encode_PACKET is called for compression indication gets encoded there + pkt.compression = N2N_COMPRESSION_ID_NONE; - if(eee->conf.compression) { - uint8_t * compression_buffer = NULL; - int32_t compression_len; + if(eee->conf.compression) { + uint8_t * compression_buffer = NULL; + int32_t compression_len; - switch (eee->conf.compression) { - case N2N_COMPRESSION_ID_LZO: - compression_buffer = malloc (len + len / 16 + 64 + 3); - if(lzo1x_1_compress(tap_pkt, len, compression_buffer, (lzo_uint*)&compression_len, wrkmem) == LZO_E_OK) { - if(compression_len < len) { - pkt.compression = N2N_COMPRESSION_ID_LZO; - } - } - break; + switch (eee->conf.compression) { + case N2N_COMPRESSION_ID_LZO: + compression_buffer = malloc (len + len / 16 + 64 + 3); + if(lzo1x_1_compress(tap_pkt, len, compression_buffer, (lzo_uint*)&compression_len, wrkmem) == LZO_E_OK) { + if(compression_len < len) { + pkt.compression = N2N_COMPRESSION_ID_LZO; + } + } + break; #ifdef N2N_HAVE_ZSTD - case N2N_COMPRESSION_ID_ZSTD: - compression_len = N2N_PKT_BUF_SIZE + 128; - compression_buffer = malloc (compression_len); // leaves enough room, for exact size call compression_len = ZSTD_compressBound (len); (slower) - compression_len = (int32_t)ZSTD_compress(compression_buffer, compression_len, tap_pkt, len, ZSTD_COMPRESSION_LEVEL); - if(!ZSTD_isError(compression_len)) { - if(compression_len < len) { - pkt.compression = N2N_COMPRESSION_ID_ZSTD; - } - } else { - traceEvent (TRACE_ERROR, "payload compression failed with zstd error '%s'.", - ZSTD_getErrorName(compression_len)); - free(compression_buffer); - // continue with unset without pkt.compression --> will send uncompressed - } - break; + case N2N_COMPRESSION_ID_ZSTD: + compression_len = N2N_PKT_BUF_SIZE + 128; + compression_buffer = malloc (compression_len); // leaves enough room, for exact size call compression_len = ZSTD_compressBound (len); (slower) + compression_len = (int32_t)ZSTD_compress(compression_buffer, compression_len, tap_pkt, len, ZSTD_COMPRESSION_LEVEL); + if(!ZSTD_isError(compression_len)) { + if(compression_len < len) { + pkt.compression = N2N_COMPRESSION_ID_ZSTD; + } + } else { + traceEvent(TRACE_ERROR, "payload compression failed with zstd error '%s'.", + ZSTD_getErrorName(compression_len)); + free(compression_buffer); + // continue with unset without pkt.compression --> will send uncompressed + } + break; #endif - default: - break; - } + default: + break; + } - if(pkt.compression != N2N_COMPRESSION_ID_NONE) { - traceEvent (TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n", - compression_str(pkt.compression), len, compression_len); + if(pkt.compression != N2N_COMPRESSION_ID_NONE) { + traceEvent(TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n", + compression_str(pkt.compression), len, compression_len); - memcpy (tap_pkt, compression_buffer, compression_len); - len = compression_len; - } + memcpy(tap_pkt, compression_buffer, compression_len); + len = compression_len; + } - if(compression_buffer) { - free(compression_buffer); + if(compression_buffer) { + free(compression_buffer); + } } - } - idx = 0; - encode_PACKET(pktbuf, &idx, &cmn, &pkt); + idx = 0; + encode_PACKET(pktbuf, &idx, &cmn, &pkt); - uint16_t headerIdx = idx; + uint16_t headerIdx = idx; - idx += eee->transop.fwd(&eee->transop, - pktbuf+idx, N2N_PKT_BUF_SIZE-idx, - tap_pkt, len, pkt.dstMac); + idx += eee->transop.fwd(&eee->transop, + pktbuf + idx, N2N_PKT_BUF_SIZE - idx, + tap_pkt, len, pkt.dstMac); - traceEvent(TRACE_DEBUG, "Encode %u B PACKET [%u B data, %u B overhead] transform %u", - (u_int)idx, (u_int)len, (u_int)(idx-len), tx_transop_idx); + traceEvent(TRACE_DEBUG, "Encode %u B PACKET [%u B data, %u B overhead] transform %u", + (u_int)idx, (u_int)len, (u_int)(idx - len), tx_transop_idx); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) - packet_header_encrypt (pktbuf, headerIdx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, - time_stamp (), pearson_hash_16 (pktbuf, idx)); + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) + packet_header_encrypt(pktbuf, headerIdx, eee->conf.header_encryption_ctx, + eee->conf.header_iv_ctx, + time_stamp(), pearson_hash_16(pktbuf, idx)); #ifdef MTU_ASSERT_VALUE - { - const u_int eth_udp_overhead = ETH_FRAMESIZE + IP4_MIN_SIZE + UDP_SIZE; + { + const u_int eth_udp_overhead = ETH_FRAMESIZE + IP4_MIN_SIZE + UDP_SIZE; - // MTU assertion which avoids fragmentation by N2N - assert(idx + eth_udp_overhead <= MTU_ASSERT_VALUE); - } + // MTU assertion which avoids fragmentation by N2N + assert(idx + eth_udp_overhead <= MTU_ASSERT_VALUE); + } #endif - eee->transop.tx_cnt++; /* stats */ + eee->transop.tx_cnt++; /* stats */ - send_packet(eee, destMac, pktbuf, idx); /* to peer or supernode */ + send_packet(eee, destMac, pktbuf, idx); /* to peer or supernode */ } /* ************************************** */ /** Read a single packet from the TAP interface, process it and write out the - * corresponding packet to the cooked socket. + * corresponding packet to the cooked socket. */ void edge_read_from_tap (n2n_edge_t * eee) { - /* tun -> remote */ - uint8_t eth_pkt[N2N_PKT_BUF_SIZE]; - macstr_t mac_buf; - ssize_t len; - - len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE ); - if((len <= 0) || (len > N2N_PKT_BUF_SIZE)) { - traceEvent(TRACE_WARNING, "read()=%d [%d/%s]", - (signed int)len, errno, strerror(errno)); - traceEvent(TRACE_WARNING, "TAP I/O operation aborted, restart later."); - sleep(3); - tuntap_close(&(eee->device)); - tuntap_open(&(eee->device), eee->tuntap_priv_conf.tuntap_dev_name, eee->tuntap_priv_conf.ip_mode, eee->tuntap_priv_conf.ip_addr, - eee->tuntap_priv_conf.netmask, eee->tuntap_priv_conf.device_mac, eee->tuntap_priv_conf.mtu); - } else { - const uint8_t * mac = eth_pkt; - traceEvent(TRACE_DEBUG, "### Rx TAP packet (%4d) for %s", - (signed int)len, macaddr_str(mac_buf, mac)); - - if(eee->conf.drop_multicast && - (is_ip6_discovery(eth_pkt, len) || - is_ethMulticast(eth_pkt, len))) { - traceEvent(TRACE_INFO, "Dropping TX multicast"); + /* tun -> remote */ + uint8_t eth_pkt[N2N_PKT_BUF_SIZE]; + macstr_t mac_buf; + ssize_t len; + + len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE ); + if((len <= 0) || (len > N2N_PKT_BUF_SIZE)) { + traceEvent(TRACE_WARNING, "read()=%d [%d/%s]", + (signed int)len, errno, strerror(errno)); + traceEvent(TRACE_WARNING, "TAP I/O operation aborted, restart later."); + sleep(3); + tuntap_close(&(eee->device)); + tuntap_open(&(eee->device), eee->tuntap_priv_conf.tuntap_dev_name, eee->tuntap_priv_conf.ip_mode, eee->tuntap_priv_conf.ip_addr, + eee->tuntap_priv_conf.netmask, eee->tuntap_priv_conf.device_mac, eee->tuntap_priv_conf.mtu); } else { - if(eee->network_traffic_filter) { - if(eee->network_traffic_filter->filter_packet_from_tap(eee->network_traffic_filter, eee, eth_pkt, - len) == N2N_DROP) { - traceEvent(TRACE_DEBUG, "Filtered packet %u", (unsigned int)len); - return; - } - } + const uint8_t * mac = eth_pkt; + traceEvent(TRACE_DEBUG, "### Rx TAP packet (%4d) for %s", + (signed int)len, macaddr_str(mac_buf, mac)); + + if(eee->conf.drop_multicast && + (is_ip6_discovery(eth_pkt, len) || + is_ethMulticast(eth_pkt, len))) { + traceEvent(TRACE_INFO, "Dropping TX multicast"); + } else { + if(eee->network_traffic_filter) { + if(eee->network_traffic_filter->filter_packet_from_tap(eee->network_traffic_filter, eee, eth_pkt, + len) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "Filtered packet %u", (unsigned int)len); + return; + } + } - if(eee->cb.packet_from_tap) { - uint16_t tmp_len = len; - if(eee->cb.packet_from_tap(eee, eth_pkt, &tmp_len) == N2N_DROP) { - traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)len); + if(eee->cb.packet_from_tap) { + uint16_t tmp_len = len; + if(eee->cb.packet_from_tap(eee, eth_pkt, &tmp_len) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)len); - return; - } - len = tmp_len; - } + return; + } + len = tmp_len; + } - if(!eee->last_sup) { - // drop packets before first registration with supernode - traceEvent(TRACE_DEBUG, "DROP packet before first registration with supernode"); - return; - } + if(!eee->last_sup) { + // drop packets before first registration with supernode + traceEvent(TRACE_DEBUG, "DROP packet before first registration with supernode"); + return; + } - edge_send_packet2net(eee, eth_pkt, len); - } - } + edge_send_packet2net(eee, eth_pkt, len); + } + } } /* ************************************** */ @@ -1869,560 +1871,560 @@ void edge_read_from_tap (n2n_edge_t * eee) { /** Read a datagram from the main UDP socket to the internet. */ void readFromIPSocket (n2n_edge_t * eee, int in_sock) { - n2n_common_t cmn; /* common fields in the packet header */ - n2n_sock_str_t sockbuf1; - n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */ - macstr_t mac_buf1; - macstr_t mac_buf2; - uint8_t udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ - ssize_t recvlen; - size_t rem; - size_t idx; - size_t msg_type; - uint8_t from_supernode; - struct sockaddr_in sender_sock; - n2n_sock_t sender; - n2n_sock_t * orig_sender = NULL; - time_t now = 0; - uint64_t stamp = 0; - size_t i; - - i = sizeof(sender_sock); - recvlen = recvfrom(in_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, - (struct sockaddr *)&sender_sock, (socklen_t*)&i); - - if(recvlen < 0) { + n2n_common_t cmn; /* common fields in the packet header */ + n2n_sock_str_t sockbuf1; + n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */ + macstr_t mac_buf1; + macstr_t mac_buf2; + uint8_t udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ + ssize_t recvlen; + size_t rem; + size_t idx; + size_t msg_type; + uint8_t from_supernode; + struct sockaddr_in sender_sock; + n2n_sock_t sender; + n2n_sock_t * orig_sender = NULL; + time_t now = 0; + uint64_t stamp = 0; + size_t i; + + i = sizeof(sender_sock); + recvlen = recvfrom(in_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t*)&i); + + if(recvlen < 0) { #ifdef WIN32 - if(WSAGetLastError() != WSAECONNRESET) + if(WSAGetLastError() != WSAECONNRESET) #endif - { - traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", recvlen, errno, strerror(errno)); + { + traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", recvlen, errno, strerror(errno)); #ifdef WIN32 - traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); + traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); #endif - } - - return; /* failed to receive data from UDP */ - } - - /* REVISIT: when UDP/IPv6 is supported we will need a flag to indicate which - * IP transport version the packet arrived on. May need to UDP sockets. */ - - memset(&sender, 0, sizeof(n2n_sock_t)); - - sender.family = AF_INET; /* UDP socket was opened PF_INET v4 */ - sender.port = ntohs(sender_sock.sin_port); - memcpy(&(sender.addr.v4), &(sender_sock.sin_addr.s_addr), IPV4_SIZE); - - /* The packet may not have an orig_sender socket spec. So default to last - * hop as sender. */ - orig_sender = &sender; - - traceEvent(TRACE_DEBUG, "### Rx N2N UDP (%d) from %s", - (signed int)recvlen, sock_to_cstr(sockbuf1, &sender)); - - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { - uint16_t checksum = 0; - if(packet_header_decrypt(udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, - &stamp, &checksum) == 0) { - traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header."); - return; - } - - // time stamp verification follows in the packet specific section as it requires to determine the - // sender from the hash list by its MAC, or the packet might be from the supernode, this all depends - // on packet type, path taken (via supernode) and packet structure (MAC is not always in the same place) + } - if(checksum != pearson_hash_16(udp_buf, recvlen)) { - traceEvent(TRACE_DEBUG, "readFromIPSocket dropped packet due to checksum error."); - return; + return; /* failed to receive data from UDP */ } - } - rem = recvlen; /* Counts down bytes of packet to protect against buffer overruns. */ - idx = 0; /* marches through packet header as parts are decoded. */ - if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) { - traceEvent(TRACE_ERROR, "Failed to decode common section in N2N_UDP"); - return; /* failed to decode packet */ - } + /* REVISIT: when UDP/IPv6 is supported we will need a flag to indicate which + * IP transport version the packet arrived on. May need to UDP sockets. */ - now = time(NULL); + memset(&sender, 0, sizeof(n2n_sock_t)); - msg_type = cmn.pc; /* packet code */ - from_supernode = cmn.flags & N2N_FLAGS_FROM_SUPERNODE; + sender.family = AF_INET; /* UDP socket was opened PF_INET v4 */ + sender.port = ntohs(sender_sock.sin_port); + memcpy(&(sender.addr.v4), &(sender_sock.sin_addr.s_addr), IPV4_SIZE); - if(0 == memcmp(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE)) { - switch(msg_type) { - case MSG_TYPE_PACKET: { - /* process PACKET - most frequent so first in list. */ - n2n_PACKET_t pkt; + /* The packet may not have an orig_sender socket spec. So default to last + * hop as sender. */ + orig_sender = &sender; - decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); + traceEvent(TRACE_DEBUG, "### Rx N2N UDP (%d) from %s", + (signed int)recvlen, sock_to_cstr(sockbuf1, &sender)); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_peer_time_stamp_and_verify (eee, from_supernode, pkt.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) { - traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PACKET due to time stamp error."); + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + uint16_t checksum = 0; + if(packet_header_decrypt(udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx, + eee->conf.header_iv_ctx, + &stamp, &checksum) == 0) { + traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header."); return; - } - } - - if(!eee->last_sup) { - // drop packets received before first registration with supernode - traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PACKET recevied before first registration with supernode."); - return; - } - - if(is_valid_peer_sock(&pkt.sock)) - orig_sender = &(pkt.sock); - - if(!from_supernode) { - /* This is a P2P packet from the peer. We purge a pending - * registration towards the possibly nat-ted peer address as we now have - * a valid channel. We still use check_peer_registration_needed in - * handle_PACKET to double check this. - */ - traceEvent(TRACE_DEBUG, "Got P2P packet"); - traceEvent(TRACE_DEBUG, "[P2P] Rx data from %s [%u B]", sock_to_cstr(sockbuf1, &sender), recvlen); - find_and_remove_peer(&eee->pending_peers, pkt.srcMac); - } else { - /* [PsP] : edge Peer->Supernode->edge Peer */ - traceEvent(TRACE_DEBUG, "[PsP] Rx data from %s (Via=%s) [%u B]", - sock_to_cstr(sockbuf2, orig_sender), sock_to_cstr(sockbuf1, &sender), recvlen); } - /* Update the sender in peer table entry */ - check_peer_registration_needed(eee, from_supernode, pkt.srcMac, NULL, NULL, orig_sender); + // time stamp verification follows in the packet specific section as it requires to determine the + // sender from the hash list by its MAC, or the packet might be from the supernode, this all depends + // on packet type, path taken (via supernode) and packet structure (MAC is not always in the same place) - handle_PACKET(eee, from_supernode, &pkt, orig_sender, udp_buf + idx, recvlen - idx); - break; - } - - case MSG_TYPE_REGISTER: { - /* Another edge is registering with us */ - n2n_REGISTER_t reg; - int via_multicast; - - decode_REGISTER(®, &cmn, udp_buf, &rem, &idx); - - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_peer_time_stamp_and_verify (eee, from_supernode, reg.srcMac, stamp, TIME_STAMP_NO_JITTER)) { - traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER due to time stamp error."); + if(checksum != pearson_hash_16(udp_buf, recvlen)) { + traceEvent(TRACE_DEBUG, "readFromIPSocket dropped packet due to checksum error."); return; - } } + } - if(is_valid_peer_sock(®.sock)) - orig_sender = &(reg.sock); - - via_multicast = !memcmp(reg.dstMac, null_mac, N2N_MAC_SIZE); + rem = recvlen; /* Counts down bytes of packet to protect against buffer overruns. */ + idx = 0; /* marches through packet header as parts are decoded. */ + if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) { + traceEvent(TRACE_ERROR, "Failed to decode common section in N2N_UDP"); + return; /* failed to decode packet */ + } - if(via_multicast && !memcmp(reg.srcMac, eee->device.mac_addr, N2N_MAC_SIZE)) { - traceEvent(TRACE_DEBUG, "Skipping REGISTER from self"); - break; - } + now = time(NULL); - if(!via_multicast && memcmp(reg.dstMac, eee->device.mac_addr, N2N_MAC_SIZE)) { - traceEvent(TRACE_DEBUG, "Skipping REGISTER for other peer"); - break; - } + msg_type = cmn.pc; /* packet code */ + from_supernode = cmn.flags & N2N_FLAGS_FROM_SUPERNODE; - if(!from_supernode) { - /* This is a P2P registration from the peer. We purge a pending - * registration towards the possibly nat-ted peer address as we now have - * a valid channel. We still use check_peer_registration_needed below - * to double check this. - */ - traceEvent(TRACE_DEBUG, "Got P2P register"); - traceEvent(TRACE_INFO, "[P2P] Rx REGISTER from %s", sock_to_cstr(sockbuf1, &sender)); - find_and_remove_peer(&eee->pending_peers, reg.srcMac); - - /* NOTE: only ACK to peers */ - send_register_ack(eee, orig_sender, ®); - } else { - traceEvent(TRACE_INFO, "[PsP] Rx REGISTER src=%s dst=%s from sn=%s (edge:%s)", - macaddr_str(mac_buf1, reg.srcMac), macaddr_str(mac_buf2, reg.dstMac), - sock_to_cstr(sockbuf1, &sender), sock_to_cstr(sockbuf2, orig_sender)); - } + if(0 == memcmp(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE)) { + switch(msg_type) { + case MSG_TYPE_PACKET: { + /* process PACKET - most frequent so first in list. */ + n2n_PACKET_t pkt; - check_peer_registration_needed(eee, from_supernode, reg.srcMac, ®.dev_addr, (const n2n_desc_t*)®.dev_desc, orig_sender); - break; - } + decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); - case MSG_TYPE_REGISTER_ACK: { - /* Peer edge is acknowledging our register request */ - n2n_REGISTER_ACK_t ra; + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify (eee, from_supernode, pkt.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) { + traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PACKET due to time stamp error."); + return; + } + } - decode_REGISTER_ACK(&ra, &cmn, udp_buf, &rem, &idx); + if(!eee->last_sup) { + // drop packets received before first registration with supernode + traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PACKET recevied before first registration with supernode."); + return; + } - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_peer_time_stamp_and_verify (eee, !definitely_from_supernode, ra.srcMac, stamp, TIME_STAMP_NO_JITTER)) { - traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER_ACK due to time stamp error."); - return; - } - } + if(is_valid_peer_sock(&pkt.sock)) + orig_sender = &(pkt.sock); + + if(!from_supernode) { + /* This is a P2P packet from the peer. We purge a pending + * registration towards the possibly nat-ted peer address as we now have + * a valid channel. We still use check_peer_registration_needed in + * handle_PACKET to double check this. + */ + traceEvent(TRACE_DEBUG, "Got P2P packet"); + traceEvent(TRACE_DEBUG, "[P2P] Rx data from %s [%u B]", sock_to_cstr(sockbuf1, &sender), recvlen); + find_and_remove_peer(&eee->pending_peers, pkt.srcMac); + } else { + /* [PsP] : edge Peer->Supernode->edge Peer */ + traceEvent(TRACE_DEBUG, "[PsP] Rx data from %s (Via=%s) [%u B]", + sock_to_cstr(sockbuf2, orig_sender), sock_to_cstr(sockbuf1, &sender), recvlen); + } - if(is_valid_peer_sock(&ra.sock)) - orig_sender = &(ra.sock); + /* Update the sender in peer table entry */ + check_peer_registration_needed(eee, from_supernode, pkt.srcMac, NULL, NULL, orig_sender); - traceEvent(TRACE_INFO, "Rx REGISTER_ACK src=%s dst=%s from peer %s (%s)", - macaddr_str(mac_buf1, ra.srcMac), - macaddr_str(mac_buf2, ra.dstMac), - sock_to_cstr(sockbuf1, &sender), - sock_to_cstr(sockbuf2, orig_sender)); + handle_PACKET(eee, from_supernode, &pkt, orig_sender, udp_buf + idx, recvlen - idx); + break; + } - peer_set_p2p_confirmed(eee, ra.srcMac, &sender, now); - break; - } - - case MSG_TYPE_REGISTER_SUPER_ACK: { - in_addr_t net; - char * ip_str = NULL; - n2n_REGISTER_SUPER_ACK_t ra; - uint8_t tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; - n2n_REGISTER_SUPER_ACK_payload_t *payload; - int i; - int skip_add; - struct peer_info *sn; - - memset(&ra, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); - - // Indicates successful connection between the edge and SN nodes - static int bTrace = 1; - if(bTrace) { - traceEvent(TRACE_NORMAL, "[OK] Edge Peer <<< ================ >>> Super Node"); - bTrace = 0; - } + case MSG_TYPE_REGISTER: { + /* Another edge is registering with us */ + n2n_REGISTER_t reg; + int via_multicast; - if(eee->sn_wait) { - decode_REGISTER_SUPER_ACK(&ra, &cmn, udp_buf, &rem, &idx, tmpbuf); + decode_REGISTER(®, &cmn, udp_buf, &rem, &idx); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_peer_time_stamp_and_verify (eee, definitely_from_supernode, null_mac, stamp, TIME_STAMP_NO_JITTER)) { - traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER_SUPER_ACK due to time stamp error."); - return; - } - } + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify (eee, from_supernode, reg.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER due to time stamp error."); + return; + } + } - if(is_valid_peer_sock(&ra.sock)) - orig_sender = &(ra.sock); + if(is_valid_peer_sock(®.sock)) + orig_sender = &(reg.sock); - traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s). Attempts %u", - macaddr_str(mac_buf1, ra.edgeMac), - sock_to_cstr(sockbuf1, &sender), - sock_to_cstr(sockbuf2, orig_sender), - (unsigned int)eee->sup_attempts); + via_multicast = !memcmp(reg.dstMac, null_mac, N2N_MAC_SIZE); - if(memcmp(ra.edgeMac, eee->device.mac_addr, N2N_MAC_SIZE)) { - traceEvent(TRACE_INFO, "readFromIPSocket dropped REGISTER_SUPER_ACK due to wrong addressing."); - return; - } - - if(0 == memcmp(ra.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE)) { - payload = (n2n_REGISTER_SUPER_ACK_payload_t*)tmpbuf; - - for(i = 0; i < ra.num_sn; i++) { - skip_add = SN_ADD; - sn = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &(payload->sock), &(payload->mac), &skip_add); - - if(skip_add == SN_ADD_ADDED) { - sn->ip_addr = calloc(1,N2N_EDGE_SN_HOST_SIZE); - if(sn->ip_addr != NULL) { - inet_ntop(payload->sock.family, - (payload->sock.family == AF_INET)?(void*)&(payload->sock.addr.v4):(void*)&(payload->sock.addr.v6), - sn->ip_addr, N2N_EDGE_SN_HOST_SIZE-1); - sprintf (sn->ip_addr, "%s:%u", sn->ip_addr, (uint16_t)(payload->sock.port)); + if(via_multicast && !memcmp(reg.srcMac, eee->device.mac_addr, N2N_MAC_SIZE)) { + traceEvent(TRACE_DEBUG, "Skipping REGISTER from self"); + break; } - sn_selection_criterion_default(&(sn->selection_criterion)); - sn->last_seen = now - LAST_SEEN_SN_NEW; - sn->last_valid_time_stamp = initial_time_stamp(); - traceEvent(TRACE_NORMAL, "Supernode '%s' added to the list of supernodes.", sn->ip_addr); - } - // shfiting to the next payload entry - payload++; - } - if(eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_SN_ASSIGN) { - if((ra.dev_addr.net_addr != 0) && (ra.dev_addr.net_bitlen != 0)) { - net = htonl(ra.dev_addr.net_addr); - if((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) { - strncpy(eee->tuntap_priv_conf.ip_addr, ip_str, - N2N_NETMASK_STR_SIZE); + if(!via_multicast && memcmp(reg.dstMac, eee->device.mac_addr, N2N_MAC_SIZE)) { + traceEvent(TRACE_DEBUG, "Skipping REGISTER for other peer"); + break; } - net = htonl(bitlen2mask(ra.dev_addr.net_bitlen)); - if((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) { - strncpy(eee->tuntap_priv_conf.netmask, ip_str, - N2N_NETMASK_STR_SIZE); + + if(!from_supernode) { + /* This is a P2P registration from the peer. We purge a pending + * registration towards the possibly nat-ted peer address as we now have + * a valid channel. We still use check_peer_registration_needed below + * to double check this. + */ + traceEvent(TRACE_DEBUG, "Got P2P register"); + traceEvent(TRACE_INFO, "[P2P] Rx REGISTER from %s", sock_to_cstr(sockbuf1, &sender)); + find_and_remove_peer(&eee->pending_peers, reg.srcMac); + + /* NOTE: only ACK to peers */ + send_register_ack(eee, orig_sender, ®); + } else { + traceEvent(TRACE_INFO, "[PsP] Rx REGISTER src=%s dst=%s from sn=%s (edge:%s)", + macaddr_str(mac_buf1, reg.srcMac), macaddr_str(mac_buf2, reg.dstMac), + sock_to_cstr(sockbuf1, &sender), sock_to_cstr(sockbuf2, orig_sender)); } - } - } - if(!eee->last_sup) // send gratuitous ARP only upon first registration with supernode - send_grat_arps(eee); + check_peer_registration_needed(eee, from_supernode, reg.srcMac, ®.dev_addr, (const n2n_desc_t*)®.dev_desc, orig_sender); + break; + } - eee->last_sup = now; - eee->sn_wait = 0; - eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */ + case MSG_TYPE_REGISTER_ACK: { + /* Peer edge is acknowledging our register request */ + n2n_REGISTER_ACK_t ra; - if(eee->cb.sn_registration_updated) - eee->cb.sn_registration_updated(eee, now, &sender); + decode_REGISTER_ACK(&ra, &cmn, udp_buf, &rem, &idx); - /* NOTE: the register_interval should be chosen by the edge node - * based on its NAT configuration. */ - //eee->conf.register_interval = ra.lifetime; + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify (eee, !definitely_from_supernode, ra.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER_ACK due to time stamp error."); + return; + } + } - } else { - traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old cookie."); - } + if(is_valid_peer_sock(&ra.sock)) + orig_sender = &(ra.sock); - } else { - traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with no outstanding REGISTER_SUPER."); - } - break; - } + traceEvent(TRACE_INFO, "Rx REGISTER_ACK src=%s dst=%s from peer %s (%s)", + macaddr_str(mac_buf1, ra.srcMac), + macaddr_str(mac_buf2, ra.dstMac), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender)); - case MSG_TYPE_REGISTER_SUPER_NAK: { + peer_set_p2p_confirmed(eee, ra.srcMac, &sender, now); + break; + } - n2n_REGISTER_SUPER_NAK_t nak; - struct peer_info *peer, *scan; + case MSG_TYPE_REGISTER_SUPER_ACK: { + in_addr_t net; + char * ip_str = NULL; + n2n_REGISTER_SUPER_ACK_t ra; + uint8_t tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; + n2n_REGISTER_SUPER_ACK_payload_t *payload; + int i; + int skip_add; + struct peer_info *sn; + + memset(&ra, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); + + // Indicates successful connection between the edge and SN nodes + static int bTrace = 1; + if(bTrace) { + traceEvent(TRACE_NORMAL, "[OK] Edge Peer <<< ================ >>> Super Node"); + bTrace = 0; + } - memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + if(eee->sn_wait) { + decode_REGISTER_SUPER_ACK(&ra, &cmn, udp_buf, &rem, &idx, tmpbuf); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify (eee, definitely_from_supernode, null_mac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "readFromIPSocket dropped REGISTER_SUPER_ACK due to time stamp error."); + return; + } + } + + if(is_valid_peer_sock(&ra.sock)) + orig_sender = &(ra.sock); + + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s). Attempts %u", + macaddr_str(mac_buf1, ra.edgeMac), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender), + (unsigned int)eee->sup_attempts); + + if(memcmp(ra.edgeMac, eee->device.mac_addr, N2N_MAC_SIZE)) { + traceEvent(TRACE_INFO, "readFromIPSocket dropped REGISTER_SUPER_ACK due to wrong addressing."); + return; + } + + if(0 == memcmp(ra.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE)) { + payload = (n2n_REGISTER_SUPER_ACK_payload_t*)tmpbuf; + + for(i = 0; i < ra.num_sn; i++) { + skip_add = SN_ADD; + sn = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &(payload->sock), &(payload->mac), &skip_add); + + if(skip_add == SN_ADD_ADDED) { + sn->ip_addr = calloc(1,N2N_EDGE_SN_HOST_SIZE); + if(sn->ip_addr != NULL) { + inet_ntop(payload->sock.family, + (payload->sock.family == AF_INET) ? (void*)&(payload->sock.addr.v4) : (void*)&(payload->sock.addr.v6), + sn->ip_addr, N2N_EDGE_SN_HOST_SIZE - 1); + sprintf (sn->ip_addr, "%s:%u", sn->ip_addr, (uint16_t)(payload->sock.port)); + } + sn_selection_criterion_default(&(sn->selection_criterion)); + sn->last_seen = now - LAST_SEEN_SN_NEW; + sn->last_valid_time_stamp = initial_time_stamp(); + traceEvent(TRACE_NORMAL, "Supernode '%s' added to the list of supernodes.", sn->ip_addr); + } + // shfiting to the next payload entry + payload++; + } + + if(eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_SN_ASSIGN) { + if((ra.dev_addr.net_addr != 0) && (ra.dev_addr.net_bitlen != 0)) { + net = htonl(ra.dev_addr.net_addr); + if((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) { + strncpy(eee->tuntap_priv_conf.ip_addr, ip_str, + N2N_NETMASK_STR_SIZE); + } + net = htonl(bitlen2mask(ra.dev_addr.net_bitlen)); + if((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) { + strncpy(eee->tuntap_priv_conf.netmask, ip_str, + N2N_NETMASK_STR_SIZE); + } + } + } + + if(!eee->last_sup) // send gratuitous ARP only upon first registration with supernode + send_grat_arps(eee); + + eee->last_sup = now; + eee->sn_wait = 0; + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */ + + if(eee->cb.sn_registration_updated) + eee->cb.sn_registration_updated(eee, now, &sender); + + /* NOTE: the register_interval should be chosen by the edge node + * based on its NAT configuration. */ + //eee->conf.register_interval = ra.lifetime; + + } else { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old cookie."); + } + + } else { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with no outstanding REGISTER_SUPER."); + } + break; + } - decode_REGISTER_SUPER_NAK(&nak, &cmn, udp_buf, &rem, &idx); - traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_NAK"); + case MSG_TYPE_REGISTER_SUPER_NAK: { - if((memcmp(&(nak.srcMac), &(eee->device.mac_addr), sizeof(n2n_mac_t))) == 0) { - traceEvent(TRACE_ERROR, "%s is already used. Stopping the program.", macaddr_str(mac_buf1, nak.srcMac)); - exit(1); - } else { - HASH_FIND_PEER(eee->known_peers, nak.srcMac, peer); - if(peer != NULL) { - HASH_DEL(eee->known_peers, peer); - } - HASH_FIND_PEER(eee->pending_peers, nak.srcMac, scan); - if(scan != NULL) { - HASH_DEL(eee->pending_peers, scan); - } - } - break; - } + n2n_REGISTER_SUPER_NAK_t nak; + struct peer_info *peer, *scan; - case MSG_TYPE_PEER_INFO: { + memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); - n2n_PEER_INFO_t pi; - struct peer_info * scan; - int skip_add; - SN_SELECTION_CRITERION_DATA_TYPE data; + decode_REGISTER_SUPER_NAK(&nak, &cmn, udp_buf, &rem, &idx); + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_NAK"); - decode_PEER_INFO(&pi, &cmn, udp_buf, &rem, &idx); + if((memcmp(&(nak.srcMac), &(eee->device.mac_addr), sizeof(n2n_mac_t))) == 0) { + traceEvent(TRACE_ERROR, "%s is already used. Stopping the program.", macaddr_str(mac_buf1, nak.srcMac)); + exit(1); + } else { + HASH_FIND_PEER(eee->known_peers, nak.srcMac, peer); + if(peer != NULL) { + HASH_DEL(eee->known_peers, peer); + } + HASH_FIND_PEER(eee->pending_peers, nak.srcMac, scan); + if(scan != NULL) { + HASH_DEL(eee->pending_peers, scan); + } + } + break; + } - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_peer_time_stamp_and_verify (eee, definitely_from_supernode, null_mac, stamp, TIME_STAMP_ALLOW_JITTER)) { - traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PEER_INFO due to time stamp error."); - return; - } - } + case MSG_TYPE_PEER_INFO: { - if(!is_valid_peer_sock(&pi.sock)) { - traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]", - sock_to_cstr(sockbuf1, &pi.sock), - macaddr_str(mac_buf1, pi.mac) ); - break; - } + n2n_PEER_INFO_t pi; + struct peer_info * scan; + int skip_add; + SN_SELECTION_CRITERION_DATA_TYPE data; - if(memcmp(pi.mac, null_mac, sizeof(n2n_mac_t)) == 0) { - skip_add = SN_ADD_SKIP; - scan = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &sender, &pi.srcMac, &skip_add); - if(scan != NULL) { - scan->last_seen = now; - /* The data type depends on the actual selection strategy that has been chosen. */ - sn_selection_criterion_calculate(eee, scan, &pi.data); - break; - } - } else { - HASH_FIND_PEER(eee->pending_peers, pi.mac, scan); + decode_PEER_INFO(&pi, &cmn, udp_buf, &rem, &idx); - if(scan) { - scan->sock = pi.sock; - traceEvent(TRACE_INFO, "Rx PEER_INFO for %s: is at %s", - macaddr_str(mac_buf1, pi.mac), - sock_to_cstr(sockbuf1, &pi.sock)); + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify (eee, definitely_from_supernode, null_mac, stamp, TIME_STAMP_ALLOW_JITTER)) { + traceEvent(TRACE_DEBUG, "readFromIPSocket dropped PEER_INFO due to time stamp error."); + return; + } + } - send_register(eee, &scan->sock, scan->mac_addr); + if(!is_valid_peer_sock(&pi.sock)) { + traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]", + sock_to_cstr(sockbuf1, &pi.sock), + macaddr_str(mac_buf1, pi.mac)); + break; + } - } else { - traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s", - macaddr_str(mac_buf1, pi.mac) ); - } - } - break; - } + if(memcmp(pi.mac, null_mac, sizeof(n2n_mac_t)) == 0) { + skip_add = SN_ADD_SKIP; + scan = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &sender, &pi.srcMac, &skip_add); + if(scan != NULL) { + scan->last_seen = now; + /* The data type depends on the actual selection strategy that has been chosen. */ + sn_selection_criterion_calculate(eee, scan, &pi.data); + break; + } + } else { + HASH_FIND_PEER(eee->pending_peers, pi.mac, scan); + + if(scan) { + scan->sock = pi.sock; + traceEvent(TRACE_INFO, "Rx PEER_INFO for %s: is at %s", + macaddr_str(mac_buf1, pi.mac), + sock_to_cstr(sockbuf1, &pi.sock)); + + send_register(eee, &scan->sock, scan->mac_addr); + + } else { + traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s", + macaddr_str(mac_buf1, pi.mac)); + } + } + break; + } - default: - /* Not a known message type */ - traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type); - return; - } /* switch(msg_type) */ - } else if(from_supernode) /* if(community match) */ - traceEvent(TRACE_WARNING, "Received packet with unknown community"); - else - traceEvent(TRACE_INFO, "Ignoring packet with unknown community"); + default: + /* Not a known message type */ + traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type); + return; + } /* switch(msg_type) */ + } else if(from_supernode) /* if(community match) */ + traceEvent(TRACE_WARNING, "Received packet with unknown community"); + else + traceEvent(TRACE_INFO, "Ignoring packet with unknown community"); } /* ************************************** */ void print_edge_stats (const n2n_edge_t *eee) { - const struct n2n_edge_stats *s = &eee->stats; + const struct n2n_edge_stats *s = &eee->stats; - traceEvent(TRACE_NORMAL, "**********************************"); - traceEvent(TRACE_NORMAL, "Packet stats:"); - traceEvent(TRACE_NORMAL, " TX P2P: %u pkts", s->tx_p2p); - traceEvent(TRACE_NORMAL, " RX P2P: %u pkts", s->rx_p2p); - traceEvent(TRACE_NORMAL, " TX Supernode: %u pkts (%u broadcast)", s->tx_sup, s->tx_sup_broadcast); - traceEvent(TRACE_NORMAL, " RX Supernode: %u pkts (%u broadcast)", s->rx_sup, s->rx_sup_broadcast); - traceEvent(TRACE_NORMAL, "**********************************"); + traceEvent(TRACE_NORMAL, "**********************************"); + traceEvent(TRACE_NORMAL, "Packet stats:"); + traceEvent(TRACE_NORMAL, " TX P2P: %u pkts", s->tx_p2p); + traceEvent(TRACE_NORMAL, " RX P2P: %u pkts", s->rx_p2p); + traceEvent(TRACE_NORMAL, " TX Supernode: %u pkts (%u broadcast)", s->tx_sup, s->tx_sup_broadcast); + traceEvent(TRACE_NORMAL, " RX Supernode: %u pkts (%u broadcast)", s->rx_sup, s->rx_sup_broadcast); + traceEvent(TRACE_NORMAL, "**********************************"); } /* ************************************** */ int run_edge_loop (n2n_edge_t * eee, int *keep_running) { - size_t numPurged; - time_t lastIfaceCheck = 0; - time_t lastTransop = 0; - time_t last_purge_known = 0; - time_t last_purge_pending = 0; + size_t numPurged; + time_t lastIfaceCheck = 0; + time_t lastTransop = 0; + time_t last_purge_known = 0; + time_t last_purge_pending = 0; #ifdef WIN32 - struct tunread_arg arg; - arg.eee = eee; - arg.keep_running = keep_running; - HANDLE tun_read_thread = startTunReadThread(&arg); + struct tunread_arg arg; + arg.eee = eee; + arg.keep_running = keep_running; + HANDLE tun_read_thread = startTunReadThread(&arg); #endif - *keep_running = 1; - update_supernode_reg(eee, time(NULL)); + *keep_running = 1; + update_supernode_reg(eee, time(NULL)); - /* Main loop - * - * select() is used to wait for input on either the TAP fd or the UDP/TCP - * socket. When input is present the data is read and processed by either - * readFromIPSocket() or edge_read_from_tap() - */ + /* Main loop + * + * select() is used to wait for input on either the TAP fd or the UDP/TCP + * socket. When input is present the data is read and processed by either + * readFromIPSocket() or edge_read_from_tap() + */ - while(*keep_running) { - int rc, max_sock = 0; - fd_set socket_mask; - struct timeval wait_time; - time_t nowTime; + while(*keep_running) { + int rc, max_sock = 0; + fd_set socket_mask; + struct timeval wait_time; + time_t nowTime; - FD_ZERO(&socket_mask); - FD_SET(eee->udp_sock, &socket_mask); - FD_SET(eee->udp_mgmt_sock, &socket_mask); - max_sock = max(eee->udp_sock, eee->udp_mgmt_sock); + FD_ZERO(&socket_mask); + FD_SET(eee->udp_sock, &socket_mask); + FD_SET(eee->udp_mgmt_sock, &socket_mask); + max_sock = max(eee->udp_sock, eee->udp_mgmt_sock); #ifndef SKIP_MULTICAST_PEERS_DISCOVERY - FD_SET(eee->udp_multicast_sock, &socket_mask); - max_sock = max(eee->udp_sock, eee->udp_multicast_sock); + FD_SET(eee->udp_multicast_sock, &socket_mask); + max_sock = max(eee->udp_sock, eee->udp_multicast_sock); #endif #ifndef WIN32 - FD_SET(eee->device.fd, &socket_mask); - max_sock = max(max_sock, eee->device.fd); + FD_SET(eee->device.fd, &socket_mask); + max_sock = max(max_sock, eee->device.fd); #endif - wait_time.tv_sec = (eee->sn_wait)?(SOCKET_TIMEOUT_INTERVAL_SECS / 10 + 1):(SOCKET_TIMEOUT_INTERVAL_SECS); - wait_time.tv_usec = 0; + wait_time.tv_sec = (eee->sn_wait)?(SOCKET_TIMEOUT_INTERVAL_SECS / 10 + 1):(SOCKET_TIMEOUT_INTERVAL_SECS); + wait_time.tv_usec = 0; - rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time); - nowTime = time(NULL); + rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time); + nowTime = time(NULL); - /* Make sure ciphers are updated before the packet is treated. */ - if((nowTime - lastTransop) > TRANSOP_TICK_INTERVAL) { - lastTransop = nowTime; + /* Make sure ciphers are updated before the packet is treated. */ + if((nowTime - lastTransop) > TRANSOP_TICK_INTERVAL) { + lastTransop = nowTime; - eee->transop.tick(&eee->transop, nowTime); - } + eee->transop.tick(&eee->transop, nowTime); + } - if(rc > 0) { - /* Any or all of the FDs could have input; check them all. */ + if(rc > 0) { + /* Any or all of the FDs could have input; check them all. */ - if(FD_ISSET(eee->udp_sock, &socket_mask)) { - /* Read a cooked socket from the internet socket (unicast). Writes on the TAP - * socket. */ - readFromIPSocket(eee, eee->udp_sock); - } + if(FD_ISSET(eee->udp_sock, &socket_mask)) { + /* Read a cooked socket from the internet socket (unicast). Writes on the TAP + * socket. */ + readFromIPSocket(eee, eee->udp_sock); + } #ifndef SKIP_MULTICAST_PEERS_DISCOVERY - if(FD_ISSET(eee->udp_multicast_sock, &socket_mask)) { - /* Read a cooked socket from the internet socket (multicast). Writes on the TAP - * socket. */ - traceEvent(TRACE_DEBUG, "Received packet from multicast socket"); - readFromIPSocket(eee, eee->udp_multicast_sock); - } + if(FD_ISSET(eee->udp_multicast_sock, &socket_mask)) { + /* Read a cooked socket from the internet socket (multicast). Writes on the TAP + * socket. */ + traceEvent(TRACE_DEBUG, "Received packet from multicast socket"); + readFromIPSocket(eee, eee->udp_multicast_sock); + } #endif - if(FD_ISSET(eee->udp_mgmt_sock, &socket_mask)) { - /* Read a cooked socket from the internet socket. Writes on the TAP - * socket. */ - readFromMgmtSocket(eee, keep_running); + if(FD_ISSET(eee->udp_mgmt_sock, &socket_mask)) { + /* Read a cooked socket from the internet socket. Writes on the TAP + * socket. */ + readFromMgmtSocket(eee, keep_running); - if(!(*keep_running)) - break; - } + if(!(*keep_running)) + break; + } #ifndef WIN32 - if(FD_ISSET(eee->device.fd, &socket_mask)) { - /* Read an ethernet frame from the TAP socket. Write on the IP - * socket. */ - edge_read_from_tap(eee); - } + if(FD_ISSET(eee->device.fd, &socket_mask)) { + /* Read an ethernet frame from the TAP socket. Write on the IP + * socket. */ + edge_read_from_tap(eee); + } #endif - } + } - /* Finished processing select data. */ - update_supernode_reg(eee, nowTime); + /* Finished processing select data. */ + update_supernode_reg(eee, nowTime); - numPurged = purge_expired_registrations(&eee->known_peers, &last_purge_known, PURGE_REGISTRATION_FREQUENCY); - numPurged += purge_expired_registrations(&eee->pending_peers, &last_purge_pending, PURGE_REGISTRATION_FREQUENCY); + numPurged = purge_expired_registrations(&eee->known_peers, &last_purge_known, PURGE_REGISTRATION_FREQUENCY); + numPurged += purge_expired_registrations(&eee->pending_peers, &last_purge_pending, PURGE_REGISTRATION_FREQUENCY); - if(numPurged > 0) { - traceEvent(TRACE_INFO, "%u peers removed. now: pending=%u, operational=%u", - numPurged, - HASH_COUNT(eee->pending_peers), - HASH_COUNT(eee->known_peers)); - } + if(numPurged > 0) { + traceEvent(TRACE_INFO, "%u peers removed. now: pending=%u, operational=%u", + numPurged, + HASH_COUNT(eee->pending_peers), + HASH_COUNT(eee->known_peers)); + } - if((eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_DHCP) && - ((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) { - uint32_t old_ip = eee->device.ip_addr; + if((eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_DHCP) && + ((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) { + uint32_t old_ip = eee->device.ip_addr; - traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address."); - tuntap_get_address(&(eee->device)); - lastIfaceCheck = nowTime; + traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address."); + tuntap_get_address(&(eee->device)); + lastIfaceCheck = nowTime; - if((old_ip != eee->device.ip_addr) && eee->cb.ip_address_changed) - eee->cb.ip_address_changed(eee, old_ip, eee->device.ip_addr); - } + if((old_ip != eee->device.ip_addr) && eee->cb.ip_address_changed) + eee->cb.ip_address_changed(eee, old_ip, eee->device.ip_addr); + } - if(eee->cb.main_loop_period) - eee->cb.main_loop_period(eee, nowTime); + if(eee->cb.main_loop_period) + eee->cb.main_loop_period(eee, nowTime); - sort_supernodes(eee, nowTime); + sort_supernodes(eee, nowTime); - } /* while */ + } /* while */ #ifdef WIN32 - WaitForSingleObject(tun_read_thread, INFINITE); + WaitForSingleObject(tun_read_thread, INFINITE); #endif - send_unregister_super(eee); + send_unregister_super(eee); - closesocket(eee->udp_sock); + closesocket(eee->udp_sock); - return(0); + return(0); } /* ************************************** */ @@ -2430,107 +2432,107 @@ int run_edge_loop (n2n_edge_t * eee, int *keep_running) { /** Deinitialise the edge and deallocate any owned memory. */ void edge_term (n2n_edge_t * eee) { - if(eee->udp_sock >= 0) - closesocket(eee->udp_sock); + if(eee->udp_sock >= 0) + closesocket(eee->udp_sock); - if(eee->udp_mgmt_sock >= 0) - closesocket(eee->udp_mgmt_sock); + if(eee->udp_mgmt_sock >= 0) + closesocket(eee->udp_mgmt_sock); #ifndef SKIP_MULTICAST_PEERS_DISCOVERY - if(eee->udp_multicast_sock >= 0) - closesocket(eee->udp_multicast_sock); + if(eee->udp_multicast_sock >= 0) + closesocket(eee->udp_multicast_sock); #endif - clear_peer_list(&eee->pending_peers); - clear_peer_list(&eee->known_peers); + clear_peer_list(&eee->pending_peers); + clear_peer_list(&eee->known_peers); - eee->transop.deinit(&eee->transop); + eee->transop.deinit(&eee->transop); - edge_cleanup_routes(eee); + edge_cleanup_routes(eee); - destroy_network_traffic_filter(eee->network_traffic_filter); + destroy_network_traffic_filter(eee->network_traffic_filter); - closeTraceFile(); + closeTraceFile(); - free(eee); + free(eee); } /* ************************************** */ static int edge_init_sockets (n2n_edge_t *eee, int udp_local_port, int mgmt_port, uint8_t tos) { - int sockopt; + int sockopt; - if(eee->udp_sock >= 0) - closesocket(eee->udp_sock); + if(eee->udp_sock >= 0) + closesocket(eee->udp_sock); - if(eee->udp_mgmt_sock >= 0) - closesocket(eee->udp_mgmt_sock); + if(eee->udp_mgmt_sock >= 0) + closesocket(eee->udp_mgmt_sock); #ifndef SKIP_MULTICAST_PEERS_DISCOVERY - if(eee->udp_multicast_sock >= 0) - closesocket(eee->udp_multicast_sock); + if(eee->udp_multicast_sock >= 0) + closesocket(eee->udp_multicast_sock); #endif - if(udp_local_port > 0) - traceEvent(TRACE_NORMAL, "Binding to local port %d", udp_local_port); + if(udp_local_port > 0) + traceEvent(TRACE_NORMAL, "Binding to local port %d", udp_local_port); - eee->udp_sock = open_socket(udp_local_port, 1 /* bind ANY */); - if(eee->udp_sock < 0) { - traceEvent(TRACE_ERROR, "Failed to bind main UDP port %u", udp_local_port); - return(-1); - } + eee->udp_sock = open_socket(udp_local_port, 1 /* bind ANY */); + if(eee->udp_sock < 0) { + traceEvent(TRACE_ERROR, "Failed to bind main UDP port %u", udp_local_port); + return(-1); + } - if(tos) { - /* https://www.tucny.com/Home/dscp-tos */ - sockopt = tos; + if(tos) { + /* https://www.tucny.com/Home/dscp-tos */ + sockopt = tos; - if(setsockopt(eee->udp_sock, IPPROTO_IP, IP_TOS, (char *)&sockopt, sizeof(sockopt)) == 0) - traceEvent(TRACE_NORMAL, "TOS set to 0x%x", tos); - else - traceEvent(TRACE_ERROR, "Could not set TOS 0x%x[%d]: %s", tos, errno, strerror(errno)); - } + if(setsockopt(eee->udp_sock, IPPROTO_IP, IP_TOS, (char *)&sockopt, sizeof(sockopt)) == 0) + traceEvent(TRACE_NORMAL, "TOS set to 0x%x", tos); + else + traceEvent(TRACE_ERROR, "Could not set TOS 0x%x[%d]: %s", tos, errno, strerror(errno)); + } #ifdef IP_PMTUDISC_DO - sockopt = (eee->conf.disable_pmtu_discovery) ? IP_PMTUDISC_DONT : IP_PMTUDISC_DO; + sockopt = (eee->conf.disable_pmtu_discovery) ? IP_PMTUDISC_DONT : IP_PMTUDISC_DO; - if(setsockopt(eee->udp_sock, IPPROTO_IP, IP_MTU_DISCOVER, &sockopt, sizeof(sockopt)) < 0) - traceEvent(TRACE_WARNING, "Could not %s PMTU discovery[%d]: %s", - (eee->conf.disable_pmtu_discovery) ? "disable" : "enable", errno, strerror(errno)); - else - traceEvent(TRACE_DEBUG, "PMTU discovery %s", (eee->conf.disable_pmtu_discovery) ? "disabled" : "enabled"); + if(setsockopt(eee->udp_sock, IPPROTO_IP, IP_MTU_DISCOVER, &sockopt, sizeof(sockopt)) < 0) + traceEvent(TRACE_WARNING, "Could not %s PMTU discovery[%d]: %s", + (eee->conf.disable_pmtu_discovery) ? "disable" : "enable", errno, strerror(errno)); + else + traceEvent(TRACE_DEBUG, "PMTU discovery %s", (eee->conf.disable_pmtu_discovery) ? "disabled" : "enabled"); #endif - eee->udp_mgmt_sock = open_socket(mgmt_port, 0 /* bind LOOPBACK */); - if(eee->udp_mgmt_sock < 0) { - traceEvent(TRACE_ERROR, "Failed to bind management UDP port %u", mgmt_port); - return(-2); - } + eee->udp_mgmt_sock = open_socket(mgmt_port, 0 /* bind LOOPBACK */); + if(eee->udp_mgmt_sock < 0) { + traceEvent(TRACE_ERROR, "Failed to bind management UDP port %u", mgmt_port); + return(-2); + } #ifndef SKIP_MULTICAST_PEERS_DISCOVERY - /* Populate the multicast group for local edge */ - eee->multicast_peer.family = AF_INET; - eee->multicast_peer.port = N2N_MULTICAST_PORT; - eee->multicast_peer.addr.v4[0] = 224; /* N2N_MULTICAST_GROUP */ - eee->multicast_peer.addr.v4[1] = 0; - eee->multicast_peer.addr.v4[2] = 0; - eee->multicast_peer.addr.v4[3] = 68; - - eee->udp_multicast_sock = open_socket(N2N_MULTICAST_PORT, 1 /* bind ANY */); - if(eee->udp_multicast_sock < 0) - return(-3); - else { - u_int enable_reuse = 1; - - /* allow multiple sockets to use the same PORT number */ - setsockopt(eee->udp_multicast_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&enable_reuse, sizeof(enable_reuse)); + /* Populate the multicast group for local edge */ + eee->multicast_peer.family = AF_INET; + eee->multicast_peer.port = N2N_MULTICAST_PORT; + eee->multicast_peer.addr.v4[0] = 224; /* N2N_MULTICAST_GROUP */ + eee->multicast_peer.addr.v4[1] = 0; + eee->multicast_peer.addr.v4[2] = 0; + eee->multicast_peer.addr.v4[3] = 68; + + eee->udp_multicast_sock = open_socket(N2N_MULTICAST_PORT, 1 /* bind ANY */); + if(eee->udp_multicast_sock < 0) + return(-3); + else { + u_int enable_reuse = 1; + + /* allow multiple sockets to use the same PORT number */ + setsockopt(eee->udp_multicast_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&enable_reuse, sizeof(enable_reuse)); #ifdef SO_REUSEPORT /* no SO_REUSEPORT in Windows / old linux versions */ - setsockopt(eee->udp_multicast_sock, SOL_SOCKET, SO_REUSEPORT, &enable_reuse, sizeof(enable_reuse)); + setsockopt(eee->udp_multicast_sock, SOL_SOCKET, SO_REUSEPORT, &enable_reuse, sizeof(enable_reuse)); #endif - } + } #endif - return(0); + return(0); } /* ************************************** */ @@ -2539,232 +2541,232 @@ static int edge_init_sockets (n2n_edge_t *eee, int udp_local_port, int mgmt_port static uint32_t get_gateway_ip() { - FILE *fd; - char *token = NULL; - char *gateway_ip_str = NULL; - char buf[256]; - uint32_t gateway = 0; + FILE *fd; + char *token = NULL; + char *gateway_ip_str = NULL; + char buf[256]; + uint32_t gateway = 0; - if(!(fd = fopen("/proc/net/route", "r"))) - return(0); + if(!(fd = fopen("/proc/net/route", "r"))) + return(0); - while(fgets(buf, sizeof(buf), fd)) { - if(strtok(buf, "\t") && (token = strtok(NULL, "\t")) && (!strcmp(token, "00000000"))) { - token = strtok(NULL, "\t"); + while(fgets(buf, sizeof(buf), fd)) { + if(strtok(buf, "\t") && (token = strtok(NULL, "\t")) && (!strcmp(token, "00000000"))) { + token = strtok(NULL, "\t"); - if(token) { - struct in_addr addr; + if(token) { + struct in_addr addr; - addr.s_addr = strtoul(token, NULL, 16); - gateway_ip_str = inet_ntoa(addr); + addr.s_addr = strtoul(token, NULL, 16); + gateway_ip_str = inet_ntoa(addr); - if(gateway_ip_str) { - gateway = addr.s_addr; - break; + if(gateway_ip_str) { + gateway = addr.s_addr; + break; + } + } } - } } - } - fclose(fd); + fclose(fd); - return(gateway); + return(gateway); } static char* route_cmd_to_str (int cmd, const n2n_route_t *route, char *buf, size_t bufsize) { - const char *cmd_str; - struct in_addr addr; - char netbuf[64], gwbuf[64]; + const char *cmd_str; + struct in_addr addr; + char netbuf[64], gwbuf[64]; - switch(cmd) { - case RTM_NEWROUTE: - cmd_str = "Add"; - break; + switch(cmd) { + case RTM_NEWROUTE: + cmd_str = "Add"; + break; - case RTM_DELROUTE: - cmd_str = "Delete"; - break; + case RTM_DELROUTE: + cmd_str = "Delete"; + break; - default: - cmd_str = "?"; - } + default: + cmd_str = "?"; + } - addr.s_addr = route->net_addr; - inet_ntop(AF_INET, &addr, netbuf, sizeof(netbuf)); - addr.s_addr = route->gateway; - inet_ntop(AF_INET, &addr, gwbuf, sizeof(gwbuf)); + addr.s_addr = route->net_addr; + inet_ntop(AF_INET, &addr, netbuf, sizeof(netbuf)); + addr.s_addr = route->gateway; + inet_ntop(AF_INET, &addr, gwbuf, sizeof(gwbuf)); - snprintf(buf, bufsize, "%s %s/%d via %s", cmd_str, netbuf, route->net_bitlen, gwbuf); + snprintf(buf, bufsize, "%s %s/%d via %s", cmd_str, netbuf, route->net_bitlen, gwbuf); - return(buf); + return(buf); } /* Adapted from https://olegkutkov.me/2019/08/29/modifying-linux-network-routes-using-netlink/ */ -#define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) /* Add new data to rtattr */ static int rtattr_add (struct nlmsghdr *n, int maxlen, int type, const void *data, int alen) { - int len = RTA_LENGTH(alen); - struct rtattr *rta; + int len = RTA_LENGTH(alen); + struct rtattr *rta; - if(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { - traceEvent(TRACE_ERROR, "rtattr_add error: message exceeded bound of %d\n", maxlen); - return -1; - } + if(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + traceEvent(TRACE_ERROR, "rtattr_add error: message exceeded bound of %d\n", maxlen); + return -1; + } - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = len; + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; - if(alen) - memcpy(RTA_DATA(rta), data, alen); + if(alen) + memcpy(RTA_DATA(rta), data, alen); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); - return 0; + return 0; } static int routectl (int cmd, int flags, n2n_route_t *route, int if_idx) { - int rv = -1; - int rv2; - char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */ - char route_buf[256]; - struct iovec iov; - struct msghdr msg; - struct sockaddr_nl sa; - uint8_t read_reply = 1; - int nl_sock; - - struct { - struct nlmsghdr n; - struct rtmsg r; - char buf[4096]; - } nl_request; - - if((nl_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { - traceEvent(TRACE_ERROR, "netlink socket creation failed [%d]: %s", errno, strerror(errno)); - return(-1); - } - - /* Subscribe to route change events */ - iov.iov_base = nl_buf; - iov.iov_len = sizeof(nl_buf); - - memset(&sa, 0, sizeof(sa)); - sa.nl_family = PF_NETLINK; - sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY; - sa.nl_pid = getpid(); - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &sa; - msg.msg_namelen = sizeof(sa); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - /* Subscribe to route events */ - if(bind(nl_sock, (struct sockaddr*)&sa, sizeof(sa)) == -1) { - traceEvent(TRACE_ERROR, "netlink socket bind failed [%d]: %s", errno, strerror(errno)); - goto out; - } - - /* Initialize request structure */ - memset(&nl_request, 0, sizeof(nl_request)); - nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags; - nl_request.n.nlmsg_type = cmd; - nl_request.r.rtm_family = AF_INET; - nl_request.r.rtm_table = RT_TABLE_MAIN; - nl_request.r.rtm_scope = RT_SCOPE_NOWHERE; - - /* Set additional flags if NOT deleting route */ - if(cmd != RTM_DELROUTE) { - nl_request.r.rtm_protocol = RTPROT_BOOT; - nl_request.r.rtm_type = RTN_UNICAST; - } - - nl_request.r.rtm_family = AF_INET; - nl_request.r.rtm_dst_len = route->net_bitlen; - - /* Select scope, for simplicity we supports here only IPv6 and IPv4 */ - if(nl_request.r.rtm_family == AF_INET6) - nl_request.r.rtm_scope = RT_SCOPE_UNIVERSE; - else - nl_request.r.rtm_scope = RT_SCOPE_LINK; - - /* Set gateway */ - if(route->net_bitlen) { - if(rtattr_add(&nl_request.n, sizeof(nl_request), RTA_GATEWAY, &route->gateway, 4) < 0) - goto out; - - nl_request.r.rtm_scope = 0; - nl_request.r.rtm_family = AF_INET; - } + int rv = -1; + int rv2; + char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */ + char route_buf[256]; + struct iovec iov; + struct msghdr msg; + struct sockaddr_nl sa; + uint8_t read_reply = 1; + int nl_sock; + + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[4096]; + } nl_request; + + if((nl_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { + traceEvent(TRACE_ERROR, "netlink socket creation failed [%d]: %s", errno, strerror(errno)); + return(-1); + } - /* Don't set destination and interface in case of default gateways */ - if(route->net_bitlen) { - /* Set destination network */ - if(rtattr_add(&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &route->net_addr, 4) < 0) - goto out; + /* Subscribe to route change events */ + iov.iov_base = nl_buf; + iov.iov_len = sizeof(nl_buf); - /* Set interface */ - if(if_idx > 0) { - if(rtattr_add(&nl_request.n, sizeof(nl_request), RTA_OIF, &if_idx, sizeof(int)) < 0) + memset(&sa, 0, sizeof(sa)); + sa.nl_family = PF_NETLINK; + sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY; + sa.nl_pid = getpid(); + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &sa; + msg.msg_namelen = sizeof(sa); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + /* Subscribe to route events */ + if(bind(nl_sock, (struct sockaddr*)&sa, sizeof(sa)) == -1) { + traceEvent(TRACE_ERROR, "netlink socket bind failed [%d]: %s", errno, strerror(errno)); goto out; } - } - /* Send message to the netlink */ - if((rv2 = send(nl_sock, &nl_request, sizeof(nl_request), 0)) != sizeof(nl_request)) { - traceEvent(TRACE_ERROR, "netlink send failed [%d]: %s", errno, strerror(errno)); - goto out; - } + /* Initialize request structure */ + memset(&nl_request, 0, sizeof(nl_request)); + nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags; + nl_request.n.nlmsg_type = cmd; + nl_request.r.rtm_family = AF_INET; + nl_request.r.rtm_table = RT_TABLE_MAIN; + nl_request.r.rtm_scope = RT_SCOPE_NOWHERE; - /* Wait for the route notification. Assume that the first reply we get is the correct one. */ - traceEvent(TRACE_DEBUG, "waiting for netlink response..."); + /* Set additional flags if NOT deleting route */ + if(cmd != RTM_DELROUTE) { + nl_request.r.rtm_protocol = RTPROT_BOOT; + nl_request.r.rtm_type = RTN_UNICAST; + } + + nl_request.r.rtm_family = AF_INET; + nl_request.r.rtm_dst_len = route->net_bitlen; - while(read_reply) { - ssize_t len = recvmsg(nl_sock, &msg, 0); - struct nlmsghdr *nh; + /* Select scope, for simplicity we supports here only IPv6 and IPv4 */ + if(nl_request.r.rtm_family == AF_INET6) + nl_request.r.rtm_scope = RT_SCOPE_UNIVERSE; + else + nl_request.r.rtm_scope = RT_SCOPE_LINK; - for(nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { - /* Stop after the first reply */ - read_reply = 0; + /* Set gateway */ + if(route->net_bitlen) { + if(rtattr_add(&nl_request.n, sizeof(nl_request), RTA_GATEWAY, &route->gateway, 4) < 0) + goto out; - if(nh->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = NLMSG_DATA(nh); - int errcode = err->error; + nl_request.r.rtm_scope = 0; + nl_request.r.rtm_family = AF_INET; + } - if(errcode < 0) - errcode = -errcode; + /* Don't set destination and interface in case of default gateways */ + if(route->net_bitlen) { + /* Set destination network */ + if(rtattr_add(&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &route->net_addr, 4) < 0) + goto out; - /* Ignore EEXIST as existing rules are ok */ - if(errcode != EEXIST) { - traceEvent(TRACE_ERROR, "[err=%d] route: %s", errcode, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf))); - goto out; + /* Set interface */ + if(if_idx > 0) { + if(rtattr_add(&nl_request.n, sizeof(nl_request), RTA_OIF, &if_idx, sizeof(int)) < 0) + goto out; } - } + } - if(nh->nlmsg_type == NLMSG_DONE) - break; + /* Send message to the netlink */ + if((rv2 = send(nl_sock, &nl_request, sizeof(nl_request), 0)) != sizeof(nl_request)) { + traceEvent(TRACE_ERROR, "netlink send failed [%d]: %s", errno, strerror(errno)); + goto out; + } - if(nh->nlmsg_type == cmd) { - traceEvent(TRACE_DEBUG, "Found netlink reply"); - break; - } + /* Wait for the route notification. Assume that the first reply we get is the correct one. */ + traceEvent(TRACE_DEBUG, "waiting for netlink response..."); + + while(read_reply) { + ssize_t len = recvmsg(nl_sock, &msg, 0); + struct nlmsghdr *nh; + + for(nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { + /* Stop after the first reply */ + read_reply = 0; + + if(nh->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = NLMSG_DATA(nh); + int errcode = err->error; + + if(errcode < 0) + errcode = -errcode; + + /* Ignore EEXIST as existing rules are ok */ + if(errcode != EEXIST) { + traceEvent(TRACE_ERROR, "[err=%d] route: %s", errcode, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf))); + goto out; + } + } + + if(nh->nlmsg_type == NLMSG_DONE) + break; + + if(nh->nlmsg_type == cmd) { + traceEvent(TRACE_DEBUG, "Found netlink reply"); + break; + } + } } - } - traceEvent(TRACE_DEBUG, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf))); - rv = 0; + traceEvent(TRACE_DEBUG, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf))); + rv = 0; out: - close(nl_sock); + close(nl_sock); - return(rv); + return(rv); } #endif @@ -2773,123 +2775,123 @@ static int routectl (int cmd, int flags, n2n_route_t *route, int if_idx) { static int edge_init_routes_linux (n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) { #ifdef __linux__ - int i; - for(i = 0; inet_addr == 0) && (route->net_bitlen == 0)) { - /* This is a default gateway rule. We need to: - * - * 1. Add a route to the supernode via the host internet gateway - * 2. Add the new default gateway route - * - * Instead of modifying the system default gateway, we use the trick - * of adding a route to the networks 0.0.0.0/1 and 128.0.0.0/1, thus - * covering the whole IPv4 range. Such routes in linux take precedence - * over the default gateway (0.0.0.0/0) since are more specific. - * This leaves the default gateway unchanged so that after n2n is - * stopped the cleanup is easier. - * See https://github.com/zerotier/ZeroTierOne/issues/178#issuecomment-204599227 - */ - n2n_sock_t sn; - n2n_route_t custom_route; - uint32_t *a; - - if(eee->sn_route_to_clean) { - traceEvent(TRACE_ERROR, "Only one default gateway route allowed"); - return(-1); - } + int i; + for(i = 0; inet_addr == 0) && (route->net_bitlen == 0)) { + /* This is a default gateway rule. We need to: + * + * 1. Add a route to the supernode via the host internet gateway + * 2. Add the new default gateway route + * + * Instead of modifying the system default gateway, we use the trick + * of adding a route to the networks 0.0.0.0/1 and 128.0.0.0/1, thus + * covering the whole IPv4 range. Such routes in linux take precedence + * over the default gateway (0.0.0.0/0) since are more specific. + * This leaves the default gateway unchanged so that after n2n is + * stopped the cleanup is easier. + * See https://github.com/zerotier/ZeroTierOne/issues/178#issuecomment-204599227 + */ + n2n_sock_t sn; + n2n_route_t custom_route; + uint32_t *a; + + if(eee->sn_route_to_clean) { + traceEvent(TRACE_ERROR, "Only one default gateway route allowed"); + return(-1); + } - if(eee->conf.sn_num != 1) { - traceEvent(TRACE_ERROR, "Only one supernode supported with routes"); - return(-1); - } + if(eee->conf.sn_num != 1) { + traceEvent(TRACE_ERROR, "Only one supernode supported with routes"); + return(-1); + } - if(supernode2sock(&sn, eee->conf.supernodes->ip_addr) < 0) - return(-1); + if(supernode2sock(&sn, eee->conf.supernodes->ip_addr) < 0) + return(-1); - if(sn.family != AF_INET) { - traceEvent(TRACE_ERROR, "Only IPv4 routes supported"); - return(-1); - } + if(sn.family != AF_INET) { + traceEvent(TRACE_ERROR, "Only IPv4 routes supported"); + return(-1); + } - a = (u_int32_t*)sn.addr.v4; - custom_route.net_addr = *a; - custom_route.net_bitlen = 32; - custom_route.gateway = get_gateway_ip(); + a = (u_int32_t*)sn.addr.v4; + custom_route.net_addr = *a; + custom_route.net_bitlen = 32; + custom_route.gateway = get_gateway_ip(); - if(!custom_route.gateway) { - traceEvent(TRACE_ERROR, "could not determine the gateway IP address"); - return(-1); - } + if(!custom_route.gateway) { + traceEvent(TRACE_ERROR, "could not determine the gateway IP address"); + return(-1); + } - /* ip route add supernode via internet_gateway */ - if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, -1) < 0) - return(-1); + /* ip route add supernode via internet_gateway */ + if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, -1) < 0) + return(-1); - /* Save the route to delete it when n2n is stopped */ - eee->sn_route_to_clean = calloc(1, sizeof(n2n_route_t)); + /* Save the route to delete it when n2n is stopped */ + eee->sn_route_to_clean = calloc(1, sizeof(n2n_route_t)); - /* Store a copy of the rules into the runtime to delete it during shutdown */ - if(eee->sn_route_to_clean) - *eee->sn_route_to_clean = custom_route; + /* Store a copy of the rules into the runtime to delete it during shutdown */ + if(eee->sn_route_to_clean) + *eee->sn_route_to_clean = custom_route; - /* ip route add 0.0.0.0/1 via n2n_gateway */ - custom_route.net_addr = 0; - custom_route.net_bitlen = 1; - custom_route.gateway = route->gateway; + /* ip route add 0.0.0.0/1 via n2n_gateway */ + custom_route.net_addr = 0; + custom_route.net_bitlen = 1; + custom_route.gateway = route->gateway; - if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) - return(-1); + if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) + return(-1); - /* ip route add 128.0.0.0/1 via n2n_gateway */ - custom_route.net_addr = 128; - custom_route.net_bitlen = 1; - custom_route.gateway = route->gateway; + /* ip route add 128.0.0.0/1 via n2n_gateway */ + custom_route.net_addr = 128; + custom_route.net_bitlen = 1; + custom_route.gateway = route->gateway; - if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) - return(-1); - } else { - /* ip route add net via n2n_gateway */ - if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, route, eee->device.if_idx) < 0) - return(-1); + if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) + return(-1); + } else { + /* ip route add net via n2n_gateway */ + if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, route, eee->device.if_idx) < 0) + return(-1); + } } - } #endif - return(0); + return(0); } /* ************************************** */ static int edge_init_routes_win (n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) { #ifdef WIN32 - int i; - struct in_addr net_addr, gateway; - char c_net_addr[32]; - char c_gateway[32]; - char cmd[256]; - - for(i = 0; i < num_routes; i++) { - n2n_route_t *route = &routes[i]; - if((route->net_addr == 0) && (route->net_bitlen == 0)) { - traceEvent(TRACE_NORMAL, "Warning: The 0.0.0.0/0 route settings are not supported on Windows"); - return(-1); - } else { - /* ip route add net via n2n_gateway */ - memcpy(&net_addr, &(route->net_addr), sizeof(net_addr)); - memcpy(&gateway, &(route->gateway), sizeof(gateway)); - _snprintf(c_net_addr, sizeof(c_net_addr), inet_ntoa(net_addr)); - _snprintf(c_gateway, sizeof(c_gateway), inet_ntoa(gateway)); - _snprintf(cmd, sizeof(cmd), "route add %s/%d %s > nul", c_net_addr, route->net_bitlen, c_gateway); - traceEvent(TRACE_NORMAL, "ROUTE CMD = '%s'\n", cmd); - system(cmd); + int i; + struct in_addr net_addr, gateway; + char c_net_addr[32]; + char c_gateway[32]; + char cmd[256]; + + for(i = 0; i < num_routes; i++) { + n2n_route_t *route = &routes[i]; + if((route->net_addr == 0) && (route->net_bitlen == 0)) { + traceEvent(TRACE_NORMAL, "Warning: The 0.0.0.0/0 route settings are not supported on Windows"); + return(-1); + } else { + /* ip route add net via n2n_gateway */ + memcpy(&net_addr, &(route->net_addr), sizeof(net_addr)); + memcpy(&gateway, &(route->gateway), sizeof(gateway)); + _snprintf(c_net_addr, sizeof(c_net_addr), inet_ntoa(net_addr)); + _snprintf(c_gateway, sizeof(c_gateway), inet_ntoa(gateway)); + _snprintf(cmd, sizeof(cmd), "route add %s/%d %s > nul", c_net_addr, route->net_bitlen, c_gateway); + traceEvent(TRACE_NORMAL, "ROUTE CMD = '%s'\n", cmd); + system(cmd); + } } - } #endif // WIN32 - return (0); + return (0); } /* ************************************** */ @@ -2899,24 +2901,24 @@ static int edge_init_routes_win (n2n_edge_t *eee, n2n_route_t *routes, uint16_t * the TAP device is destroyed. */ static int edge_init_routes (n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) { #ifdef __linux__ - return edge_init_routes_linux(eee, routes, num_routes); + return edge_init_routes_linux(eee, routes, num_routes); #endif #ifdef WIN32 - return edge_init_routes_win(eee, routes, num_routes); + return edge_init_routes_win(eee, routes, num_routes); #endif - return 0; + return 0; } /* ************************************** */ static void edge_cleanup_routes (n2n_edge_t *eee) { #ifdef __linux__ - if(eee->sn_route_to_clean) { - /* ip route del supernode via internet_gateway */ - routectl(RTM_DELROUTE, 0, eee->sn_route_to_clean, -1); - free(eee->sn_route_to_clean); - } + if(eee->sn_route_to_clean) { + /* ip route del supernode via internet_gateway */ + routectl(RTM_DELROUTE, 0, eee->sn_route_to_clean, -1); + free(eee->sn_route_to_clean); + } #endif } @@ -2924,89 +2926,89 @@ static void edge_cleanup_routes (n2n_edge_t *eee) { void edge_init_conf_defaults (n2n_edge_conf_t *conf) { - memset(conf, 0, sizeof(*conf)); - - conf->local_port = 0 /* any port */; - conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */ - conf->transop_id = N2N_TRANSFORM_ID_NULL; - conf->header_encryption = HEADER_ENCRYPTION_NONE; - conf->compression = N2N_COMPRESSION_ID_NONE; - conf->drop_multicast = 1; - conf->allow_p2p = 1; - conf->disable_pmtu_discovery = 1; - conf->register_interval = REGISTER_SUPER_INTERVAL_DFL; - conf->tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; - /* reserve possible last char as null terminator. */ - gethostname((char*)conf->dev_desc, N2N_DESC_SIZE-1); - - if(getenv("N2N_KEY")) { - conf->encrypt_key = strdup(getenv("N2N_KEY")); - conf->transop_id = N2N_TRANSFORM_ID_TWOFISH; - } + memset(conf, 0, sizeof(*conf)); + + conf->local_port = 0 /* any port */; + conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */ + conf->transop_id = N2N_TRANSFORM_ID_NULL; + conf->header_encryption = HEADER_ENCRYPTION_NONE; + conf->compression = N2N_COMPRESSION_ID_NONE; + conf->drop_multicast = 1; + conf->allow_p2p = 1; + conf->disable_pmtu_discovery = 1; + conf->register_interval = REGISTER_SUPER_INTERVAL_DFL; + conf->tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; + /* reserve possible last char as null terminator. */ + gethostname((char*)conf->dev_desc, N2N_DESC_SIZE-1); + + if(getenv("N2N_KEY")) { + conf->encrypt_key = strdup(getenv("N2N_KEY")); + conf->transop_id = N2N_TRANSFORM_ID_TWOFISH; + } } /* ************************************** */ void edge_term_conf (n2n_edge_conf_t *conf) { - if(conf->routes) free(conf->routes); - if(conf->encrypt_key) free(conf->encrypt_key); + if(conf->routes) free(conf->routes); + if(conf->encrypt_key) free(conf->encrypt_key); - if(conf->network_traffic_filter_rules) { - filter_rule_t *el = 0, *tmp = 0; - HASH_ITER(hh, conf->network_traffic_filter_rules, el, tmp) { - HASH_DEL(conf->network_traffic_filter_rules, el); - free(el); + if(conf->network_traffic_filter_rules) { + filter_rule_t *el = 0, *tmp = 0; + HASH_ITER(hh, conf->network_traffic_filter_rules, el, tmp) { + HASH_DEL(conf->network_traffic_filter_rules, el); + free(el); + } } - } } /* ************************************** */ const n2n_edge_conf_t* edge_get_conf (const n2n_edge_t *eee) { - return(&eee->conf); + return(&eee->conf); } /* ************************************** */ int edge_conf_add_supernode (n2n_edge_conf_t *conf, const char *ip_and_port) { - struct peer_info *sn; - n2n_sock_t *sock; - int skip_add; - int rv = -1; + struct peer_info *sn; + n2n_sock_t *sock; + int skip_add; + int rv = -1; - sock = (n2n_sock_t*)calloc(1,sizeof(n2n_sock_t)); - rv = supernode2sock(sock, ip_and_port); + sock = (n2n_sock_t*)calloc(1,sizeof(n2n_sock_t)); + rv = supernode2sock(sock, ip_and_port); - if(rv != 0) { - traceEvent(TRACE_WARNING, "Invalid socket"); - free(sock); - return(1); - } + if(rv != 0) { + traceEvent(TRACE_WARNING, "Invalid socket"); + free(sock); + return(1); + } - skip_add = SN_ADD; - sn = add_sn_to_list_by_mac_or_sock(&(conf->supernodes), sock, (n2n_mac_t *)null_mac, &skip_add); + skip_add = SN_ADD; + sn = add_sn_to_list_by_mac_or_sock(&(conf->supernodes), sock, (n2n_mac_t *)null_mac, &skip_add); - if(sn != NULL) { - sn->ip_addr = calloc(1,N2N_EDGE_SN_HOST_SIZE); + if(sn != NULL) { + sn->ip_addr = calloc(1,N2N_EDGE_SN_HOST_SIZE); - if(sn->ip_addr != NULL) { - strncpy(sn->ip_addr, ip_and_port, N2N_EDGE_SN_HOST_SIZE - 1); - memcpy(&(sn->sock), sock, sizeof(n2n_sock_t)); - memcpy(&(sn->mac_addr), null_mac, sizeof(n2n_mac_t)); - sn->purgeable = SN_UNPURGEABLE; - sn->last_valid_time_stamp = initial_time_stamp(); + if(sn->ip_addr != NULL) { + strncpy(sn->ip_addr, ip_and_port, N2N_EDGE_SN_HOST_SIZE - 1); + memcpy(&(sn->sock), sock, sizeof(n2n_sock_t)); + memcpy(&(sn->mac_addr), null_mac, sizeof(n2n_mac_t)); + sn->purgeable = SN_UNPURGEABLE; + sn->last_valid_time_stamp = initial_time_stamp(); + } } - } - free(sock); + free(sock); - traceEvent(TRACE_NORMAL, "Adding supernode = %s", sn->ip_addr); - conf->sn_num++; + traceEvent(TRACE_NORMAL, "Adding supernode = %s", sn->ip_addr); + conf->sn_num++; - return(0); + return(0); } /* ************************************** */ @@ -3017,40 +3019,40 @@ int quick_edge_init (char *device_name, char *community_name, char *supernode_ip_address_port, int *keep_on_running) { - tuntap_dev tuntap; - n2n_edge_t *eee; - n2n_edge_conf_t conf; - int rv; - - /* Setup the configuration */ - edge_init_conf_defaults(&conf); - conf.encrypt_key = encrypt_key; - conf.transop_id = N2N_TRANSFORM_ID_TWOFISH; - conf.compression = N2N_COMPRESSION_ID_NONE; - snprintf((char*)conf.community_name, sizeof(conf.community_name), "%s", community_name); - edge_conf_add_supernode(&conf, supernode_ip_address_port); - - /* Validate configuration */ - if(edge_verify_conf(&conf) != 0) - return(-1); - - /* Open the tuntap device */ - if(tuntap_open(&tuntap, device_name, "static", - local_ip_address, "255.255.255.0", - device_mac, DEFAULT_MTU) < 0) - return(-2); - - /* Init edge */ - if((eee = edge_init(&conf, &rv)) == NULL) - goto quick_edge_init_end; - - rv = run_edge_loop(eee, keep_on_running); - edge_term(eee); - edge_term_conf(&conf); + tuntap_dev tuntap; + n2n_edge_t *eee; + n2n_edge_conf_t conf; + int rv; + + /* Setup the configuration */ + edge_init_conf_defaults(&conf); + conf.encrypt_key = encrypt_key; + conf.transop_id = N2N_TRANSFORM_ID_TWOFISH; + conf.compression = N2N_COMPRESSION_ID_NONE; + snprintf((char*)conf.community_name, sizeof(conf.community_name), "%s", community_name); + edge_conf_add_supernode(&conf, supernode_ip_address_port); + + /* Validate configuration */ + if(edge_verify_conf(&conf) != 0) + return(-1); + + /* Open the tuntap device */ + if(tuntap_open(&tuntap, device_name, "static", + local_ip_address, "255.255.255.0", + device_mac, DEFAULT_MTU) < 0) + return(-2); + + /* Init edge */ + if((eee = edge_init(&conf, &rv)) == NULL) + goto quick_edge_init_end; + + rv = run_edge_loop(eee, keep_on_running); + edge_term(eee); + edge_term_conf(&conf); quick_edge_init_end: - tuntap_close(&tuntap); - return(rv); + tuntap_close(&tuntap); + return(rv); } /* ************************************** */ diff --git a/src/edge_utils_win32.c b/src/edge_utils_win32.c index 231bab4..5cc0aae 100644 --- a/src/edge_utils_win32.c +++ b/src/edge_utils_win32.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -24,28 +24,29 @@ static DWORD* tunReadThread (LPVOID lpArg) { - struct tunread_arg *arg = (struct tunread_arg*)lpArg; + struct tunread_arg *arg = (struct tunread_arg*)lpArg; - while(*arg->keep_running) - edge_read_from_tap(arg->eee); + while(*arg->keep_running) { + edge_read_from_tap(arg->eee); + } - return((DWORD*)NULL); + return((DWORD*)NULL); } /* ************************************** */ /** Start a second thread in Windows because TUNTAP interfaces do not expose - * file descriptors. */ + * file descriptors. */ HANDLE startTunReadThread (struct tunread_arg *arg) { - DWORD dwThreadId; + DWORD dwThreadId; - return(CreateThread(NULL, /* security attributes */ - 0, /* use default stack size */ - (LPTHREAD_START_ROUTINE)tunReadThread, /* thread function */ - (void*)arg, /* argument to thread function */ - 0, /* thread creation flags */ - &dwThreadId)); /* thread id out */ + return(CreateThread(NULL, /* security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE)tunReadThread, /* thread function */ + (void*)arg, /* argument to thread function */ + 0, /* thread creation flags */ + &dwThreadId)); /* thread id out */ } #endif diff --git a/src/example_edge_embed.c b/src/example_edge_embed.c index d9adfba..e981bc0 100644 --- a/src/example_edge_embed.c +++ b/src/example_edge_embed.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -22,52 +22,52 @@ static int keep_running; int main() { - n2n_edge_conf_t conf; - tuntap_dev tuntap; - n2n_edge_t *eee; - int rc; + n2n_edge_conf_t conf; + tuntap_dev tuntap; + n2n_edge_t *eee; + int rc; - edge_init_conf_defaults(&conf); - conf.allow_p2p = 1; // Whether to allow peer-to-peer communication - conf.allow_routing = 1; // Whether to allow the edge to route packets to other edges - snprintf((char *)conf.community_name, sizeof(conf.community_name), "%s", "mycommunity"); // Community to connect to - conf.disable_pmtu_discovery = 1; // Whether to disable the path MTU discovery - conf.drop_multicast = 0; // Whether to disable multicast - conf.tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; // How to set the IP address - conf.encrypt_key = "mysecret"; // Secret to decrypt & encrypt with - conf.local_port = 0; // What port to use (0 = any port) - conf.mgmt_port = N2N_EDGE_MGMT_PORT; // Edge management port (5644 by default) - conf.register_interval = 1; // Interval for both UDP NAT hole punching and supernode registration - conf.register_ttl = 1; // Interval for UDP NAT hole punching through supernode - edge_conf_add_supernode(&conf, "localhost:1234"); // Supernode to connect to - conf.tos = 16; // Type of service for sent packets - conf.transop_id = N2N_TRANSFORM_ID_TWOFISH; // Use the twofish encryption + edge_init_conf_defaults(&conf); + conf.allow_p2p = 1; // Whether to allow peer-to-peer communication + conf.allow_routing = 1; // Whether to allow the edge to route packets to other edges + snprintf((char *)conf.community_name, sizeof(conf.community_name), "%s", "mycommunity"); // Community to connect to + conf.disable_pmtu_discovery = 1; // Whether to disable the path MTU discovery + conf.drop_multicast = 0; // Whether to disable multicast + conf.tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; // How to set the IP address + conf.encrypt_key = "mysecret"; // Secret to decrypt & encrypt with + conf.local_port = 0; // What port to use (0 = any port) + conf.mgmt_port = N2N_EDGE_MGMT_PORT; // Edge management port (5644 by default) + conf.register_interval = 1; // Interval for both UDP NAT hole punching and supernode registration + conf.register_ttl = 1; // Interval for UDP NAT hole punching through supernode + edge_conf_add_supernode(&conf, "localhost:1234"); // Supernode to connect to + conf.tos = 16; // Type of service for sent packets + conf.transop_id = N2N_TRANSFORM_ID_TWOFISH; // Use the twofish encryption - if(edge_verify_conf(&conf) != 0) { - return -1; - } - - if(tuntap_open(&tuntap, - "edge0", // Name of the device to create - "static", // IP mode; static|dhcp - "10.0.0.1", // Set ip address - "255.255.255.0", // Netmask to use - "DE:AD:BE:EF:01:10", // Set mac address - DEFAULT_MTU) < 0) // MTU to use - { + if(edge_verify_conf(&conf) != 0) { return -1; } - eee = edge_init(&conf, &rc); - if(eee == NULL) { - exit(1); - } + if(tuntap_open(&tuntap, + "edge0", // Name of the device to create + "static", // IP mode; static|dhcp + "10.0.0.1", // Set ip address + "255.255.255.0", // Netmask to use + "DE:AD:BE:EF:01:10", // Set mac address + DEFAULT_MTU) < 0) // MTU to use + { + return -1; + } + + eee = edge_init(&conf, &rc); + if(eee == NULL) { + exit(1); + } - keep_running = 1; - rc = run_edge_loop(eee, &keep_running); + keep_running = 1; + rc = run_edge_loop(eee, &keep_running); - edge_term(eee); - tuntap_close(&tuntap); + edge_term(eee); + tuntap_close(&tuntap); - return rc; + return rc; } diff --git a/src/example_edge_embed_quick_edge_init.c b/src/example_edge_embed_quick_edge_init.c index 92b3ba1..e3646b2 100644 --- a/src/example_edge_embed_quick_edge_init.c +++ b/src/example_edge_embed_quick_edge_init.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -19,37 +19,37 @@ #include "n2n.h" /* - This tool demonstrates how to easily embed - n2n on an existing application + This tool demonstrates how to easily embed + n2n on an existing application */ int main (int argc, char* argv[]) { - char *device_name = (char*)"n2n0"; - char *network_name = (char*)"mynetwork"; - char *secret_key = (char*)"mysecret"; - char *my_mac_address = (char*)"DE:AD:BE:EF:01:10"; - char *my_ipv4_addr = (char*)"1.2.3.4"; - char *supernode = (char*)"7.8.9.10:1234"; - int keep_on_running = 1; - - /* Increase tracelevel to see what's happening */ - setTraceLevel(10); - - /* Random seed */ - n2n_srand (n2n_seed()); - - /* - NOTE - - As the function below won't end, you should - call it inside a separate thread - */ - return(quick_edge_init(device_name, - network_name, - secret_key, - my_mac_address, - my_ipv4_addr, - supernode, - &keep_on_running)); + char *device_name = (char*)"n2n0"; + char *network_name = (char*)"mynetwork"; + char *secret_key = (char*)"mysecret"; + char *my_mac_address = (char*)"DE:AD:BE:EF:01:10"; + char *my_ipv4_addr = (char*)"1.2.3.4"; + char *supernode = (char*)"7.8.9.10:1234"; + int keep_on_running = 1; + + /* Increase tracelevel to see what's happening */ + setTraceLevel(10); + + /* Random seed */ + n2n_srand (n2n_seed()); + + /* + NOTE + + As the function below won't end, you should + call it inside a separate thread + */ + return(quick_edge_init(device_name, + network_name, + secret_key, + my_mac_address, + my_ipv4_addr, + supernode, + &keep_on_running)); } diff --git a/src/example_sn_embed.c b/src/example_sn_embed.c index 4428e69..9b56f68 100644 --- a/src/example_sn_embed.c +++ b/src/example_sn_embed.c @@ -20,31 +20,29 @@ static int keep_running; -int main() -{ - n2n_sn_t sss_node; - int rc; +int main () { - sn_init(&sss_node); - sss_node.daemon = 0; // Whether to daemonize - sss_node.lport = 1234; // Main UDP listen port + n2n_sn_t sss_node; + int rc; - sss_node.sock = open_socket(sss_node.lport, 1); - if (-1 == sss_node.sock) - { - exit(-2); - } + sn_init(&sss_node); + sss_node.daemon = 0; // Whether to daemonize + sss_node.lport = 1234; // Main UDP listen port - sss_node.mgmt_sock = open_socket(5645, 0); // Main UDP management port - if (-1 == sss_node.mgmt_sock) - { - exit(-2); - } + sss_node.sock = open_socket(sss_node.lport, 1); + if(-1 == sss_node.sock) { + exit(-2); + } - keep_running = 1; - rc = run_sn_loop(&sss_node, &keep_running); + sss_node.mgmt_sock = open_socket(5645, 0); // Main UDP management port + if(-1 == sss_node.mgmt_sock) { + exit(-2); + } - sn_term(&sss_node); + keep_running = 1; + rc = run_sn_loop(&sss_node, &keep_running); - return rc; + sn_term(&sss_node); + + return rc; } diff --git a/src/n2n.c b/src/n2n.c index 3c631ed..4a2a955 100644 --- a/src/n2n.c +++ b/src/n2n.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -34,34 +34,34 @@ static const n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0}; SOCKET open_socket (int local_port, int bind_any) { - SOCKET sock_fd; - struct sockaddr_in local_address; - int sockopt; + SOCKET sock_fd; + struct sockaddr_in local_address; + int sockopt; - if((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - traceEvent(TRACE_ERROR, "Unable to create socket [%s][%d]\n", - strerror(errno), sock_fd); - return(-1); - } + if((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + traceEvent(TRACE_ERROR, "Unable to create socket [%s][%d]\n", + strerror(errno), sock_fd); + return(-1); + } #ifndef WIN32 - /* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */ + /* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */ #endif - sockopt = 1; - setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt)); + sockopt = 1; + setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt)); - memset(&local_address, 0, sizeof(local_address)); - local_address.sin_family = AF_INET; - local_address.sin_port = htons(local_port); - local_address.sin_addr.s_addr = htonl(bind_any ? INADDR_ANY : INADDR_LOOPBACK); + memset(&local_address, 0, sizeof(local_address)); + local_address.sin_family = AF_INET; + local_address.sin_port = htons(local_port); + local_address.sin_addr.s_addr = htonl(bind_any ? INADDR_ANY : INADDR_LOOPBACK); - if(bind(sock_fd,(struct sockaddr*) &local_address, sizeof(local_address)) == -1) { - traceEvent(TRACE_ERROR, "Bind error on local port %u [%s]\n", local_port, strerror(errno)); - return(-1); - } + if(bind(sock_fd,(struct sockaddr*) &local_address, sizeof(local_address)) == -1) { + traceEvent(TRACE_ERROR, "Bind error on local port %u [%s]\n", local_port, strerror(errno)); + return(-1); + } - return(sock_fd); + return(sock_fd); } static int traceLevel = 2 /* NORMAL */; @@ -70,110 +70,110 @@ static FILE *traceFile = NULL; int getTraceLevel () { - return(traceLevel); + return(traceLevel); } void setTraceLevel (int level) { - traceLevel = level; + traceLevel = level; } void setUseSyslog (int use_syslog) { - useSyslog = use_syslog; + useSyslog = use_syslog; } void setTraceFile (FILE *f) { - traceFile = f; + traceFile = f; } void closeTraceFile () { - if((traceFile != NULL) && (traceFile != stdout)) { - fclose(traceFile); - } + if((traceFile != NULL) && (traceFile != stdout)) { + fclose(traceFile); + } #ifndef WIN32 - if(useSyslog && syslog_opened) { - closelog(); - syslog_opened = 0; - } + if(useSyslog && syslog_opened) { + closelog(); + syslog_opened = 0; + } #endif } #define N2N_TRACE_DATESIZE 32 void traceEvent (int eventTraceLevel, char* file, int line, char * format, ...) { - va_list va_ap; - - if(traceFile == NULL) { - traceFile = stdout; - } - - if(eventTraceLevel <= traceLevel) { - char buf[1024]; - char out_buf[1280]; - char theDate[N2N_TRACE_DATESIZE]; - char *extra_msg = ""; - time_t theTime = time(NULL); - int i; - - /* We have two paths - one if we're logging, one if we aren't - * Note that the no-log case is those systems which don't support it(WIN32), - * those without the headers !defined(USE_SYSLOG) - * those where it's parametrically off... - */ - - memset(buf, 0, sizeof(buf)); - strftime(theDate, N2N_TRACE_DATESIZE, "%d/%b/%Y %H:%M:%S", localtime(&theTime)); - - va_start(va_ap, format); - vsnprintf(buf, sizeof(buf) - 1, format, va_ap); - va_end(va_ap); - - if(eventTraceLevel == 0 /* TRACE_ERROR */) { - extra_msg = "ERROR: "; - } else if(eventTraceLevel == 1 /* TRACE_WARNING */) { - extra_msg = "WARNING: "; - } + va_list va_ap; - while(buf[strlen(buf) - 1] == '\n') { - buf[strlen(buf) - 1] = '\0'; + if(traceFile == NULL) { + traceFile = stdout; } + if(eventTraceLevel <= traceLevel) { + char buf[1024]; + char out_buf[1280]; + char theDate[N2N_TRACE_DATESIZE]; + char *extra_msg = ""; + time_t theTime = time(NULL); + int i; + + /* We have two paths - one if we're logging, one if we aren't + * Note that the no-log case is those systems which don't support it(WIN32), + * those without the headers !defined(USE_SYSLOG) + * those where it's parametrically off... + */ + + memset(buf, 0, sizeof(buf)); + strftime(theDate, N2N_TRACE_DATESIZE, "%d/%b/%Y %H:%M:%S", localtime(&theTime)); + + va_start(va_ap, format); + vsnprintf(buf, sizeof(buf) - 1, format, va_ap); + va_end(va_ap); + + if(eventTraceLevel == 0 /* TRACE_ERROR */) { + extra_msg = "ERROR: "; + } else if(eventTraceLevel == 1 /* TRACE_WARNING */) { + extra_msg = "WARNING: "; + } + + while(buf[strlen(buf) - 1] == '\n') { + buf[strlen(buf) - 1] = '\0'; + } + #ifndef WIN32 - if(useSyslog) { - if(!syslog_opened) { - openlog("n2n", LOG_PID, LOG_DAEMON); - syslog_opened = 1; - } - - snprintf(out_buf, sizeof(out_buf), "%s%s", extra_msg, buf); - syslog(LOG_INFO, "%s", out_buf); - } else { - for(i = strlen(file) - 1; i > 0; i--) { - if(file[i] == '/') { - i++; - break; + if(useSyslog) { + if(!syslog_opened) { + openlog("n2n", LOG_PID, LOG_DAEMON); + syslog_opened = 1; + } + + snprintf(out_buf, sizeof(out_buf), "%s%s", extra_msg, buf); + syslog(LOG_INFO, "%s", out_buf); + } else { + for(i = strlen(file) - 1; i > 0; i--) { + if(file[i] == '/') { + i++; + break; + } + } + snprintf(out_buf, sizeof(out_buf), "%s [%s:%d] %s%s", theDate, &file[i], line, extra_msg, buf); + fprintf(traceFile, "%s\n", out_buf); + fflush(traceFile); } - } - snprintf(out_buf, sizeof(out_buf), "%s [%s:%d] %s%s", theDate, &file[i], line, extra_msg, buf); - fprintf(traceFile, "%s\n", out_buf); - fflush(traceFile); - } #else - /* this is the WIN32 code */ - for(i = strlen(file) - 1; i > 0; i--) { - if(file[i] == '\\') { - i++; - break; - } - } - snprintf(out_buf, sizeof(out_buf), "%s [%s:%d] %s%s", theDate, &file[i], line, extra_msg, buf); - fprintf(traceFile, "%s\n", out_buf); - fflush(traceFile); + /* this is the WIN32 code */ + for(i = strlen(file) - 1; i > 0; i--) { + if(file[i] == '\\') { + i++; + break; + } + } + snprintf(out_buf, sizeof(out_buf), "%s [%s:%d] %s%s", theDate, &file[i], line, extra_msg, buf); + fprintf(traceFile, "%s\n", out_buf); + fflush(traceFile); #endif - } + } } @@ -182,64 +182,64 @@ void traceEvent (int eventTraceLevel, char* file, int line, char * format, ...) /* addr should be in network order. Things are so much simpler that way. */ char* intoa (uint32_t /* host order */ addr, char* buf, uint16_t buf_len) { - char *cp, *retStr; - uint8_t byteval; - int n; - - cp = &buf[buf_len]; - *--cp = '\0'; - - n = 4; - do { - byteval = addr & 0xff; - *--cp = byteval % 10 + '0'; - byteval /= 10; - if(byteval > 0) { - *--cp = byteval % 10 + '0'; - byteval /= 10; - if(byteval > 0) { - *--cp = byteval + '0'; - } - } - *--cp = '.'; - addr >>= 8; - } while(--n > 0); + char *cp, *retStr; + uint8_t byteval; + int n; + + cp = &buf[buf_len]; + *--cp = '\0'; + + n = 4; + do { + byteval = addr & 0xff; + *--cp = byteval % 10 + '0'; + byteval /= 10; + if(byteval > 0) { + *--cp = byteval % 10 + '0'; + byteval /= 10; + if(byteval > 0) { + *--cp = byteval + '0'; + } + } + *--cp = '.'; + addr >>= 8; + } while(--n > 0); - /* Convert the string to lowercase */ - retStr = (char*)(cp + 1); + /* Convert the string to lowercase */ + retStr = (char*)(cp + 1); - return(retStr); + return(retStr); } /** Convert subnet prefix bit length to host order subnet mask. */ uint32_t bitlen2mask (uint8_t bitlen) { - uint8_t i; - uint32_t mask = 0; + uint8_t i; + uint32_t mask = 0; - for (i = 1; i <= bitlen; ++i) { - mask |= 1 << (32 - i); - } + for (i = 1; i <= bitlen; ++i) { + mask |= 1 << (32 - i); + } - return mask; + return mask; } /** Convert host order subnet mask to subnet prefix bit length. */ uint8_t mask2bitlen (uint32_t mask) { - uint8_t i, bitlen = 0; + uint8_t i, bitlen = 0; - for (i = 0; i < 32; ++i) { - if ((mask << i) & 0x80000000) { - ++bitlen; - } else { - break; + for (i = 0; i < 32; ++i) { + if((mask << i) & 0x80000000) { + ++bitlen; + } else { + break; + } } - } - return bitlen; + return bitlen; } @@ -248,11 +248,11 @@ uint8_t mask2bitlen (uint32_t mask) { char * macaddr_str (macstr_t buf, const n2n_mac_t mac) { - snprintf(buf, N2N_MACSTR_SIZE, "%02X:%02X:%02X:%02X:%02X:%02X", - mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF, - mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF); + snprintf(buf, N2N_MACSTR_SIZE, "%02X:%02X:%02X:%02X:%02X:%02X", + mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF, + mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF); - return(buf); + return(buf); } /* *********************************************** */ @@ -260,110 +260,110 @@ char * macaddr_str (macstr_t buf, /** Resolve the supernode IP address. * * REVISIT: This is a really bad idea. The edge will block completely while the - * hostname resolution is performed. This could take 15 seconds. + * hostname resolution is performed. This could take 15 seconds. */ int supernode2sock (n2n_sock_t * sn, const n2n_sn_name_t addrIn) { - n2n_sn_name_t addr; - const char *supernode_host; - int rv = 0; - - memcpy(addr, addrIn, N2N_EDGE_SN_HOST_SIZE); - - supernode_host = strtok(addr, ":"); + n2n_sn_name_t addr; + const char *supernode_host; + int rv = 0; - if(supernode_host) { - in_addr_t sn_addr; - char *supernode_port = strtok(NULL, ":"); - const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL}; - struct addrinfo * ainfo = NULL; - int nameerr; + memcpy(addr, addrIn, N2N_EDGE_SN_HOST_SIZE); - if(supernode_port) { - sn->port = atoi(supernode_port); - } else { - traceEvent(TRACE_WARNING, "Bad supernode parameter (-l ) %s %s:%s", - addr, supernode_host, supernode_port); - } + supernode_host = strtok(addr, ":"); - nameerr = getaddrinfo(supernode_host, NULL, &aihints, &ainfo); + if(supernode_host) { + in_addr_t sn_addr; + char *supernode_port = strtok(NULL, ":"); + const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL}; + struct addrinfo * ainfo = NULL; + int nameerr; - if(0 == nameerr) { - struct sockaddr_in * saddr; - - /* ainfo s the head of a linked list if non-NULL. */ - if(ainfo && (PF_INET == ainfo->ai_family)) { - /* It is definitely and IPv4 address -> sockaddr_in */ - saddr = (struct sockaddr_in *)ainfo->ai_addr; + if(supernode_port) { + sn->port = atoi(supernode_port); + } else { + traceEvent(TRACE_WARNING, "Bad supernode parameter (-l ) %s %s:%s", + addr, supernode_host, supernode_port); + } - memcpy(sn->addr.v4, &(saddr->sin_addr.s_addr), IPV4_SIZE); - sn->family = AF_INET; - } else { - /* Should only return IPv4 addresses due to aihints. */ - traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host); - rv = -1; - } + nameerr = getaddrinfo(supernode_host, NULL, &aihints, &ainfo); + + if(0 == nameerr) { + struct sockaddr_in * saddr; + + /* ainfo s the head of a linked list if non-NULL. */ + if(ainfo && (PF_INET == ainfo->ai_family)) { + /* It is definitely and IPv4 address -> sockaddr_in */ + saddr = (struct sockaddr_in *)ainfo->ai_addr; + + memcpy(sn->addr.v4, &(saddr->sin_addr.s_addr), IPV4_SIZE); + sn->family = AF_INET; + } else { + /* Should only return IPv4 addresses due to aihints. */ + traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host); + rv = -1; + } + + freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */ + ainfo = NULL; + } else { + traceEvent(TRACE_WARNING, "Failed to resolve supernode host %s, %d: %s", supernode_host, nameerr, gai_strerror(nameerr)); + rv = -2; + } - freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */ - ainfo = NULL; } else { - traceEvent(TRACE_WARNING, "Failed to resolve supernode host %s, %d: %s", supernode_host, nameerr, gai_strerror(nameerr)); - rv = -2; + traceEvent(TRACE_WARNING, "Wrong supernode parameter (-l )"); + rv = -3; } - } else { - traceEvent(TRACE_WARNING, "Wrong supernode parameter (-l )"); - rv = -3; - } - - return(rv); + return(rv); } /* ************************************** */ struct peer_info* add_sn_to_list_by_mac_or_sock (struct peer_info **sn_list, n2n_sock_t *sock, n2n_mac_t *mac, int *skip_add) { - struct peer_info *scan, *tmp, *peer = NULL; - - if(memcmp(mac, null_mac, sizeof(n2n_mac_t)) != 0) { /* not zero MAC */ - HASH_FIND_PEER(*sn_list, mac, peer); - } - - if(peer == NULL) { /* zero MAC, search by socket */ - HASH_ITER(hh, *sn_list, scan, tmp) { - if(memcmp(&(scan->sock), sock, sizeof(n2n_sock_t)) == 0) { - HASH_DEL(*sn_list, scan); - memcpy(&(scan->mac_addr), mac, sizeof(n2n_mac_t)); - HASH_ADD_PEER(*sn_list, scan); - peer = scan; - break; - } + struct peer_info *scan, *tmp, *peer = NULL; + + if(memcmp(mac, null_mac, sizeof(n2n_mac_t)) != 0) { /* not zero MAC */ + HASH_FIND_PEER(*sn_list, mac, peer); } - if((peer == NULL) && (*skip_add == SN_ADD)) { - peer = (struct peer_info*)calloc(1, sizeof(struct peer_info)); - if(peer) { - sn_selection_criterion_default(&(peer->selection_criterion)); - memcpy(&(peer->sock), sock, sizeof(n2n_sock_t)); - memcpy(&(peer->mac_addr), mac, sizeof(n2n_mac_t)); - HASH_ADD_PEER(*sn_list, peer); - *skip_add = SN_ADD_ADDED; - } + if(peer == NULL) { /* zero MAC, search by socket */ + HASH_ITER(hh, *sn_list, scan, tmp) { + if(memcmp(&(scan->sock), sock, sizeof(n2n_sock_t)) == 0) { + HASH_DEL(*sn_list, scan); + memcpy(&(scan->mac_addr), mac, sizeof(n2n_mac_t)); + HASH_ADD_PEER(*sn_list, scan); + peer = scan; + break; + } + } + + if((peer == NULL) && (*skip_add == SN_ADD)) { + peer = (struct peer_info*)calloc(1, sizeof(struct peer_info)); + if(peer) { + sn_selection_criterion_default(&(peer->selection_criterion)); + memcpy(&(peer->sock), sock, sizeof(n2n_sock_t)); + memcpy(&(peer->mac_addr), mac, sizeof(n2n_mac_t)); + HASH_ADD_PEER(*sn_list, peer); + *skip_add = SN_ADD_ADDED; + } + } } - } - return peer; + return peer; } /* ************************************************ */ uint8_t is_multi_broadcast (const uint8_t * dest_mac) { - int is_broadcast = (memcmp(broadcast_addr, dest_mac, 6) == 0); - int is_multicast = (memcmp(multicast_addr, dest_mac, 3) == 0); - int is_ipv6_multicast = (memcmp(ipv6_multicast_addr, dest_mac, 2) == 0); + int is_broadcast = (memcmp(broadcast_addr, dest_mac, 6) == 0); + int is_multicast = (memcmp(multicast_addr, dest_mac, 3) == 0); + int is_ipv6_multicast = (memcmp(ipv6_multicast_addr, dest_mac, 2) == 0); - return is_broadcast || is_multicast || is_ipv6_multicast; + return is_broadcast || is_multicast || is_ipv6_multicast; } /* http://www.faqs.org/rfcs/rfc908.html */ @@ -373,40 +373,40 @@ uint8_t is_multi_broadcast (const uint8_t * dest_mac) { char* msg_type2str (uint16_t msg_type) { - switch(msg_type) { - case MSG_TYPE_REGISTER: return("MSG_TYPE_REGISTER"); - case MSG_TYPE_DEREGISTER: return("MSG_TYPE_DEREGISTER"); - case MSG_TYPE_PACKET: return("MSG_TYPE_PACKET"); - case MSG_TYPE_REGISTER_ACK: return("MSG_TYPE_REGISTER_ACK"); - case MSG_TYPE_REGISTER_SUPER: return("MSG_TYPE_REGISTER_SUPER"); - case MSG_TYPE_REGISTER_SUPER_ACK: return("MSG_TYPE_REGISTER_SUPER_ACK"); - case MSG_TYPE_REGISTER_SUPER_NAK: return("MSG_TYPE_REGISTER_SUPER_NAK"); - case MSG_TYPE_FEDERATION: return("MSG_TYPE_FEDERATION"); - default: return("???"); - } - - return("???"); + switch(msg_type) { + case MSG_TYPE_REGISTER: return("MSG_TYPE_REGISTER"); + case MSG_TYPE_DEREGISTER: return("MSG_TYPE_DEREGISTER"); + case MSG_TYPE_PACKET: return("MSG_TYPE_PACKET"); + case MSG_TYPE_REGISTER_ACK: return("MSG_TYPE_REGISTER_ACK"); + case MSG_TYPE_REGISTER_SUPER: return("MSG_TYPE_REGISTER_SUPER"); + case MSG_TYPE_REGISTER_SUPER_ACK: return("MSG_TYPE_REGISTER_SUPER_ACK"); + case MSG_TYPE_REGISTER_SUPER_NAK: return("MSG_TYPE_REGISTER_SUPER_NAK"); + case MSG_TYPE_FEDERATION: return("MSG_TYPE_FEDERATION"); + default: return("???"); + } + + return("???"); } /* *********************************************** */ void hexdump (const uint8_t *buf, size_t len) { - size_t i; + size_t i; - if(0 == len) { - return; - } + if(0 == len) { + return; + } - printf("-----------------------------------------------\n"); - for (i = 0; i < len; i++) { - if ((i > 0) && ((i % 16) == 0)) { - printf("\n"); + printf("-----------------------------------------------\n"); + for(i = 0; i < len; i++) { + if((i > 0) && ((i % 16) == 0)) { + printf("\n"); + } + printf("%02X ", buf[i] & 0xFF); } - printf("%02X ", buf[i] & 0xFF); - } - printf("\n"); - printf("-----------------------------------------------\n"); + printf("\n"); + printf("-----------------------------------------------\n"); } @@ -414,132 +414,132 @@ void hexdump (const uint8_t *buf, size_t len) { void print_n2n_version () { - printf("Welcome to n2n v.%s for %s\n" - "Built on %s\n" - "Copyright 2007-2020 - ntop.org and contributors\n\n", - GIT_RELEASE, PACKAGE_OSNAME, PACKAGE_BUILDDATE); + printf("Welcome to n2n v.%s for %s\n" + "Built on %s\n" + "Copyright 2007-2020 - ntop.org and contributors\n\n", + GIT_RELEASE, PACKAGE_OSNAME, PACKAGE_BUILDDATE); } /* *********************************************** */ size_t purge_expired_registrations (struct peer_info ** peer_list, time_t* p_last_purge, int timeout) { - time_t now = time(NULL); - size_t num_reg = 0; + time_t now = time(NULL); + size_t num_reg = 0; - if((now - (*p_last_purge)) < timeout) { - return 0; - } + if((now - (*p_last_purge)) < timeout) { + return 0; + } - traceEvent(TRACE_DEBUG, "Purging old registrations"); + traceEvent(TRACE_DEBUG, "Purging old registrations"); - num_reg = purge_peer_list(peer_list, now - REGISTRATION_TIMEOUT); + num_reg = purge_peer_list(peer_list, now - REGISTRATION_TIMEOUT); - (*p_last_purge) = now; - traceEvent(TRACE_DEBUG, "Remove %ld registrations", num_reg); + (*p_last_purge) = now; + traceEvent(TRACE_DEBUG, "Remove %ld registrations", num_reg); - return num_reg; + return num_reg; } /** Purge old items from the peer_list and return the number of items that were removed. */ size_t purge_peer_list (struct peer_info ** peer_list, time_t purge_before) { - struct peer_info *scan, *tmp; - size_t retval = 0; + struct peer_info *scan, *tmp; + size_t retval = 0; - HASH_ITER(hh, *peer_list, scan, tmp) { - if((scan->purgeable == SN_PURGEABLE) && (scan->last_seen < purge_before)) { - HASH_DEL(*peer_list, scan); - retval++; - free(scan); + HASH_ITER(hh, *peer_list, scan, tmp) { + if((scan->purgeable == SN_PURGEABLE) && (scan->last_seen < purge_before)) { + HASH_DEL(*peer_list, scan); + retval++; + free(scan); + } } - } - return retval; + return retval; } /** Purge all items from the peer_list and return the number of items that were removed. */ size_t clear_peer_list (struct peer_info ** peer_list) { - struct peer_info *scan, *tmp; - size_t retval = 0; + struct peer_info *scan, *tmp; + size_t retval = 0; - HASH_ITER(hh, *peer_list, scan, tmp) { - HASH_DEL(*peer_list, scan); - retval++; - free(scan); - } + HASH_ITER(hh, *peer_list, scan, tmp) { + HASH_DEL(*peer_list, scan); + retval++; + free(scan); + } - return retval; + return retval; } static uint8_t hex2byte (const char * s) { - char tmp[3]; - tmp[0] = s[0]; - tmp[1] = s[1]; - tmp[2] = 0; /* NULL term */ + char tmp[3]; + tmp[0] = s[0]; + tmp[1] = s[1]; + tmp[2] = 0; /* NULL term */ - return((uint8_t)strtol(tmp, NULL, 16)); + return((uint8_t)strtol(tmp, NULL, 16)); } extern int str2mac (uint8_t * outmac /* 6 bytes */, const char * s) { - size_t i; - - /* break it down as one case for the first "HH", the 5 x through loop for - * each ":HH" where HH is a two hex nibbles in ASCII. */ + size_t i; - *outmac = hex2byte(s); - ++outmac; - s += 2; /* don't skip colon yet - helps generalise loop. */ + /* break it down as one case for the first "HH", the 5 x through loop for + * each ":HH" where HH is a two hex nibbles in ASCII. */ - for(i = 1; i < 6; ++i) { - s += 1; *outmac = hex2byte(s); ++outmac; - s += 2; - } + s += 2; /* don't skip colon yet - helps generalise loop. */ - return 0; /* ok */ + for(i = 1; i < 6; ++i) { + s += 1; + *outmac = hex2byte(s); + ++outmac; + s += 2; + } + + return 0; /* ok */ } extern char * sock_to_cstr (n2n_sock_str_t out, const n2n_sock_t * sock) { - if(NULL == out) { - return NULL; - } - memset(out, 0, N2N_SOCKBUF_SIZE); - - if(AF_INET6 == sock->family) { - /* INET6 not written yet */ - snprintf(out, N2N_SOCKBUF_SIZE, "XXXX:%hu", sock->port); - return out; - } else { - const uint8_t * a = sock->addr.v4; - - snprintf(out, N2N_SOCKBUF_SIZE, "%hu.%hu.%hu.%hu:%hu", - (unsigned short)(a[0] & 0xff), - (unsigned short)(a[1] & 0xff), - (unsigned short)(a[2] & 0xff), - (unsigned short)(a[3] & 0xff), - (unsigned short)sock->port); - return out; - } + if(NULL == out) { + return NULL; + } + memset(out, 0, N2N_SOCKBUF_SIZE); + + if(AF_INET6 == sock->family) { + /* INET6 not written yet */ + snprintf(out, N2N_SOCKBUF_SIZE, "XXXX:%hu", sock->port); + return out; + } else { + const uint8_t * a = sock->addr.v4; + + snprintf(out, N2N_SOCKBUF_SIZE, "%hu.%hu.%hu.%hu:%hu", + (unsigned short)(a[0] & 0xff), + (unsigned short)(a[1] & 0xff), + (unsigned short)(a[2] & 0xff), + (unsigned short)(a[3] & 0xff), + (unsigned short)sock->port); + return out; + } } char *ip_subnet_to_str (dec_ip_bit_str_t buf, const n2n_ip_subnet_t *ipaddr) { - snprintf(buf, sizeof(dec_ip_bit_str_t), "%hhu.%hhu.%hhu.%hhu/%hhu", - (uint8_t) ((ipaddr->net_addr >> 24) & 0xFF), - (uint8_t) ((ipaddr->net_addr >> 16) & 0xFF), - (uint8_t) ((ipaddr->net_addr >> 8) & 0xFF), - (uint8_t) (ipaddr->net_addr & 0xFF), - ipaddr->net_bitlen); + snprintf(buf, sizeof(dec_ip_bit_str_t), "%hhu.%hhu.%hhu.%hhu/%hhu", + (uint8_t) ((ipaddr->net_addr >> 24) & 0xFF), + (uint8_t) ((ipaddr->net_addr >> 16) & 0xFF), + (uint8_t) ((ipaddr->net_addr >> 8) & 0xFF), + (uint8_t) (ipaddr->net_addr & 0xFF), + ipaddr->net_bitlen); - return buf; + return buf; } @@ -547,30 +547,30 @@ char *ip_subnet_to_str (dec_ip_bit_str_t buf, const n2n_ip_subnet_t *ipaddr) { int sock_equal (const n2n_sock_t * a, const n2n_sock_t * b) { - if(a->port != b->port) { - return(0); - } - - if(a->family != b->family) { - return(0); - } - - switch(a->family) { - case AF_INET: - if(memcmp(a->addr.v4, b->addr.v4, IPV4_SIZE)) { + if(a->port != b->port) { return(0); - } - break; + } - default: - if(memcmp(a->addr.v6, b->addr.v6, IPV6_SIZE)) { + if(a->family != b->family) { return(0); - } - break; - } + } - /* equal */ - return(1); + switch(a->family) { + case AF_INET: + if(memcmp(a->addr.v4, b->addr.v4, IPV4_SIZE)) { + return(0); + } + break; + + default: + if(memcmp(a->addr.v6, b->addr.v6, IPV6_SIZE)) { + return(0); + } + break; + } + + /* equal */ + return(1); } /* *********************************************** */ @@ -578,23 +578,23 @@ int sock_equal (const n2n_sock_t * a, #if defined(WIN32) int gettimeofday (struct timeval *tp, void *tzp) { - time_t clock; - struct tm tm; - SYSTEMTIME wtm; - - GetLocalTime(&wtm); - tm.tm_year = wtm.wYear - 1900; - tm.tm_mon = wtm.wMonth - 1; - tm.tm_mday = wtm.wDay; - tm.tm_hour = wtm.wHour; - tm.tm_min = wtm.wMinute; - tm.tm_sec = wtm.wSecond; - tm.tm_isdst = -1; - clock = mktime(&tm); - tp->tv_sec = clock; - tp->tv_usec = wtm.wMilliseconds * 1000; - - return (0); + time_t clock; + struct tm tm; + SYSTEMTIME wtm; + + GetLocalTime(&wtm); + tm.tm_year = wtm.wYear - 1900; + tm.tm_mon = wtm.wMonth - 1; + tm.tm_mday = wtm.wDay; + tm.tm_hour = wtm.wHour; + tm.tm_min = wtm.wMinute; + tm.tm_sec = wtm.wSecond; + tm.tm_isdst = -1; + clock = mktime(&tm); + tp->tv_sec = clock; + tp->tv_usec = wtm.wMilliseconds * 1000; + + return (0); } #endif @@ -602,28 +602,28 @@ int gettimeofday (struct timeval *tp, void *tzp) { // returns a time stamp for use with replay protection uint64_t time_stamp (void) { - struct timeval tod; - uint64_t micro_seconds; - - gettimeofday (&tod, NULL); - /* We will (roughly) calculate the microseconds since 1970 leftbound into the return value. - The leading 32 bits are used for tv_sec. The following 20 bits (sufficent as microseconds - fraction never exceeds 1,000,000,) encode the value tv_usec. The remaining lowest 12 bits - are kept random for use in IV */ - micro_seconds = n2n_rand(); - micro_seconds = ( (((uint64_t)(tod.tv_sec) << 32) + (tod.tv_usec << 12)) - | (micro_seconds >> 52) ); - // more exact but more costly due to the multiplication: - // micro_seconds = (tod.tv_sec * 1000000 + tod.tv_usec) << 12) | ... - - return (micro_seconds); + struct timeval tod; + uint64_t micro_seconds; + + gettimeofday (&tod, NULL); + /* We will (roughly) calculate the microseconds since 1970 leftbound into the return value. + The leading 32 bits are used for tv_sec. The following 20 bits (sufficent as microseconds + fraction never exceeds 1,000,000,) encode the value tv_usec. The remaining lowest 12 bits + are kept random for use in IV */ + micro_seconds = n2n_rand(); + micro_seconds = ((((uint64_t)(tod.tv_sec) << 32) + (tod.tv_usec << 12)) + | (micro_seconds >> 52)); + // more exact but more costly due to the multiplication: + // micro_seconds = (tod.tv_sec * 1000000 + tod.tv_usec) << 12) | ... + + return (micro_seconds); } // returns an initial time stamp for use with replay protection uint64_t initial_time_stamp (void) { - return (time_stamp() - TIME_STAMP_FRAME); + return (time_stamp() - TIME_STAMP_FRAME); } @@ -631,36 +631,36 @@ uint64_t initial_time_stamp (void) { // and, in case of validity, updates the "last valid time stamp" int time_stamp_verify_and_update (uint64_t stamp, uint64_t * previous_stamp, int allow_jitter) { - int64_t diff; // do not change to unsigned - - // is it around current time (+/- allowed deviation TIME_STAMP_FRAME)? - diff = stamp - time_stamp(); - // abs() - diff = (diff < 0 ? -diff : diff); - if(diff >= TIME_STAMP_FRAME) { - traceEvent(TRACE_DEBUG, "time_stamp_verify_and_update found a timestamp out of allowed frame."); - return (0); // failure - } - - // if applicable: is it higher than previous time stamp (including allowed deviation of TIME_STAMP_JITTER)? - if(NULL != previous_stamp) { - // always reset lowest three (random) nybbles -- important in case of no jitter, do not if() to avoid jumping - stamp = (stamp >> 12) << 12; - *previous_stamp = (*previous_stamp >> 12) << 12; - - diff = stamp - *previous_stamp; - if (allow_jitter) { - diff += TIME_STAMP_JITTER; + int64_t diff; // do not change to unsigned + + // is it around current time (+/- allowed deviation TIME_STAMP_FRAME)? + diff = stamp - time_stamp(); + // abs() + diff = (diff < 0 ? -diff : diff); + if(diff >= TIME_STAMP_FRAME) { + traceEvent(TRACE_DEBUG, "time_stamp_verify_and_update found a timestamp out of allowed frame."); + return (0); // failure } - if(diff <= 0) { - traceEvent(TRACE_DEBUG, "time_stamp_verify_and_update found a timestamp too old compared to previous."); - return (0); // failure + // if applicable: is it higher than previous time stamp (including allowed deviation of TIME_STAMP_JITTER)? + if(NULL != previous_stamp) { + // always reset lowest three (random) nybbles -- important in case of no jitter, do not if() to avoid jumping + stamp = (stamp >> 12) << 12; + *previous_stamp = (*previous_stamp >> 12) << 12; + + diff = stamp - *previous_stamp; + if (allow_jitter) { + diff += TIME_STAMP_JITTER; + } + + if(diff <= 0) { + traceEvent(TRACE_DEBUG, "time_stamp_verify_and_update found a timestamp too old compared to previous."); + return (0); // failure + } + // for not allowing to exploit the allowed TIME_STAMP_JITTER to "turn the clock backwards", + // set the higher of the values + *previous_stamp = (stamp > *previous_stamp ? stamp : *previous_stamp); } - // for not allowing to exploit the allowed TIME_STAMP_JITTER to "turn the clock backwards", - // set the higher of the values - *previous_stamp = (stamp > *previous_stamp ? stamp : *previous_stamp); - } - return (1); // success + return (1); // success } diff --git a/src/n2n_regex.c b/src/n2n_regex.c index be6b6bf..5827da3 100644 --- a/src/n2n_regex.c +++ b/src/n2n_regex.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -29,21 +29,21 @@ * * Supports: * --------- - * '.' Dot, matches any character - * '^' Start anchor, matches beginning of string -- NOTE: currently disabled (checking for full matches anyway) - * '$' End anchor, matches end of string -- NOTE: currently disabled (checking for full matches anyway) - * '*' Asterisk, match zero or more (greedy) - * '+' Plus, match one or more (greedy) - * '?' Question, match zero or one (non-greedy) - * '[abc]' Character class, match if one of {'a', 'b', 'c'} - * '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} -- NOTE: feature is currently broken! - * '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z } - * '\s' Whitespace, \t \f \r \n \v and spaces - * '\S' Non-whitespace - * '\w' Alphanumeric, [a-zA-Z0-9_] - * '\W' Non-alphanumeric - * '\d' Digits, [0-9] - * '\D' Non-digits + * '.' Dot, matches any character + * '^' Start anchor, matches beginning of string -- NOTE: currently disabled (checking for full matches anyway) + * '$' End anchor, matches end of string -- NOTE: currently disabled (checking for full matches anyway) + * '*' Asterisk, match zero or more (greedy) + * '+' Plus, match one or more (greedy) + * '?' Question, match zero or one (non-greedy) + * '[abc]' Character class, match if one of {'a', 'b', 'c'} + * '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} -- NOTE: feature is currently broken! + * '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z } + * '\s' Whitespace, \t \f \r \n \v and spaces + * '\S' Non-whitespace + * '\w' Alphanumeric, [a-zA-Z0-9_] + * '\W' Non-alphanumeric + * '\d' Digits, [0-9] + * '\D' Non-digits * * */ @@ -54,18 +54,18 @@ /* Definitions: */ -#define MAX_REGEXP_OBJECTS 30 /* Max number of regex symbols in expression. */ -#define MAX_CHAR_CLASS_LEN 40 /* Max length of character-class buffer in. */ +#define MAX_REGEXP_OBJECTS 30 /* Max number of regex symbols in expression. */ +#define MAX_CHAR_CLASS_LEN 40 /* Max length of character-class buffer in. */ enum { UNUSED, DOT, BEGIN, END, QUESTIONMARK, STAR, PLUS, CHAR_TYPE, CHAR_CLASS, INV_CHAR_CLASS, DIGIT, NOT_DIGIT, ALPHA, NOT_ALPHA, WHITESPACE, NOT_WHITESPACE, /* BRANCH */ }; typedef struct regex_t { - unsigned char type; /* CHAR_TYPE, STAR, etc. */ - union { - unsigned char ch; /* the character itself */ - unsigned char* ccl; /* OR a pointer to characters in class */ - }; + unsigned char type; /* CHAR_TYPE, STAR, etc. */ + union { + unsigned char ch; /* the character itself */ + unsigned char* ccl; /* OR a pointer to characters in class */ + }; } regex_t; @@ -89,187 +89,187 @@ static int ismetachar (char c); /* Public functions: */ int re_match (const char* pattern, const char* text, int* matchlength) { - re_t re_p; /* pointer to (to be created) copy of compiled regex */ - int ret = -1; + re_t re_p; /* pointer to (to be created) copy of compiled regex */ + int ret = -1; - re_p = re_compile (pattern); - ret = re_matchp(re_p, text, matchlength); - free(re_p); + re_p = re_compile (pattern); + ret = re_matchp(re_p, text, matchlength); + free(re_p); - return(ret); + return(ret); } int re_matchp (re_t pattern, const char* text, int* matchlength) { - *matchlength = 0; + *matchlength = 0; - if(pattern != 0) { - if(pattern[0].type == BEGIN) { - return ((matchpattern(&pattern[1], text, matchlength)) ? 0 : -1); - } else { - int idx = -1; - - do { - idx += 1; - - if(matchpattern(pattern, text, matchlength)) { - if(text[0] == '\0') { - return -1; - } - return idx; + if(pattern != 0) { + if(pattern[0].type == BEGIN) { + return ((matchpattern(&pattern[1], text, matchlength)) ? 0 : -1); + } else { + int idx = -1; + + do { + idx += 1; + + if(matchpattern(pattern, text, matchlength)) { + if(text[0] == '\0') { + return -1; + } + return idx; + } + } while(*text++ != '\0'); } - } while(*text++ != '\0'); } - } - return -1; + return -1; } re_t re_compile (const char* pattern) { - /* The sizes of the two static arrays below substantiates the static RAM usage of this module. - MAX_REGEXP_OBJECTS is the max number of symbols in the expression. - MAX_CHAR_CLASS_LEN determines the size of buffer for chars in all char-classes in the expression. */ - static regex_t re_compiled[MAX_REGEXP_OBJECTS]; - re_t re_p; /* pointer to (to be created) copy of compiled regex in re_compiled */ - - static unsigned char ccl_buf[MAX_CHAR_CLASS_LEN]; - int ccl_bufidx = 1; - - char c; /* current char in pattern */ - int i = 0; /* index into pattern */ - int j = 0; /* index into re_compiled */ - - while(pattern[i] != '\0' && (j+1 < MAX_REGEXP_OBJECTS)) { - c = pattern[i]; - - switch(c) { - /* Meta-characters: */ -// case '^': { re_compiled[j].type = BEGIN; } break; <-- disabled (always full matches) -// case '$': { re_compiled[j].type = END; } break; <-- disabled (always full matches) - case '.': { re_compiled[j].type = DOT; } break; - case '*': { re_compiled[j].type = STAR; } break; - case '+': { re_compiled[j].type = PLUS; } break; - case '?': { re_compiled[j].type = QUESTIONMARK; } break; -/* case '|': { re_compiled[j].type = BRANCH; } break; <-- not working properly */ - - /* Escaped character-classes (\s \w ...): */ - case '\\': { - if(pattern[i+1] != '\0') { - /* Skip the escape-char '\\' */ - i += 1; - /* ... and check the next */ - switch(pattern[i]) { - /* Meta-character: */ - case 'd': { re_compiled[j].type = DIGIT; } break; - case 'D': { re_compiled[j].type = NOT_DIGIT; } break; - case 'w': { re_compiled[j].type = ALPHA; } break; - case 'W': { re_compiled[j].type = NOT_ALPHA; } break; - case 's': { re_compiled[j].type = WHITESPACE; } break; - case 'S': { re_compiled[j].type = NOT_WHITESPACE; } break; - - /* Escaped character, e.g. '.' */ - default: { - re_compiled[j].type = CHAR_TYPE; - re_compiled[j].ch = pattern[i]; + /* The sizes of the two static arrays below substantiates the static RAM usage of this module. + MAX_REGEXP_OBJECTS is the max number of symbols in the expression. + MAX_CHAR_CLASS_LEN determines the size of buffer for chars in all char-classes in the expression. */ + static regex_t re_compiled[MAX_REGEXP_OBJECTS]; + re_t re_p; /* pointer to (to be created) copy of compiled regex in re_compiled */ + + static unsigned char ccl_buf[MAX_CHAR_CLASS_LEN]; + int ccl_bufidx = 1; + + char c; /* current char in pattern */ + int i = 0; /* index into pattern */ + int j = 0; /* index into re_compiled */ + + while(pattern[i] != '\0' && (j + 1 < MAX_REGEXP_OBJECTS)) { + c = pattern[i]; + + switch(c) { + /* Meta-characters: */ + // case '^': { re_compiled[j].type = BEGIN; } break; <-- disabled (always full matches) + // case '$': { re_compiled[j].type = END; } break; <-- disabled (always full matches) + case '.': { re_compiled[j].type = DOT; } break; + case '*': { re_compiled[j].type = STAR; } break; + case '+': { re_compiled[j].type = PLUS; } break; + case '?': { re_compiled[j].type = QUESTIONMARK; } break; + /* case '|': { re_compiled[j].type = BRANCH; } break; <-- not working properly */ + + /* Escaped character-classes (\s \w ...): */ + case '\\': { + if(pattern[i + 1] != '\0') { + /* Skip the escape-char '\\' */ + i += 1; + /* ... and check the next */ + switch(pattern[i]) { + /* Meta-character: */ + case 'd': { re_compiled[j].type = DIGIT; } break; + case 'D': { re_compiled[j].type = NOT_DIGIT; } break; + case 'w': { re_compiled[j].type = ALPHA; } break; + case 'W': { re_compiled[j].type = NOT_ALPHA; } break; + case 's': { re_compiled[j].type = WHITESPACE; } break; + case 'S': { re_compiled[j].type = NOT_WHITESPACE; } break; + + /* Escaped character, e.g. '.' */ + default: { + re_compiled[j].type = CHAR_TYPE; + re_compiled[j].ch = pattern[i]; + } break; + } + } + /* '\\' as last char in pattern -> invalid regular expression. */ + /* + else + { + re_compiled[j].type = CHAR_TYPE; + re_compiled[j].ch = pattern[i]; + } + */ } break; - } - } - /* '\\' as last char in pattern -> invalid regular expression. */ -/* - else - { - re_compiled[j].type = CHAR_TYPE; - re_compiled[j].ch = pattern[i]; - } -*/ - } break; - - /* Character class: */ - case '[': { - /* Remember where the char-buffer starts. */ - int buf_begin = ccl_bufidx; - /* Look-ahead to determine if negated */ - if(pattern[i+1] == '^') { - re_compiled[j].type = INV_CHAR_CLASS; - i += 1; /* Increment i to avoid including '^' in the char-buffer */ - } else { - re_compiled[j].type = CHAR_CLASS; - } + /* Character class: */ + case '[': { + /* Remember where the char-buffer starts. */ + int buf_begin = ccl_bufidx; + + /* Look-ahead to determine if negated */ + if(pattern[i+1] == '^') { + re_compiled[j].type = INV_CHAR_CLASS; + i += 1; /* Increment i to avoid including '^' in the char-buffer */ + } else { + re_compiled[j].type = CHAR_CLASS; + } + + /* Copy characters inside [..] to buffer */ + while((pattern[++i] != ']') + && (pattern[i] != '\0')) /* Missing ] */ + { + if(pattern[i] == '\\') { + if(ccl_bufidx >= MAX_CHAR_CLASS_LEN - 1) { + //fputs("exceeded internal buffer!\n", stderr); + return 0; + } + ccl_buf[ccl_bufidx++] = pattern[i++]; + } else if(ccl_bufidx >= MAX_CHAR_CLASS_LEN) { + //fputs("exceeded internal buffer!\n", stderr); + return 0; + } + ccl_buf[ccl_bufidx++] = pattern[i]; + } + if(ccl_bufidx >= MAX_CHAR_CLASS_LEN) { + /* Catches cases such as [00000000000000000000000000000000000000][ */ + //fputs("exceeded internal buffer!\n", stderr); + return 0; + } + /* Null-terminate string end */ + ccl_buf[ccl_bufidx++] = 0; + re_compiled[j].ccl = &ccl_buf[buf_begin]; + } break; - /* Copy characters inside [..] to buffer */ - while( (pattern[++i] != ']') - && (pattern[i] != '\0')) /* Missing ] */ - { - if(pattern[i] == '\\') { - if(ccl_bufidx >= MAX_CHAR_CLASS_LEN - 1) { - //fputs("exceeded internal buffer!\n", stderr); - return 0; - } - ccl_buf[ccl_bufidx++] = pattern[i++]; - } else if(ccl_bufidx >= MAX_CHAR_CLASS_LEN) { - //fputs("exceeded internal buffer!\n", stderr); - return 0; - } - ccl_buf[ccl_bufidx++] = pattern[i]; - } - if(ccl_bufidx >= MAX_CHAR_CLASS_LEN) { - /* Catches cases such as [00000000000000000000000000000000000000][ */ - //fputs("exceeded internal buffer!\n", stderr); - return 0; + /* Other characters: */ + default: { + re_compiled[j].type = CHAR_TYPE; + re_compiled[j].ch = c; + } break; } - /* Null-terminate string end */ - ccl_buf[ccl_bufidx++] = 0; - re_compiled[j].ccl = &ccl_buf[buf_begin]; - } break; - - /* Other characters: */ - default: { - re_compiled[j].type = CHAR_TYPE; - re_compiled[j].ch = c; - } break; + i += 1; + j += 1; } - i += 1; - j += 1; - } - /* 'UNUSED' is a sentinel used to indicate end-of-pattern */ - re_compiled[j].type = UNUSED; + /* 'UNUSED' is a sentinel used to indicate end-of-pattern */ + re_compiled[j].type = UNUSED; - re_p = (re_t)calloc(1, sizeof(re_compiled)); - memcpy (re_p, re_compiled, sizeof(re_compiled)); + re_p = (re_t)calloc(1, sizeof(re_compiled)); + memcpy (re_p, re_compiled, sizeof(re_compiled)); - return (re_t) re_p; + return (re_t) re_p; } void re_print (regex_t* pattern) { - const char* types[] = { "UNUSED", "DOT", "BEGIN", "END", "QUESTIONMARK", "STAR", "PLUS", "CHAR_TYPE", "CHAR_CLASS", "INV_CHAR_CLASS", "DIGIT", "NOT_DIGIT", "ALPHA", "NOT_ALPHA", "WHITESPACE" , "NOT_WHITESPACE", /* "BRANCH" */ }; - int i; - int j; - char c; + const char* types[] = { "UNUSED", "DOT", "BEGIN", "END", "QUESTIONMARK", "STAR", "PLUS", "CHAR_TYPE", "CHAR_CLASS", "INV_CHAR_CLASS", "DIGIT", "NOT_DIGIT", "ALPHA", "NOT_ALPHA", "WHITESPACE" , "NOT_WHITESPACE", /* "BRANCH" */ }; + int i; + int j; + char c; - for(i = 0; i < MAX_REGEXP_OBJECTS; ++i) { - if(pattern[i].type == UNUSED) { - break; - } + for(i = 0; i < MAX_REGEXP_OBJECTS; ++i) { + if(pattern[i].type == UNUSED) { + break; + } - printf("type: %s", types[pattern[i].type]); - if((pattern[i].type == CHAR_CLASS) || (pattern[i].type == INV_CHAR_CLASS)) { - printf(" ["); - for(j = 0; j < MAX_CHAR_CLASS_LEN; ++j) { - c = pattern[i].ccl[j]; - if((c == '\0') || (c == ']')) { - break; + printf("type: %s", types[pattern[i].type]); + if((pattern[i].type == CHAR_CLASS) || (pattern[i].type == INV_CHAR_CLASS)) { + printf(" ["); + for(j = 0; j < MAX_CHAR_CLASS_LEN; ++j) { + c = pattern[i].ccl[j]; + if((c == '\0') || (c == ']')) { + break; + } + printf("%c", c); + } + printf("]"); + } else if(pattern[i].type == CHAR_TYPE) { + printf(" '%c'", pattern[i].ch); } - printf("%c", c); - } - printf("]"); - } else if(pattern[i].type == CHAR_TYPE) { - printf(" '%c'", pattern[i].ch); + printf("\n"); } - printf("\n"); - } } @@ -277,154 +277,154 @@ void re_print (regex_t* pattern) { /* Private functions: */ static int matchdigit (char c) { - return ((c >= '0') && (c <= '9')); + return ((c >= '0') && (c <= '9')); } static int matchalpha (char c) { - return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); } static int matchwhitespace (char c) { - return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\f') || (c == '\v')); + return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\f') || (c == '\v')); } static int matchalphanum (char c) { - return ((c == '_') || matchalpha(c) || matchdigit(c)); + return ((c == '_') || matchalpha(c) || matchdigit(c)); } static int matchrange (char c, const char* str) { - return ((c != '-') && (str[0] != '\0') && (str[0] != '-') && - (str[1] == '-') && (str[1] != '\0') && - (str[2] != '\0') && ((c >= str[0]) && (c <= str[2]))); + return ((c != '-') && (str[0] != '\0') && (str[0] != '-') && + (str[1] == '-') && (str[1] != '\0') && + (str[2] != '\0') && ((c >= str[0]) && (c <= str[2]))); } static int matchdot (char c) { - return ((c != '\n') && (c != '\r')); + return ((c != '\n') && (c != '\r')); } static int ismetachar (char c) { - return ((c == 's') || (c == 'S') || (c == 'w') || (c == 'W') || (c == 'd') || (c == 'D')); + return ((c == 's') || (c == 'S') || (c == 'w') || (c == 'W') || (c == 'd') || (c == 'D')); } static int matchmetachar (char c, const char* str) { - switch(str[0]) { - case 'd': return matchdigit(c); - case 'D': return !matchdigit(c); - case 'w': return matchalphanum(c); - case 'W': return !matchalphanum(c); - case 's': return matchwhitespace(c); - case 'S': return !matchwhitespace(c); - default: return (c == str[0]); - } + switch(str[0]) { + case 'd': return matchdigit(c); + case 'D': return !matchdigit(c); + case 'w': return matchalphanum(c); + case 'W': return !matchalphanum(c); + case 's': return matchwhitespace(c); + case 'S': return !matchwhitespace(c); + default: return (c == str[0]); + } } static int matchcharclass (char c, const char* str) { - do { - if(matchrange(c, str)) { - return 1; - } else if(str[0] == '\\') { - /* Escape-char: increment str-ptr and match on next char */ - str += 1; - if(matchmetachar(c, str)) { - return 1; - } else if((c == str[0]) && !ismetachar(c)) { - return 1; - } - } else if(c == str[0]) { - if(c == '-') { - return ((str[-1] == '\0') || (str[1] == '\0')); - } else { - return 1; - } - } - } while(*str++ != '\0'); + do { + if(matchrange(c, str)) { + return 1; + } else if(str[0] == '\\') { + /* Escape-char: increment str-ptr and match on next char */ + str += 1; + if(matchmetachar(c, str)) { + return 1; + } else if((c == str[0]) && !ismetachar(c)) { + return 1; + } + } else if(c == str[0]) { + if(c == '-') { + return ((str[-1] == '\0') || (str[1] == '\0')); + } else { + return 1; + } + } + } while(*str++ != '\0'); - return 0; + return 0; } static int matchone (regex_t p, char c) { - switch(p.type) { - case DOT: return matchdot(c); - case CHAR_CLASS: return matchcharclass(c, (const char*)p.ccl); - case INV_CHAR_CLASS: return !matchcharclass(c, (const char*)p.ccl); - case DIGIT: return matchdigit(c); - case NOT_DIGIT: return !matchdigit(c); - case ALPHA: return matchalphanum(c); - case NOT_ALPHA: return !matchalphanum(c); - case WHITESPACE: return matchwhitespace(c); - case NOT_WHITESPACE: return !matchwhitespace(c); - default: return (p.ch == c); - } + switch(p.type) { + case DOT: return matchdot(c); + case CHAR_CLASS: return matchcharclass(c, (const char*)p.ccl); + case INV_CHAR_CLASS: return !matchcharclass(c, (const char*)p.ccl); + case DIGIT: return matchdigit(c); + case NOT_DIGIT: return !matchdigit(c); + case ALPHA: return matchalphanum(c); + case NOT_ALPHA: return !matchalphanum(c); + case WHITESPACE: return matchwhitespace(c); + case NOT_WHITESPACE: return !matchwhitespace(c); + default: return (p.ch == c); + } } static int matchstar (regex_t p, regex_t* pattern, const char* text, int* matchlength) { - int prelen = *matchlength; - const char* prepoint = text; + int prelen = *matchlength; + const char* prepoint = text; - while((text[0] != '\0') && matchone(p, *text)) { - text++; - (*matchlength)++; - } + while((text[0] != '\0') && matchone(p, *text)) { + text++; + (*matchlength)++; + } - while(text >= prepoint) { - if(matchpattern(pattern, text--, matchlength)) { - return 1; + while(text >= prepoint) { + if(matchpattern(pattern, text--, matchlength)) { + return 1; + } + (*matchlength)--; } - (*matchlength)--; - } - *matchlength = prelen; + *matchlength = prelen; - return 0; + return 0; } static int matchplus (regex_t p, regex_t* pattern, const char* text, int* matchlength) { - const char* prepoint = text; + const char* prepoint = text; - while((text[0] != '\0') && matchone(p, *text)) { - text++; - (*matchlength)++; - } + while((text[0] != '\0') && matchone(p, *text)) { + text++; + (*matchlength)++; + } - while(text > prepoint) { - if(matchpattern(pattern, text--, matchlength)) { - return 1; + while(text > prepoint) { + if(matchpattern(pattern, text--, matchlength)) { + return 1; + } + (*matchlength)--; } - (*matchlength)--; - } - return 0; + return 0; } static int matchquestion (regex_t p, regex_t* pattern, const char* text, int* matchlength) { - if(p.type == UNUSED) { - return 1; - } - - if(matchpattern(pattern, text, matchlength)) { - return 1; - } + if(p.type == UNUSED) { + return 1; + } - if(*text && matchone(p, *text++)) { if(matchpattern(pattern, text, matchlength)) { - (*matchlength)++; - return 1; + return 1; + } + + if(*text && matchone(p, *text++)) { + if(matchpattern(pattern, text, matchlength)) { + (*matchlength)++; + return 1; + } } - } - return 0; + return 0; } @@ -433,23 +433,23 @@ static int matchquestion (regex_t p, regex_t* pattern, const char* text, int* ma /* Recursive matching */ static int matchpattern (regex_t* pattern, const char* text, int *matchlength) { - int pre = *matchlength; - - if((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK)) { - return matchquestion(pattern[1], &pattern[2], text, matchlength); - } else if(pattern[1].type == STAR) { - return matchstar(pattern[0], &pattern[2], text, matchlength); - } else if(pattern[1].type == PLUS) { - return matchplus(pattern[0], &pattern[2], text, matchlength); - } else if((pattern[0].type == END) && pattern[1].type == UNUSED) { - return text[0] == '\0'; - } else if((text[0] != '\0') && matchone(pattern[0], text[0])) { - (*matchlength)++; - return matchpattern(&pattern[1], text+1); - } else { - *matchlength = pre; - return 0; - } + int pre = *matchlength; + + if((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK)) { + return matchquestion(pattern[1], &pattern[2], text, matchlength); + } else if(pattern[1].type == STAR) { + return matchstar(pattern[0], &pattern[2], text, matchlength); + } else if(pattern[1].type == PLUS) { + return matchplus(pattern[0], &pattern[2], text, matchlength); + } else if((pattern[0].type == END) && pattern[1].type == UNUSED) { + return text[0] == '\0'; + } else if((text[0] != '\0') && matchone(pattern[0], text[0])) { + (*matchlength)++; + return matchpattern(&pattern[1], text+1); + } else { + *matchlength = pre; + return 0; + } } #else @@ -457,30 +457,30 @@ static int matchpattern (regex_t* pattern, const char* text, int *matchlength) { /* Iterative matching */ static int matchpattern (regex_t* pattern, const char* text, int* matchlength) { - int pre = *matchlength; - - do { - if((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK)) { - return matchquestion(pattern[0], &pattern[2], text, matchlength); - } else if(pattern[1].type == STAR) { - return matchstar(pattern[0], &pattern[2], text, matchlength); - } else if(pattern[1].type == PLUS) { - return matchplus(pattern[0], &pattern[2], text, matchlength); - } else if((pattern[0].type == END) && pattern[1].type == UNUSED) { - return (text[0] == '\0'); - } -/* Branching is not working properly - else if (pattern[1].type == BRANCH) - { - return (matchpattern(pattern, text) || matchpattern(&pattern[2], text)); - } + int pre = *matchlength; + + do { + if((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK)) { + return matchquestion(pattern[0], &pattern[2], text, matchlength); + } else if(pattern[1].type == STAR) { + return matchstar(pattern[0], &pattern[2], text, matchlength); + } else if(pattern[1].type == PLUS) { + return matchplus(pattern[0], &pattern[2], text, matchlength); + } else if((pattern[0].type == END) && pattern[1].type == UNUSED) { + return (text[0] == '\0'); + } +/* Branching is not working properly + else if (pattern[1].type == BRANCH) + { + return (matchpattern(pattern, text) || matchpattern(&pattern[2], text)); + } */ - (*matchlength)++; - } while((text[0] != '\0') && matchone(*pattern++, *text++)); + (*matchlength)++; + } while((text[0] != '\0') && matchone(*pattern++, *text++)); - *matchlength = pre; + *matchlength = pre; - return 0; + return 0; } #endif diff --git a/src/network_traffic_filter.c b/src/network_traffic_filter.c index dbd067e..137b478 100644 --- a/src/network_traffic_filter.c +++ b/src/network_traffic_filter.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -22,27 +22,27 @@ // cache that hit less than 10 while 10000 package processed will be delete; #define CLEAR_CACHE_EVERY_X_COUNT 10000 -#define CLAER_CACHE_ACTIVE_COUNT 10 +#define CLAER_CACHE_ACTIVE_COUNT 10 /* for [-Wmissing-declarations] */ const char* get_filter_packet_proto_name (filter_packet_proto proto); const char* get_filter_packet_proto_name (filter_packet_proto proto) { - switch(proto) { - case FPP_ARP: - return "ARP"; - case FPP_TCP: - return "TCP"; - case FPP_UDP: - return "UDP"; - case FPP_ICMP: - return "ICMP"; - case FPP_IGMP: - return "IGMP"; - default: - return "UNKNOWN_PROTO"; - } + switch(proto) { + case FPP_ARP: + return "ARP"; + case FPP_TCP: + return "TCP"; + case FPP_UDP: + return "UDP"; + case FPP_ICMP: + return "ICMP"; + case FPP_IGMP: + return "IGMP"; + default: + return "UNKNOWN_PROTO"; + } } @@ -51,30 +51,30 @@ const char* get_filter_packet_info_log_string (packet_address_proto_info_t* info const char* get_filter_packet_info_log_string (packet_address_proto_info_t* info) { - static char buf[1024] = {0}; - - switch(info->proto) { - case FPP_ARP: - case FPP_ICMP: - case FPP_IGMP: - return get_filter_packet_proto_name(info->proto); - case FPP_TCP: - case FPP_UDP: { - struct in_addr src, dst; - - src.s_addr = info->src_ip; - dst.s_addr = info->dst_ip; - const char* proto = get_filter_packet_proto_name(info->proto); - char src_ip[64] = {0}; - char dst_ip[64] = {0}; - strcpy(src_ip, inet_ntoa(src)); - strcpy(dst_ip, inet_ntoa(dst)); - sprintf(buf, "%s\t%s:%d->%s:%d", proto, src_ip, info->src_port, dst_ip, info->dst_port); - return buf; + static char buf[1024] = {0}; + + switch(info->proto) { + case FPP_ARP: + case FPP_ICMP: + case FPP_IGMP: + return get_filter_packet_proto_name(info->proto); + case FPP_TCP: + case FPP_UDP: { + struct in_addr src, dst; + + src.s_addr = info->src_ip; + dst.s_addr = info->dst_ip; + const char* proto = get_filter_packet_proto_name(info->proto); + char src_ip[64] = {0}; + char dst_ip[64] = {0}; + strcpy(src_ip, inet_ntoa(src)); + strcpy(dst_ip, inet_ntoa(dst)); + sprintf(buf, "%s\t%s:%d->%s:%d", proto, src_ip, info->src_port, dst_ip, info->dst_port); + return buf; + } + default: + return "UNKNOWN_PROTO"; } - default: - return "UNKNOWN_PROTO"; - } } /* for [-Wmissing-declarations] */ @@ -82,82 +82,82 @@ void collect_packet_info (packet_address_proto_info_t* out_info, unsigned char * void collect_packet_info (packet_address_proto_info_t* out_info, unsigned char *buffer, int size) { - ether_hdr_t *hdr_ether = (ether_hdr_t*)buffer; - uint16_t ether_type = ntohs(hdr_ether->type); - struct n2n_iphdr *hdr_ip = NULL; - struct n2n_tcphdr *hdr_tcp = NULL; - struct n2n_udphdr *udp_hdr = NULL; - - memset(out_info, 0, sizeof(packet_address_proto_info_t)); - - switch(ether_type) { - case 0x0800: { - buffer += sizeof(ether_hdr_t); - size -= sizeof(ether_hdr_t); - if(size <= 0) { - return; - } - hdr_ip = (struct n2n_iphdr*)buffer; - - switch(hdr_ip->version) { - case 4: { - out_info->src_ip = hdr_ip->saddr; - out_info->dst_ip = hdr_ip->daddr; - switch(hdr_ip->protocol) { - case 0x01: - out_info->proto = FPP_ICMP; - break; - case 0x02: - out_info->proto = FPP_IGMP; - break; - case 0x06: { - out_info->proto = FPP_TCP; - buffer += hdr_ip->ihl * 4; - size -= hdr_ip->ihl * 4; - if(size <= 0) { - return; - } - hdr_tcp = (struct n2n_tcphdr*)buffer; - out_info->src_port = ntohs(hdr_tcp->source); - out_info->dst_port = ntohs(hdr_tcp->dest); - break; - } - case 0x11: { - out_info->proto = FPP_UDP; - buffer += hdr_ip->ihl * 4; - size -= hdr_ip->ihl * 4; - if(size <= 0) { + ether_hdr_t *hdr_ether = (ether_hdr_t*)buffer; + uint16_t ether_type = ntohs(hdr_ether->type); + struct n2n_iphdr *hdr_ip = NULL; + struct n2n_tcphdr *hdr_tcp = NULL; + struct n2n_udphdr *udp_hdr = NULL; + + memset(out_info, 0, sizeof(packet_address_proto_info_t)); + + switch(ether_type) { + case 0x0800: { + buffer += sizeof(ether_hdr_t); + size -= sizeof(ether_hdr_t); + if(size <= 0) { return; - } - udp_hdr = (struct n2n_udphdr*)buffer; - out_info->src_port = ntohs(udp_hdr->source); - out_info->dst_port = ntohs(udp_hdr->dest); - break; } - default: - out_info->proto = FPP_UNKNOWN; - }; + hdr_ip = (struct n2n_iphdr*)buffer; + + switch(hdr_ip->version) { + case 4: { + out_info->src_ip = hdr_ip->saddr; + out_info->dst_ip = hdr_ip->daddr; + switch(hdr_ip->protocol) { + case 0x01: + out_info->proto = FPP_ICMP; + break; + case 0x02: + out_info->proto = FPP_IGMP; + break; + case 0x06: { + out_info->proto = FPP_TCP; + buffer += hdr_ip->ihl * 4; + size -= hdr_ip->ihl * 4; + if(size <= 0) { + return; + } + hdr_tcp = (struct n2n_tcphdr*)buffer; + out_info->src_port = ntohs(hdr_tcp->source); + out_info->dst_port = ntohs(hdr_tcp->dest); + break; + } + case 0x11: { + out_info->proto = FPP_UDP; + buffer += hdr_ip->ihl * 4; + size -= hdr_ip->ihl * 4; + if(size <= 0) { + return; + } + udp_hdr = (struct n2n_udphdr*)buffer; + out_info->src_port = ntohs(udp_hdr->source); + out_info->dst_port = ntohs(udp_hdr->dest); + break; + } + default: + out_info->proto = FPP_UNKNOWN; + }; + break; + } + case 6: { + // TODO: IPV6 Not Support + out_info->proto = FPP_UNKNOWN; + break; + } + default: + out_info->proto = FPP_UNKNOWN; + } break; - } - case 6: { - // TODO: IPV6 Not Support - out_info->proto = FPP_UNKNOWN; - break; } - default: - out_info->proto = FPP_UNKNOWN; - } - break; - } - case 0x0806: - out_info->proto = FPP_ARP; - break; - case 0x86DD: - out_info->proto = FPP_UNKNOWN; - break; - default: - printf("EtherType 0x%04X", ether_type); - }; + case 0x0806: + out_info->proto = FPP_ARP; + break; + case 0x86DD: + out_info->proto = FPP_UNKNOWN; + break; + default: + printf("EtherType 0x%04X", ether_type); + }; } /* for [-Wmissing-declarations] */ @@ -165,39 +165,39 @@ const char* get_filter_rule_info_log_string (filter_rule_t* rule); const char* get_filter_rule_info_log_string (filter_rule_t* rule) { - static char buf[1024] = {0}; - char* print_start = buf; - char src_net[64] = {0}; - char dst_net[64] = {0}; - struct in_addr src, dst; - - src.s_addr = rule->key.src_net_cidr; - dst.s_addr = rule->key.dst_net_cidr; - strcpy(src_net, inet_ntoa(src)); - strcpy(dst_net, inet_ntoa(dst)); - print_start += sprintf(print_start, "%s/%d:[%d,%d],%s/%d:[%d,%d]", - src_net, rule->key.src_net_bit_len, - rule->key.src_port_range.start_port, rule->key.src_port_range.end_port, - dst_net, rule->key.dst_net_bit_len, - rule->key.dst_port_range.start_port, rule->key.dst_port_range.end_port + static char buf[1024] = {0}; + char* print_start = buf; + char src_net[64] = {0}; + char dst_net[64] = {0}; + struct in_addr src, dst; + + src.s_addr = rule->key.src_net_cidr; + dst.s_addr = rule->key.dst_net_cidr; + strcpy(src_net, inet_ntoa(src)); + strcpy(dst_net, inet_ntoa(dst)); + print_start += sprintf(print_start, "%s/%d:[%d,%d],%s/%d:[%d,%d]", + src_net, rule->key.src_net_bit_len, + rule->key.src_port_range.start_port, rule->key.src_port_range.end_port, + dst_net, rule->key.dst_net_bit_len, + rule->key.dst_port_range.start_port, rule->key.dst_port_range.end_port #if 0 - , - rule->bool_accept_tcp ? '+' : '-', rule->bool_accept_udp ? '+' : '-', rule->bool_accept_icmp ? '+' : '-' + , + rule->bool_accept_tcp ? '+' : '-', rule->bool_accept_udp ? '+' : '-', rule->bool_accept_icmp ? '+' : '-' #endif - ); - if(rule->key.bool_tcp_configured) { - print_start += sprintf(print_start, ",TCP%c", rule->bool_accept_tcp ? '+' : '-'); - } + ); + if(rule->key.bool_tcp_configured) { + print_start += sprintf(print_start, ",TCP%c", rule->bool_accept_tcp ? '+' : '-'); + } - if(rule->key.bool_udp_configured) { - print_start += sprintf(print_start, ",UDP%c", rule->bool_accept_udp ? '+' : '-'); - } + if(rule->key.bool_udp_configured) { + print_start += sprintf(print_start, ",UDP%c", rule->bool_accept_udp ? '+' : '-'); + } - if(rule->key.bool_icmp_configured) { - print_start += sprintf(print_start, ",ICMP%c", rule->bool_accept_icmp ? '+' : '-'); - } + if(rule->key.bool_icmp_configured) { + print_start += sprintf(print_start, ",ICMP%c", rule->bool_accept_icmp ? '+' : '-'); + } - return buf; + return buf; } @@ -207,17 +207,17 @@ uint8_t march_cidr_and_address (in_addr_t network, uint8_t net_bitlen, in_addr_t uint8_t march_cidr_and_address (in_addr_t network, uint8_t net_bitlen, in_addr_t ip_addr) { - in_addr_t mask = 0, ip_addr_network = 0; - - network = ntohl(network); - ip_addr = ntohl(ip_addr); - uint32_t mask1 = net_bitlen != 0 ? ((~mask) << (32u-net_bitlen)) : 0; - ip_addr_network = ip_addr & mask1; - if(network == ip_addr_network) { - return net_bitlen + 1; // march 0.0.0.0/0 still march success, that case return 1 - } else { - return 0; - } + in_addr_t mask = 0, ip_addr_network = 0; + + network = ntohl(network); + ip_addr = ntohl(ip_addr); + uint32_t mask1 = net_bitlen != 0 ? ((~mask) << (32u-net_bitlen)) : 0; + ip_addr_network = ip_addr & mask1; + if(network == ip_addr_network) { + return net_bitlen + 1; // march 0.0.0.0/0 still march success, that case return 1 + } else { + return 0; + } } /* for [-Wmissing-declarations] */ @@ -226,61 +226,60 @@ uint8_t march_rule_and_cache_key (filter_rule_key_t *rule_key, packet_address_pr // if ports march, compare cidr. if cidr ok, return sum of src&dst cidr net_bitlen. means always select larger net_bitlen record when multi record is marched. uint8_t march_rule_and_cache_key (filter_rule_key_t *rule_key, packet_address_proto_info_t *pkt_addr_info) { - // march failed if proto is not configured at the rule. - switch(pkt_addr_info->proto) { - case FPP_ICMP: - if(!rule_key->bool_icmp_configured) { - return 0; - } - break; - case FPP_UDP: - if(!rule_key->bool_udp_configured) { - return 0; - } - break; - case FPP_TCP: - if(!rule_key->bool_tcp_configured) { - return 0; - } - break; - default: - return 0; - } - - // ignore ports for ICMP proto. - if(pkt_addr_info->proto == FPP_ICMP || (rule_key->src_port_range.start_port <= pkt_addr_info->src_port - && pkt_addr_info->src_port <= rule_key->src_port_range.end_port - && rule_key->dst_port_range.start_port <= pkt_addr_info->dst_port - && pkt_addr_info->dst_port <= rule_key->dst_port_range.end_port)) { - uint8_t march_src_score = march_cidr_and_address(rule_key->src_net_cidr, rule_key->src_net_bit_len, pkt_addr_info->src_ip); - uint8_t march_dst_score = march_cidr_and_address(rule_key->dst_net_cidr, rule_key->dst_net_bit_len, pkt_addr_info->dst_ip); - if((march_src_score > 0) && (march_dst_score > 0)) { - return march_src_score + march_dst_score; + // march failed if proto is not configured at the rule. + switch(pkt_addr_info->proto) { + case FPP_ICMP: + if(!rule_key->bool_icmp_configured) { + return 0; + } + break; + case FPP_UDP: + if(!rule_key->bool_udp_configured) { + return 0; + } + break; + case FPP_TCP: + if(!rule_key->bool_tcp_configured) { + return 0; + } + break; + default: + return 0; + } + + // ignore ports for ICMP proto. + if(pkt_addr_info->proto == FPP_ICMP || (rule_key->src_port_range.start_port <= pkt_addr_info->src_port + && pkt_addr_info->src_port <= rule_key->src_port_range.end_port + && rule_key->dst_port_range.start_port <= pkt_addr_info->dst_port + && pkt_addr_info->dst_port <= rule_key->dst_port_range.end_port)) { + uint8_t march_src_score = march_cidr_and_address(rule_key->src_net_cidr, rule_key->src_net_bit_len, pkt_addr_info->src_ip); + uint8_t march_dst_score = march_cidr_and_address(rule_key->dst_net_cidr, rule_key->dst_net_bit_len, pkt_addr_info->dst_ip); + if((march_src_score > 0) && (march_dst_score > 0)) { + return march_src_score + march_dst_score; + } } - } - return(0); + return(0); } /* for [-Wmissing-declarations] */ filter_rule_t* get_filter_rule (filter_rule_t **rules, packet_address_proto_info_t *pkt_addr_info); - filter_rule_t* get_filter_rule (filter_rule_t **rules, packet_address_proto_info_t *pkt_addr_info) { - filter_rule_t *item = 0, *tmp = 0, *marched_rule = 0; - int march_score = 0; + filter_rule_t *item = 0, *tmp = 0, *marched_rule = 0; + int march_score = 0; - HASH_ITER(hh, *rules, item, tmp) { - /* ... it is safe to delete and free s here */ - uint8_t cur_march_score = march_rule_and_cache_key(&(item->key), pkt_addr_info); - if(cur_march_score > march_score) { - marched_rule = item; - march_score = cur_march_score; + HASH_ITER(hh, *rules, item, tmp) { + /* ... it is safe to delete and free s here */ + uint8_t cur_march_score = march_rule_and_cache_key(&(item->key), pkt_addr_info); + if(cur_march_score > march_score) { + marched_rule = item; + march_score = cur_march_score; + } } - } - return marched_rule; + return marched_rule; } @@ -289,20 +288,20 @@ void update_and_clear_cache_if_need (network_traffic_filter_t *filter); void update_and_clear_cache_if_need (network_traffic_filter_t *filter) { - if(++(filter->work_count_scene_last_clear) > CLEAR_CACHE_EVERY_X_COUNT) { - filter_rule_pair_cache_t *item = NULL, *tmp = NULL; - HASH_ITER(hh, filter->connections_rule_cache, item, tmp) { - /* ... it is safe to delete and free s here */ - if(item->active_count < CLAER_CACHE_ACTIVE_COUNT) { - traceEvent(TRACE_DEBUG, "### DELETE filter cache %s", get_filter_packet_info_log_string(&item->key)); - HASH_DEL(filter->connections_rule_cache, item); - free(item); - } else { - item->active_count = 0; - } + if(++(filter->work_count_scene_last_clear) > CLEAR_CACHE_EVERY_X_COUNT) { + filter_rule_pair_cache_t *item = NULL, *tmp = NULL; + HASH_ITER(hh, filter->connections_rule_cache, item, tmp) { + /* ... it is safe to delete and free s here */ + if(item->active_count < CLAER_CACHE_ACTIVE_COUNT) { + traceEvent(TRACE_DEBUG, "### DELETE filter cache %s", get_filter_packet_info_log_string(&item->key)); + HASH_DEL(filter->connections_rule_cache, item); + free(item); + } else { + item->active_count = 0; + } + } + filter->work_count_scene_last_clear = 0; } - filter->work_count_scene_last_clear = 0; - } } /* for [-Wmissing-declarations] */ @@ -310,38 +309,38 @@ filter_rule_pair_cache_t* get_or_create_filter_rule_cache (network_traffic_filte filter_rule_pair_cache_t* get_or_create_filter_rule_cache (network_traffic_filter_t *filter, packet_address_proto_info_t *pkt_addr_info) { - filter_rule_pair_cache_t* rule_cache_find_result = 0; - HASH_FIND(hh, filter->connections_rule_cache, pkt_addr_info, sizeof(packet_address_proto_info_t), rule_cache_find_result); - if(!rule_cache_find_result) { - filter_rule_t* rule = get_filter_rule(&filter->rules, pkt_addr_info); - if(!rule) { - return NULL; - } + filter_rule_pair_cache_t* rule_cache_find_result = 0; + HASH_FIND(hh, filter->connections_rule_cache, pkt_addr_info, sizeof(packet_address_proto_info_t), rule_cache_find_result); + if(!rule_cache_find_result) { + filter_rule_t* rule = get_filter_rule(&filter->rules, pkt_addr_info); + if(!rule) { + return NULL; + } - rule_cache_find_result = malloc(sizeof(filter_rule_pair_cache_t)); - memset(rule_cache_find_result, 0, sizeof(filter_rule_pair_cache_t)); - rule_cache_find_result->key = *pkt_addr_info; - switch(rule_cache_find_result->key.proto) { - case FPP_ICMP: - rule_cache_find_result->bool_allow_traffic = rule->bool_accept_icmp; - break; - case FPP_UDP: - rule_cache_find_result->bool_allow_traffic = rule->bool_accept_udp; - break; - case FPP_TCP: - rule_cache_find_result->bool_allow_traffic = rule->bool_accept_tcp; - break; - default: - traceEvent(TRACE_WARNING, "### Generate filter rule cache failed!"); - return NULL; + rule_cache_find_result = malloc(sizeof(filter_rule_pair_cache_t)); + memset(rule_cache_find_result, 0, sizeof(filter_rule_pair_cache_t)); + rule_cache_find_result->key = *pkt_addr_info; + switch(rule_cache_find_result->key.proto) { + case FPP_ICMP: + rule_cache_find_result->bool_allow_traffic = rule->bool_accept_icmp; + break; + case FPP_UDP: + rule_cache_find_result->bool_allow_traffic = rule->bool_accept_udp; + break; + case FPP_TCP: + rule_cache_find_result->bool_allow_traffic = rule->bool_accept_tcp; + break; + default: + traceEvent(TRACE_WARNING, "### Generate filter rule cache failed!"); + return NULL; + } + traceEvent(TRACE_DEBUG, "### ADD filter cache %s", get_filter_packet_info_log_string(&rule_cache_find_result->key)); + HASH_ADD(hh, filter->connections_rule_cache, key, sizeof(packet_address_proto_info_t), rule_cache_find_result); } - traceEvent(TRACE_DEBUG, "### ADD filter cache %s", get_filter_packet_info_log_string(&rule_cache_find_result->key)); - HASH_ADD(hh, filter->connections_rule_cache, key, sizeof(packet_address_proto_info_t), rule_cache_find_result); - } - ++(rule_cache_find_result->active_count); - update_and_clear_cache_if_need(filter); + ++(rule_cache_find_result->active_count); + update_and_clear_cache_if_need(filter); - return rule_cache_find_result; + return rule_cache_find_result; } /* for [-Wmissing-declarations] */ @@ -349,17 +348,17 @@ n2n_verdict filter_packet_from_peer (network_traffic_filter_t *filter, n2n_edge_ n2n_verdict filter_packet_from_peer (network_traffic_filter_t *filter, n2n_edge_t *eee, const n2n_sock_t *peer, uint8_t *payload, uint16_t payload_size) { - filter_rule_pair_cache_t *cur_pkt_rule = 0; - packet_address_proto_info_t pkt_info; + filter_rule_pair_cache_t *cur_pkt_rule = 0; + packet_address_proto_info_t pkt_info; - collect_packet_info(&pkt_info, payload, payload_size); - cur_pkt_rule = get_or_create_filter_rule_cache(filter, &pkt_info); - if(cur_pkt_rule && !cur_pkt_rule->bool_allow_traffic) { - traceEvent(TRACE_DEBUG, "### DROP %s", get_filter_packet_info_log_string(&pkt_info)); - return N2N_DROP; - } + collect_packet_info(&pkt_info, payload, payload_size); + cur_pkt_rule = get_or_create_filter_rule_cache(filter, &pkt_info); + if(cur_pkt_rule && !cur_pkt_rule->bool_allow_traffic) { + traceEvent(TRACE_DEBUG, "### DROP %s", get_filter_packet_info_log_string(&pkt_info)); + return N2N_DROP; + } - return N2N_ACCEPT; + return N2N_ACCEPT; } /* for [-Wmissing-declarations] */ @@ -367,17 +366,17 @@ n2n_verdict filter_packet_from_tap (network_traffic_filter_t *filter, n2n_edge_t n2n_verdict filter_packet_from_tap (network_traffic_filter_t *filter, n2n_edge_t *eee, uint8_t *payload, uint16_t payload_size) { - filter_rule_pair_cache_t *cur_pkt_rule = 0; - packet_address_proto_info_t pkt_info; + filter_rule_pair_cache_t *cur_pkt_rule = 0; + packet_address_proto_info_t pkt_info; - collect_packet_info(&pkt_info, payload, payload_size); - cur_pkt_rule = get_or_create_filter_rule_cache(filter, &pkt_info); - if(cur_pkt_rule && !cur_pkt_rule->bool_allow_traffic) { - traceEvent(TRACE_DEBUG, "### DROP %s", get_filter_packet_info_log_string(&pkt_info)); - return N2N_DROP; - } + collect_packet_info(&pkt_info, payload, payload_size); + cur_pkt_rule = get_or_create_filter_rule_cache(filter, &pkt_info); + if(cur_pkt_rule && !cur_pkt_rule->bool_allow_traffic) { + traceEvent(TRACE_DEBUG, "### DROP %s", get_filter_packet_info_log_string(&pkt_info)); + return N2N_DROP; + } - return N2N_ACCEPT; + return N2N_ACCEPT; } /* for [-Wmissing-declarations] */ @@ -385,13 +384,13 @@ network_traffic_filter_t *create_network_traffic_filter (); network_traffic_filter_t *create_network_traffic_filter () { - network_traffic_filter_t *filter = malloc(sizeof(network_traffic_filter_t)); + network_traffic_filter_t *filter = malloc(sizeof(network_traffic_filter_t)); - memset(filter, 0, sizeof(network_traffic_filter_t)); - filter->filter_packet_from_peer = filter_packet_from_peer; - filter->filter_packet_from_tap = filter_packet_from_tap; + memset(filter, 0, sizeof(network_traffic_filter_t)); + filter->filter_packet_from_peer = filter_packet_from_peer; + filter->filter_packet_from_tap = filter_packet_from_tap; - return filter; + return filter; } /* for [-Wmissing-declarations] */ @@ -399,20 +398,20 @@ void destroy_network_traffic_filter (network_traffic_filter_t *filter); void destroy_network_traffic_filter (network_traffic_filter_t *filter) { - filter_rule_t *el = 0, *tmp = 0; - filter_rule_pair_cache_t* el1 = 0, * tmp1 = 0; + filter_rule_t *el = 0, *tmp = 0; + filter_rule_pair_cache_t* el1 = 0, * tmp1 = 0; - HASH_ITER(hh, filter->rules, el, tmp) { - HASH_DEL(filter->rules, el); - free(el); - } + HASH_ITER(hh, filter->rules, el, tmp) { + HASH_DEL(filter->rules, el); + free(el); + } - HASH_ITER(hh, filter->connections_rule_cache, el1, tmp1) { - HASH_DEL(filter->connections_rule_cache, el1); - free(el); - } + HASH_ITER(hh, filter->connections_rule_cache, el1, tmp1) { + HASH_DEL(filter->connections_rule_cache, el1); + free(el); + } - free(filter); + free(filter); } /* for [-Wmissing-declarations] */ @@ -420,14 +419,14 @@ void network_traffic_filter_add_rule (network_traffic_filter_t* filter, filter_r void network_traffic_filter_add_rule (network_traffic_filter_t* filter, filter_rule_t* rules) { - filter_rule_t *item = NULL, *tmp = NULL; + filter_rule_t *item = NULL, *tmp = NULL; - HASH_ITER(hh, rules, item, tmp) { - filter_rule_t *new_rule = malloc(sizeof(filter_rule_t)); - memcpy(new_rule, item, sizeof(filter_rule_t)); - HASH_ADD(hh, filter->rules, key, sizeof(filter_rule_key_t), new_rule); - traceEvent(TRACE_NORMAL, "### ADD network traffic filter %s", get_filter_rule_info_log_string(new_rule)); - } + HASH_ITER(hh, rules, item, tmp) { + filter_rule_t *new_rule = malloc(sizeof(filter_rule_t)); + memcpy(new_rule, item, sizeof(filter_rule_t)); + HASH_ADD(hh, filter->rules, key, sizeof(filter_rule_key_t), new_rule); + traceEvent(TRACE_NORMAL, "### ADD network traffic filter %s", get_filter_rule_info_log_string(new_rule)); + } } /* for [-Wmissing-declarations] */ @@ -435,15 +434,15 @@ in_addr_t get_int32_addr_from_ip_string (const char* begin, const char* next_pos in_addr_t get_int32_addr_from_ip_string (const char* begin, const char* next_pos_of_last_char) { - char buf[16] = {0}; + char buf[16] = {0}; - if((next_pos_of_last_char - begin) > 15) { - traceEvent(TRACE_WARNING, "Internal Error"); - return -1; - } - memcpy(buf, begin, (next_pos_of_last_char - begin)); + if((next_pos_of_last_char - begin) > 15) { + traceEvent(TRACE_WARNING, "Internal Error"); + return -1; + } + memcpy(buf, begin, (next_pos_of_last_char - begin)); - return inet_addr(buf); + return inet_addr(buf); } /* for [-Wmissing-declarations] */ @@ -451,15 +450,15 @@ int get_int32_from_number_string (const char* begin, const char* next_pos_of_las int get_int32_from_number_string (const char* begin, const char* next_pos_of_last_char) { - char buf[6] = {0}; + char buf[6] = {0}; - if((next_pos_of_last_char - begin) > 5 ) { // max is 65535, 5 char - traceEvent(TRACE_WARNING, "Internal Error"); - return 0; - } - memcpy(buf, begin, (next_pos_of_last_char - begin)); + if((next_pos_of_last_char - begin) > 5 ) { // max is 65535, 5 char + traceEvent(TRACE_WARNING, "Internal Error"); + return 0; + } + memcpy(buf, begin, (next_pos_of_last_char - begin)); - return atoi(buf); + return atoi(buf); } /* for [-Wmissing-declarations] */ @@ -467,41 +466,41 @@ void process_traffic_filter_proto (const char* begin, const char* next_pos_of_la void process_traffic_filter_proto (const char* begin, const char* next_pos_of_last_char, filter_rule_t *rule_struct) { - char buf[6] = {0}; - - if((next_pos_of_last_char - begin) > 5 ) { // max length str is "ICMP+", 5 char - traceEvent(TRACE_WARNING, "Internal Error"); - } - memcpy(buf, begin, (next_pos_of_last_char - begin)); - - if(strstr(buf, "TCP")) { - rule_struct->key.bool_tcp_configured = 1; - rule_struct->bool_accept_tcp = buf[3] == '+'; - } else if(strstr(buf, "UDP")) { - rule_struct->key.bool_udp_configured = 1; - rule_struct->bool_accept_udp = buf[3] == '+'; - } else if(strstr(buf, "ICMP")) { - rule_struct->key.bool_icmp_configured = 1; - rule_struct->bool_accept_icmp = buf[4] == '+'; - } else { - traceEvent(TRACE_WARNING, "Invalid Proto : %s", buf); - } + char buf[6] = {0}; + + if((next_pos_of_last_char - begin) > 5 ) { // max length str is "ICMP+", 5 char + traceEvent(TRACE_WARNING, "Internal Error"); + } + memcpy(buf, begin, (next_pos_of_last_char - begin)); + + if(strstr(buf, "TCP")) { + rule_struct->key.bool_tcp_configured = 1; + rule_struct->bool_accept_tcp = buf[3] == '+'; + } else if(strstr(buf, "UDP")) { + rule_struct->key.bool_udp_configured = 1; + rule_struct->bool_accept_udp = buf[3] == '+'; + } else if(strstr(buf, "ICMP")) { + rule_struct->key.bool_icmp_configured = 1; + rule_struct->bool_accept_icmp = buf[4] == '+'; + } else { + traceEvent(TRACE_WARNING, "Invalid Proto : %s", buf); + } } typedef enum { - FPS_SRC_NET = 1, - FPS_SRC_NET_BIT_LEN, - FPS_SRC_PORT_SINGLE, - FPS_SRC_PORT_RANGE, - FPS_SRC_PORT_START, - FPS_SRC_PORT_END, - FPS_DST_NET, - FPS_DST_NET_BIT_LEN, - FPS_DST_PORT_SINGLE, - FPS_DST_PORT_RANGE, - FPS_DST_PORT_START, - FPS_DST_PORT_END, - FPS_PROTO + FPS_SRC_NET = 1, + FPS_SRC_NET_BIT_LEN, + FPS_SRC_PORT_SINGLE, + FPS_SRC_PORT_RANGE, + FPS_SRC_PORT_START, + FPS_SRC_PORT_END, + FPS_DST_NET, + FPS_DST_NET_BIT_LEN, + FPS_DST_PORT_SINGLE, + FPS_DST_PORT_RANGE, + FPS_DST_PORT_START, + FPS_DST_PORT_END, + FPS_PROTO } filter_process_stage; /* for [-Wmissing-declarations] */ @@ -509,276 +508,276 @@ uint8_t process_traffic_filter_rule_str (const char *rule_str, filter_rule_t *ru uint8_t process_traffic_filter_rule_str (const char *rule_str, filter_rule_t *rule_struct) { - const char *cur_pos = rule_str, *stage_begin_pos = rule_str; - filter_process_stage stage = FPS_SRC_NET; - - while(1) { - switch(stage) { - case FPS_SRC_NET: { - if((*cur_pos >= '0' && *cur_pos <= '9') || *cur_pos == '.') { - ; // Normal FPS_SRC_NET, next char - } else if(*cur_pos == '/') { - // FPS_SRC_NET finish, next is FPS_SRC_NET_BIT_LEN - rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); - stage_begin_pos = cur_pos + 1; - stage = FPS_SRC_NET_BIT_LEN; - } else if(*cur_pos == ':') { - // FPS_SRC_NET finish, ignore FPS_SRC_NET_BIT_LEN(default 32), next is one of FPS_SRC_PORT_RANGE/FPS_SRC_PORT_SINGLE - rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); - rule_struct->key.src_net_bit_len = 32; - stage_begin_pos = cur_pos + 1; - if(*(cur_pos + 1) == '[') { - stage = FPS_SRC_PORT_RANGE; - } else { - stage = FPS_SRC_PORT_SINGLE; - } - } else if(*cur_pos == ',') { - // FPS_SRC_NET finish, ignore FPS_SRC_NET_BIT_LEN(default 32), ignore FPS_SRC_PORT(default all), - // next is FPS_DST_NET - rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); - rule_struct->key.src_net_bit_len = 32; - rule_struct->key.src_port_range.start_port = 0; - rule_struct->key.src_port_range.end_port = 65535; - stage_begin_pos = cur_pos + 1; - stage = FPS_DST_NET; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } - - case FPS_SRC_NET_BIT_LEN: { - if((*cur_pos >= '0') && (*cur_pos <= '9')) { - ; // Normal FPS_SRC_NET_BIT_LEN, next char - } else if(*cur_pos == ':') { - // FPS_SRC_NET_BIT_LEN finish, next is one of FPS_SRC_PORT_RANGE/FPS_SRC_PORT_SINGLE - rule_struct->key.src_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos); - stage_begin_pos = cur_pos + 1; - if(*(cur_pos + 1) == '[') { - stage = FPS_SRC_PORT_RANGE; - } else { - stage = FPS_SRC_PORT_SINGLE; - } - } else if(*cur_pos == ',') { - // FPS_SRC_NET_BIT_LEN finish, ignore FPS_SRC_PORT(default all), next is FPS_DST_NET - rule_struct->key.src_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);; - rule_struct->key.src_port_range.start_port = 0; - rule_struct->key.src_port_range.end_port = 65535; - stage_begin_pos = cur_pos + 1; - stage = FPS_DST_NET; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } - - case FPS_SRC_PORT_SINGLE: { - if((*cur_pos >= '0') && (*cur_pos <= '9')) { - ; // Normal FPS_SRC_PORT_SINGLE, next char - } else if(*cur_pos == ',') { - // FPS_SRC_PORT_SINGLE finish, next is FPS_DST_NET - rule_struct->key.src_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); - rule_struct->key.src_port_range.end_port = rule_struct->key.src_port_range.start_port; - stage_begin_pos = cur_pos + 1; - stage = FPS_DST_NET; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } - - case FPS_SRC_PORT_RANGE: { - if(*cur_pos == '[') { - stage_begin_pos = cur_pos + 1; - stage = FPS_SRC_PORT_START; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } - - case FPS_SRC_PORT_START: { - if((*cur_pos >= '0') && (*cur_pos <= '9')) { - ; // Normal FPS_SRC_PORT_START, next char - } else if(*cur_pos == ',') { - // FPS_SRC_PORT_START finish, next is FPS_SRC_PORT_END - rule_struct->key.src_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); - stage_begin_pos = cur_pos + 1; - stage = FPS_SRC_PORT_END; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } - - case FPS_SRC_PORT_END: { - if((*cur_pos >= '0') && (*cur_pos <= '9')) { - ; // Normal FPS_SRC_PORT_END, next char - } else if((*cur_pos == ']') && (*(cur_pos + 1) == ',')) { - // FPS_SRC_PORT_END finish, next is FPS_DST_NET - rule_struct->key.src_port_range.end_port = get_int32_from_number_string(stage_begin_pos, cur_pos); - stage_begin_pos = cur_pos + 2; - stage = FPS_DST_NET; - ++cur_pos; //skip next char ',' - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } - - case FPS_DST_NET: { - if((*cur_pos >= '0' && *cur_pos <= '9') || *cur_pos == '.') { - ; // Normal FPS_DST_NET, next char - } else if(*cur_pos == '/') { - // FPS_DST_NET finish, next is FPS_DST_NET_BIT_LEN - rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); - stage_begin_pos = cur_pos + 1; - stage = FPS_DST_NET_BIT_LEN; - } else if(*cur_pos == ':') { - // FPS_DST_NET finish, ignore FPS_DST_NET_BIT_LEN(default 32), next is one of FPS_DST_PORT_RANGE/FPS_DST_PORT_SINGLE - rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); - rule_struct->key.dst_net_bit_len = 32; - stage_begin_pos = cur_pos + 1; - if(*(cur_pos + 1) == '[') { - stage = FPS_DST_PORT_RANGE; - } else { - stage = FPS_DST_PORT_SINGLE; - } - } else if((*cur_pos == ',') || (*cur_pos == 0)) { - // FPS_DST_NET finish, ignore FPS_DST_NET_BIT_LEN(default 32), ignore FPS_DST_PORT(default all), - // next is FPS_PROTO - rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); - rule_struct->key.dst_net_bit_len = 32; - rule_struct->key.dst_port_range.start_port = 0; - rule_struct->key.dst_port_range.end_port = 65535; - stage_begin_pos = cur_pos + 1; - stage = FPS_PROTO; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } - - case FPS_DST_NET_BIT_LEN: { - if((*cur_pos >= '0') && (*cur_pos <= '9')) { - ; // Normal FPS_DST_NET_BIT_LEN, next char - } else if(*cur_pos == ':') { - // FPS_DST_NET_BIT_LEN finish, next is one of FPS_DST_PORT_RANGE/FPS_DST_PORT_SINGLE - rule_struct->key.dst_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos); - stage_begin_pos = cur_pos + 1; - if(*(cur_pos + 1) == '[') { - stage = FPS_DST_PORT_RANGE; - } else { - stage = FPS_DST_PORT_SINGLE; - } - } else if((*cur_pos == ',') || (*cur_pos == 0)) { - // FPS_DST_NET_BIT_LEN finish, ignore FPS_DST_PORT(default all), next is FPS_PROTO - rule_struct->key.dst_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);; - rule_struct->key.dst_port_range.start_port = 0; - rule_struct->key.dst_port_range.end_port = 65535; - stage_begin_pos = cur_pos + 1; - stage = FPS_PROTO; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; + const char *cur_pos = rule_str, *stage_begin_pos = rule_str; + filter_process_stage stage = FPS_SRC_NET; + + while(1) { + switch(stage) { + case FPS_SRC_NET: { + if((*cur_pos >= '0' && *cur_pos <= '9') || *cur_pos == '.') { + ; // Normal FPS_SRC_NET, next char + } else if(*cur_pos == '/') { + // FPS_SRC_NET finish, next is FPS_SRC_NET_BIT_LEN + rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + stage = FPS_SRC_NET_BIT_LEN; + } else if(*cur_pos == ':') { + // FPS_SRC_NET finish, ignore FPS_SRC_NET_BIT_LEN(default 32), next is one of FPS_SRC_PORT_RANGE/FPS_SRC_PORT_SINGLE + rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + rule_struct->key.src_net_bit_len = 32; + stage_begin_pos = cur_pos + 1; + if(*(cur_pos + 1) == '[') { + stage = FPS_SRC_PORT_RANGE; + } else { + stage = FPS_SRC_PORT_SINGLE; + } + } else if(*cur_pos == ',') { + // FPS_SRC_NET finish, ignore FPS_SRC_NET_BIT_LEN(default 32), ignore FPS_SRC_PORT(default all), + // next is FPS_DST_NET + rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + rule_struct->key.src_net_bit_len = 32; + rule_struct->key.src_port_range.start_port = 0; + rule_struct->key.src_port_range.end_port = 65535; + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_NET; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_NET_BIT_LEN: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_SRC_NET_BIT_LEN, next char + } else if(*cur_pos == ':') { + // FPS_SRC_NET_BIT_LEN finish, next is one of FPS_SRC_PORT_RANGE/FPS_SRC_PORT_SINGLE + rule_struct->key.src_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + if(*(cur_pos + 1) == '[') { + stage = FPS_SRC_PORT_RANGE; + } else { + stage = FPS_SRC_PORT_SINGLE; + } + } else if(*cur_pos == ',') { + // FPS_SRC_NET_BIT_LEN finish, ignore FPS_SRC_PORT(default all), next is FPS_DST_NET + rule_struct->key.src_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);; + rule_struct->key.src_port_range.start_port = 0; + rule_struct->key.src_port_range.end_port = 65535; + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_NET; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_PORT_SINGLE: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_SRC_PORT_SINGLE, next char + } else if(*cur_pos == ',') { + // FPS_SRC_PORT_SINGLE finish, next is FPS_DST_NET + rule_struct->key.src_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + rule_struct->key.src_port_range.end_port = rule_struct->key.src_port_range.start_port; + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_NET; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_PORT_RANGE: { + if(*cur_pos == '[') { + stage_begin_pos = cur_pos + 1; + stage = FPS_SRC_PORT_START; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_PORT_START: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_SRC_PORT_START, next char + } else if(*cur_pos == ',') { + // FPS_SRC_PORT_START finish, next is FPS_SRC_PORT_END + rule_struct->key.src_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + stage = FPS_SRC_PORT_END; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_PORT_END: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_SRC_PORT_END, next char + } else if((*cur_pos == ']') && (*(cur_pos + 1) == ',')) { + // FPS_SRC_PORT_END finish, next is FPS_DST_NET + rule_struct->key.src_port_range.end_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 2; + stage = FPS_DST_NET; + ++cur_pos; //skip next char ',' + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_DST_NET: { + if((*cur_pos >= '0' && *cur_pos <= '9') || *cur_pos == '.') { + ; // Normal FPS_DST_NET, next char + } else if(*cur_pos == '/') { + // FPS_DST_NET finish, next is FPS_DST_NET_BIT_LEN + rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_NET_BIT_LEN; + } else if(*cur_pos == ':') { + // FPS_DST_NET finish, ignore FPS_DST_NET_BIT_LEN(default 32), next is one of FPS_DST_PORT_RANGE/FPS_DST_PORT_SINGLE + rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + rule_struct->key.dst_net_bit_len = 32; + stage_begin_pos = cur_pos + 1; + if(*(cur_pos + 1) == '[') { + stage = FPS_DST_PORT_RANGE; + } else { + stage = FPS_DST_PORT_SINGLE; + } + } else if((*cur_pos == ',') || (*cur_pos == 0)) { + // FPS_DST_NET finish, ignore FPS_DST_NET_BIT_LEN(default 32), ignore FPS_DST_PORT(default all), + // next is FPS_PROTO + rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + rule_struct->key.dst_net_bit_len = 32; + rule_struct->key.dst_port_range.start_port = 0; + rule_struct->key.dst_port_range.end_port = 65535; + stage_begin_pos = cur_pos + 1; + stage = FPS_PROTO; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_DST_NET_BIT_LEN: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_DST_NET_BIT_LEN, next char + } else if(*cur_pos == ':') { + // FPS_DST_NET_BIT_LEN finish, next is one of FPS_DST_PORT_RANGE/FPS_DST_PORT_SINGLE + rule_struct->key.dst_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + if(*(cur_pos + 1) == '[') { + stage = FPS_DST_PORT_RANGE; + } else { + stage = FPS_DST_PORT_SINGLE; + } + } else if((*cur_pos == ',') || (*cur_pos == 0)) { + // FPS_DST_NET_BIT_LEN finish, ignore FPS_DST_PORT(default all), next is FPS_PROTO + rule_struct->key.dst_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);; + rule_struct->key.dst_port_range.start_port = 0; + rule_struct->key.dst_port_range.end_port = 65535; + stage_begin_pos = cur_pos + 1; + stage = FPS_PROTO; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_DST_PORT_SINGLE: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_DST_PORT_SINGLE, next char + } else if((*cur_pos == ',') || (*cur_pos == 0)) { + // FPS_DST_PORT_SINGLE finish, next is FPS_PROTO + rule_struct->key.dst_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + rule_struct->key.dst_port_range.end_port = rule_struct->key.dst_port_range.start_port; + stage_begin_pos = cur_pos + 1; + stage = FPS_PROTO; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; } - break; - } - - case FPS_DST_PORT_SINGLE: { - if((*cur_pos >= '0') && (*cur_pos <= '9')) { - ; // Normal FPS_DST_PORT_SINGLE, next char - } else if((*cur_pos == ',') || (*cur_pos == 0)) { - // FPS_DST_PORT_SINGLE finish, next is FPS_PROTO - rule_struct->key.dst_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); - rule_struct->key.dst_port_range.end_port = rule_struct->key.dst_port_range.start_port; - stage_begin_pos = cur_pos + 1; - stage = FPS_PROTO; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } - case FPS_DST_PORT_RANGE: { - if(*cur_pos == '[') { - stage_begin_pos = cur_pos + 1; - stage = FPS_DST_PORT_START; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } + case FPS_DST_PORT_RANGE: { + if(*cur_pos == '[') { + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_PORT_START; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } - case FPS_DST_PORT_START: { - if((*cur_pos >= '0') && (*cur_pos <= '9')) { - ; // Normal FPS_DST_PORT_START, next char - } else if(*cur_pos == ',') { - // FPS_DST_PORT_START finish, next is FPS_DST_PORT_END - rule_struct->key.dst_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); - stage_begin_pos = cur_pos + 1; - stage = FPS_DST_PORT_END; - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } + case FPS_DST_PORT_START: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_DST_PORT_START, next char + } else if(*cur_pos == ',') { + // FPS_DST_PORT_START finish, next is FPS_DST_PORT_END + rule_struct->key.dst_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_PORT_END; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } - case FPS_DST_PORT_END: { - if((*cur_pos >= '0') && (*cur_pos <= '9')) { - ; // Normal FPS_DST_PORT_END, next char - } else if(*cur_pos == ']') { - // FPS_DST_PORT_END finish, next is FPS_PROTO - rule_struct->key.dst_port_range.end_port = get_int32_from_number_string(stage_begin_pos, cur_pos); - stage = FPS_PROTO; - if(*(cur_pos + 1) == ',') { - stage_begin_pos = cur_pos + 2; - ++cur_pos; //skip next char ',' - } else if(*(cur_pos + 1) != 0) { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; + case FPS_DST_PORT_END: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_DST_PORT_END, next char + } else if(*cur_pos == ']') { + // FPS_DST_PORT_END finish, next is FPS_PROTO + rule_struct->key.dst_port_range.end_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage = FPS_PROTO; + if(*(cur_pos + 1) == ',') { + stage_begin_pos = cur_pos + 2; + ++cur_pos; //skip next char ',' + } else if(*(cur_pos + 1) != 0) { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; } - } else { - traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); - return 0; - } - break; - } - case FPS_PROTO: { - if((*cur_pos != '-') && (*cur_pos != '+') && (*cur_pos != ',')) { - ; // Normal FPS_PROTO. next char - } else if(*cur_pos != ',') { - process_traffic_filter_proto(stage_begin_pos, cur_pos + 1, rule_struct); - if(*(cur_pos+1) == 0) { // end of whole rule string - break; - } else { // new proto info, and skip next char ',' - stage_begin_pos = cur_pos + 2; - ++cur_pos; + case FPS_PROTO: { + if((*cur_pos != '-') && (*cur_pos != '+') && (*cur_pos != ',')) { + ; // Normal FPS_PROTO. next char + } else if(*cur_pos != ',') { + process_traffic_filter_proto(stage_begin_pos, cur_pos + 1, rule_struct); + if(*(cur_pos+1) == 0) { // end of whole rule string + break; + } else { // new proto info, and skip next char ',' + stage_begin_pos = cur_pos + 2; + ++cur_pos; + } + } else { + traceEvent(TRACE_WARNING, "Internal Error: ',' should skiped", *cur_pos, cur_pos - rule_str); + return 0; + } + break; } - } else { - traceEvent(TRACE_WARNING, "Internal Error: ',' should skiped", *cur_pos, cur_pos - rule_str); - return 0; - } - break; } - } - if(0 == *cur_pos) { - break; - } - ++cur_pos; - } + if(0 == *cur_pos) { + break; + } + ++cur_pos; + } - return 1; + return 1; } diff --git a/src/sn.c b/src/sn.c index 04a2913..b189397 100644 --- a/src/sn.c +++ b/src/sn.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -31,144 +31,144 @@ static const n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0}; */ static int load_allowed_sn_community (n2n_sn_t *sss, char *path) { - char buffer[4096], *line, *cmn_str, net_str[20]; - dec_ip_str_t ip_str = {'\0'}; - uint8_t bitlen; - in_addr_t net; - uint32_t mask; - FILE *fd = fopen(path, "r"); - struct sn_community *s, *tmp; - uint32_t num_communities = 0; - struct sn_community_regular_expression *re, *tmp_re; - uint32_t num_regex = 0; - int has_net; - - if(fd == NULL) { - traceEvent(TRACE_WARNING, "File %s not found", path); - return -1; - } - - HASH_ITER(hh, sss->communities, s, tmp) { - if(s->is_federation) { - continue; + char buffer[4096], *line, *cmn_str, net_str[20]; + dec_ip_str_t ip_str = {'\0'}; + uint8_t bitlen; + in_addr_t net; + uint32_t mask; + FILE *fd = fopen(path, "r"); + struct sn_community *s, *tmp; + uint32_t num_communities = 0; + struct sn_community_regular_expression *re, *tmp_re; + uint32_t num_regex = 0; + int has_net; + + if(fd == NULL) { + traceEvent(TRACE_WARNING, "File %s not found", path); + return -1; } - HASH_DEL(sss->communities, s); - if(NULL != s->header_encryption_ctx) { - free (s->header_encryption_ctx); - } - free(s); - } - - HASH_ITER(hh, sss->rules, re, tmp_re) { - HASH_DEL(sss->rules, re); - free(re); - } - while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { - int len = strlen(line); - - if(((len < 2) || line[0]) == '#') { - continue; + HASH_ITER(hh, sss->communities, s, tmp) { + if(s->is_federation) { + continue; + } + HASH_DEL(sss->communities, s); + if(NULL != s->header_encryption_ctx) { + free(s->header_encryption_ctx); + } + free(s); } - len--; - while(len > 0) { - if((line[len] == '\n') || (line[len] == '\r')) { - line[len] = '\0'; - len--; - } else { - break; - } + HASH_ITER(hh, sss->rules, re, tmp_re) { + HASH_DEL(sss->rules, re); + free(re); } - // cut off any IP sub-network upfront - cmn_str = (char*)calloc(len + 1, sizeof(char)); - has_net = (sscanf(line, "%s %s", cmn_str, net_str) == 2); - - // if it contains typical characters... - if(NULL != strpbrk(cmn_str, ".*+?[]\\")) { - // ...it is treated as regular expression - re = (struct sn_community_regular_expression*)calloc(1, sizeof(struct sn_community_regular_expression)); - if(re) { - re->rule = re_compile(cmn_str); - HASH_ADD_PTR(sss->rules, rule, re); - num_regex++; - traceEvent(TRACE_INFO, "Added regular expression for allowed communities '%s'", cmn_str); - free(cmn_str); - continue; - } - } + while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { + int len = strlen(line); - s = (struct sn_community*)calloc(1, sizeof(struct sn_community)); - - if(s != NULL) { - comm_init(s,cmn_str); - /* loaded from file, this community is unpurgeable */ - s->purgeable = COMMUNITY_UNPURGEABLE; - /* we do not know if header encryption is used in this community, - * first packet will show. just in case, setup the key. */ - s->header_encryption = HEADER_ENCRYPTION_UNKNOWN; - packet_header_setup_key (s->community, &(s->header_encryption_ctx), &(s->header_iv_ctx)); - HASH_ADD_STR(sss->communities, community, s); - - num_communities++; - traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]", - (char*)s->community, num_communities); - - // check for sub-network address - if(has_net) { - if(sscanf(net_str, "%15[^/]/%hhu", ip_str, &bitlen) != 2) { - traceEvent(TRACE_WARNING, "Bad net/bit format '%s' for community '%c', ignoring. See comments inside community.list file.", - net_str, cmn_str); - has_net = 0; + if((len < 2) || line[0] == '#') { + continue; } - net = inet_addr(ip_str); - mask = bitlen2mask(bitlen); - if((net == (in_addr_t)(-1)) || (net == INADDR_NONE) || (net == INADDR_ANY) - || ((ntohl(net) & ~mask) != 0) ) { - traceEvent(TRACE_WARNING, "Bad network '%s/%u' in '%s' for community '%s', ignoring.", - ip_str, bitlen, net_str, cmn_str); - has_net = 0; + + len--; + while(len > 0) { + if((line[len] == '\n') || (line[len] == '\r')) { + line[len] = '\0'; + len--; + } else { + break; + } } - if((bitlen > 30) || (bitlen == 0)) { - traceEvent(TRACE_WARNING, "Bad prefix '%hhu' in '%s' for community '%s', ignoring.", - bitlen, net_str, cmn_str); - has_net = 0; + + // cut off any IP sub-network upfront + cmn_str = (char*)calloc(len + 1, sizeof(char)); + has_net = (sscanf(line, "%s %s", cmn_str, net_str) == 2); + + // if it contains typical characters... + if(NULL != strpbrk(cmn_str, ".*+?[]\\")) { + // ...it is treated as regular expression + re = (struct sn_community_regular_expression*)calloc(1,sizeof(struct sn_community_regular_expression)); + if(re) { + re->rule = re_compile(cmn_str); + HASH_ADD_PTR(sss->rules, rule, re); + num_regex++; + traceEvent(TRACE_INFO, "Added regular expression for allowed communities '%s'", cmn_str); + free(cmn_str); + continue; + } } - } - if(has_net) { - s->auto_ip_net.net_addr = ntohl(net); - s->auto_ip_net.net_bitlen = bitlen; - traceEvent(TRACE_INFO, "Assigned sub-network %s/%u to community '%s'.", - inet_ntoa(*(struct in_addr *) &net), - s->auto_ip_net.net_bitlen, - s->community); - } else { - assign_one_ip_subnet(sss, s); - } - } - free(cmn_str); + s = (struct sn_community*)calloc(1,sizeof(struct sn_community)); + + if(s != NULL) { + comm_init(s,cmn_str); + /* loaded from file, this community is unpurgeable */ + s->purgeable = COMMUNITY_UNPURGEABLE; + /* we do not know if header encryption is used in this community, + * first packet will show. just in case, setup the key. */ + s->header_encryption = HEADER_ENCRYPTION_UNKNOWN; + packet_header_setup_key (s->community, &(s->header_encryption_ctx), &(s->header_iv_ctx)); + HASH_ADD_STR(sss->communities, community, s); + + num_communities++; + traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]", + (char*)s->community, num_communities); + + // check for sub-network address + if(has_net) { + if(sscanf(net_str, "%15[^/]/%hhu", ip_str, &bitlen) != 2) { + traceEvent(TRACE_WARNING, "Bad net/bit format '%s' for community '%c', ignoring. See comments inside community.list file.", + net_str, cmn_str); + has_net = 0; + } + net = inet_addr(ip_str); + mask = bitlen2mask(bitlen); + if((net == (in_addr_t)(-1)) || (net == INADDR_NONE) || (net == INADDR_ANY) + || ((ntohl(net) & ~mask) != 0)) { + traceEvent(TRACE_WARNING, "Bad network '%s/%u' in '%s' for community '%s', ignoring.", + ip_str, bitlen, net_str, cmn_str); + has_net = 0; + } + if((bitlen > 30) || (bitlen == 0)) { + traceEvent(TRACE_WARNING, "Bad prefix '%hhu' in '%s' for community '%s', ignoring.", + bitlen, net_str, cmn_str); + has_net = 0; + } + } + if(has_net) { + s->auto_ip_net.net_addr = ntohl(net); + s->auto_ip_net.net_bitlen = bitlen; + traceEvent(TRACE_INFO, "Assigned sub-network %s/%u to community '%s'.", + inet_ntoa(*(struct in_addr *) &net), + s->auto_ip_net.net_bitlen, + s->community); + } else { + assign_one_ip_subnet(sss, s); + } + } + + free(cmn_str); - } + } - fclose(fd); + fclose(fd); - if((num_regex + num_communities) == 0) { - traceEvent(TRACE_WARNING, "File %s does not contain any valid community names or regular expressions", path); - return -1; - } + if((num_regex + num_communities) == 0) { + traceEvent(TRACE_WARNING, "File %s does not contain any valid community names or regular expressions", path); + return -1; + } - traceEvent(TRACE_NORMAL, "Loaded %u fixed-name communities from %s", - num_communities, path); + traceEvent(TRACE_NORMAL, "Loaded %u fixed-name communities from %s", + num_communities, path); - traceEvent(TRACE_NORMAL, "Loaded %u regular expressions for community name matching from %s", - num_regex, path); + traceEvent(TRACE_NORMAL, "Loaded %u regular expressions for community name matching from %s", + num_regex, path); - /* No new communities will be allowed */ - sss->lock_communities = 1; + /* No new communities will be allowed */ + sss->lock_communities = 1; - return(0); + return(0); } @@ -177,232 +177,236 @@ static int load_allowed_sn_community (n2n_sn_t *sss, char *path) { /** Help message to print if the command line arguments are not valid. */ static void help () { - print_n2n_version(); + print_n2n_version(); - printf("supernode (see supernode.conf)\n" - "or\n" - ); - printf("supernode "); - printf("-p "); - printf("-c "); - printf("-l "); + printf("supernode (see supernode.conf)\n" + "or\n" + ); + printf("supernode "); + printf("-p "); + printf("-c "); + printf("-l "); + #if defined(N2N_HAVE_DAEMON) - printf("[-f] "); + printf("[-f] "); #endif - printf("[-F ] "); + printf("[-F ] "); #if 0 - printf("[-m ] "); + printf("[-m ] "); #endif #ifndef WIN32 - printf("[-u -g ] "); + printf("[-u -g ] "); #endif /* ifndef WIN32 */ - printf("[-t ] "); - printf("[-a ] "); - printf("[-v] "); - printf("\n\n"); - - printf("-p | Set UDP main listen port to \n"); - printf("-c | File containing the allowed communities.\n"); - printf("-l | Name/IP of a known supernode:port.\n"); + printf("[-t ] "); + printf("[-a ] "); + printf("[-v] "); + printf("\n\n"); + + printf("-p | Set UDP main listen port to \n"); + printf("-c | File containing the allowed communities.\n"); + printf("-l | Name/IP of a known supernode:port.\n"); #if defined(N2N_HAVE_DAEMON) - printf("-f | Run in foreground.\n"); + printf("-f | Run in foreground.\n"); #endif /* #if defined(N2N_HAVE_DAEMON) */ - printf("-F | Name of the supernodes federation (otherwise use '%s' by default)\n",(char *)FEDERATION_NAME); + printf("-F | Name of the supernodes federation (otherwise use '%s' by default)\n", (char *)FEDERATION_NAME); #if 0 - printf("-m | Fix MAC address for the supernode (otherwise it may be random)\n" - " | eg. -m 01:02:03:04:05:06\n"); + printf("-m | Fix MAC address for the supernode (otherwise it may be random)\n" + " | eg. -m 01:02:03:04:05:06\n"); #endif /* #if 0 */ #ifndef WIN32 - printf("-u | User ID (numeric) to use when privileges are dropped.\n"); - printf("-g | Group ID (numeric) to use when privileges are dropped.\n"); + printf("-u | User ID (numeric) to use when privileges are dropped.\n"); + printf("-g | Group ID (numeric) to use when privileges are dropped.\n"); #endif /* ifndef WIN32 */ - printf("-t | Management UDP Port (for multiple supernodes on a machine).\n"); - printf("-a | Subnet range for auto ip address service, e.g.\n"); - printf(" | -a 192.168.0.0-192.168.255.0/24, defaults to 10.128.255.0-10.255.255.0/24\n"); - printf("-v | Increase verbosity. Can be used multiple times.\n"); - printf("-h | This help message.\n"); - printf("\n"); - - exit(1); + printf("-t | Management UDP Port (for multiple supernodes on a machine).\n"); + printf("-a | Subnet range for auto ip address service, e.g.\n"); + printf(" | -a 192.168.0.0-192.168.255.0/24, defaults to 10.128.255.0-10.255.255.0/24\n"); + printf("-v | Increase verbosity. Can be used multiple times.\n"); + printf("-h | This help message.\n"); + printf("\n"); + + exit(1); } /* *************************************************** */ static int setOption (int optkey, char *_optarg, n2n_sn_t *sss) { - //traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, _optarg ? _optarg : ""); - - switch(optkey) { - case 'p': /* local-port */ - sss->lport = atoi(_optarg); - - if(sss->lport == 0) { - traceEvent(TRACE_WARNING, "Bad local port format"); - break; - } - - break; - - case 't': /* mgmt-port */ - sss->mport = atoi(_optarg); - - if(sss->mport == 0) { - traceEvent(TRACE_WARNING, "Bad management port format"); - break; - } - - break; - - case 'l': { /* supernode:port */ - n2n_sock_t *socket; - struct peer_info *anchor_sn; - size_t length; - int rv = -1; - int skip_add; - char *double_column = strchr(_optarg, ':'); - - length = strlen(_optarg); - if(length >= N2N_EDGE_SN_HOST_SIZE) { - traceEvent(TRACE_WARNING, "Size of -l argument too long: %zu. Maximum size is %d", length, N2N_EDGE_SN_HOST_SIZE); - break; - } - - if(!double_column) { - traceEvent(TRACE_WARNING, "Invalid -l format: ignored"); - return (-1); - } - - socket = (n2n_sock_t *)calloc(1, sizeof(n2n_sock_t)); - rv = supernode2sock(socket, _optarg); - - if(rv != 0) { - traceEvent(TRACE_WARNING, "Invalid socket"); - free(socket); - break; - } - - if(sss->federation != NULL) { - skip_add = SN_ADD; - anchor_sn = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), socket, (n2n_mac_t*) null_mac, &skip_add); - - if(anchor_sn != NULL) { - anchor_sn->ip_addr = calloc(1, N2N_EDGE_SN_HOST_SIZE); - if(anchor_sn->ip_addr) { - strncpy(anchor_sn->ip_addr,_optarg,N2N_EDGE_SN_HOST_SIZE-1); - memcpy(&(anchor_sn->sock), socket, sizeof(n2n_sock_t)); - memcpy(&(anchor_sn->mac_addr), null_mac, sizeof(n2n_mac_t)); - anchor_sn->purgeable = SN_UNPURGEABLE; - anchor_sn->last_valid_time_stamp = initial_time_stamp(); - } + //traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, _optarg ? _optarg : ""); + + switch(optkey) { + case 'p': /* local-port */ + sss->lport = atoi(_optarg); + + if(sss->lport == 0) { + traceEvent(TRACE_WARNING, "Bad local port format"); + break; + } + + break; + + case 't': /* mgmt-port */ + sss->mport = atoi(_optarg); + + if(sss->mport == 0) { + traceEvent(TRACE_WARNING, "Bad management port format"); + break; + } + + break; + + case 'l': { /* supernode:port */ + n2n_sock_t *socket; + struct peer_info *anchor_sn; + size_t length; + int rv = -1; + int skip_add; + char *double_column = strchr(_optarg, ':'); + + length = strlen(_optarg); + if(length >= N2N_EDGE_SN_HOST_SIZE) { + traceEvent(TRACE_WARNING, "Size of -l argument too long: %zu. Maximum size is %d", length, N2N_EDGE_SN_HOST_SIZE); + break; + } + + if(!double_column) { + traceEvent(TRACE_WARNING, "Invalid -l format: ignored"); + return (-1); + } + + socket = (n2n_sock_t *)calloc(1, sizeof(n2n_sock_t)); + rv = supernode2sock(socket, _optarg); + + if(rv != 0) { + traceEvent(TRACE_WARNING, "Invalid socket"); + free(socket); + break; + } + + if(sss->federation != NULL) { + + skip_add = SN_ADD; + anchor_sn = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), socket, (n2n_mac_t*) null_mac, &skip_add); + + if(anchor_sn != NULL) { + anchor_sn->ip_addr = calloc(1, N2N_EDGE_SN_HOST_SIZE); + if(anchor_sn->ip_addr) { + strncpy(anchor_sn->ip_addr, _optarg, N2N_EDGE_SN_HOST_SIZE - 1); + memcpy(&(anchor_sn->sock), socket, sizeof(n2n_sock_t)); + memcpy(&(anchor_sn->mac_addr), null_mac, sizeof(n2n_mac_t)); + anchor_sn->purgeable = SN_UNPURGEABLE; + anchor_sn->last_valid_time_stamp = initial_time_stamp(); + + } + } + } + + free(socket); + break; } - } - - free(socket); - break; - } - case 'a': { - dec_ip_str_t ip_min_str = {'\0'}; - dec_ip_str_t ip_max_str = {'\0'}; - in_addr_t net_min, net_max; - uint8_t bitlen; - uint32_t mask; - - if(sscanf(_optarg, "%15[^\\-]-%15[^/]/%hhu", ip_min_str, ip_max_str, &bitlen) != 3) { - traceEvent(TRACE_WARNING, "Bad net-net/bit format '%s'. See -h.", _optarg); - break; - } - - net_min = inet_addr(ip_min_str); - net_max = inet_addr(ip_max_str); - mask = bitlen2mask(bitlen); - if((net_min == (in_addr_t)(-1)) || (net_min == INADDR_NONE) || (net_min == INADDR_ANY) - || (net_max == (in_addr_t)(-1)) || (net_max == INADDR_NONE) || (net_max == INADDR_ANY) - || (ntohl(net_min) > ntohl(net_max)) - || ((ntohl(net_min) & ~mask) != 0) || ((ntohl(net_max) & ~mask) != 0) ) { - traceEvent(TRACE_WARNING, "Bad network range '%s...%s/%u' in '%s', defaulting to '%s...%s/%d'", - ip_min_str, ip_max_str, bitlen, _optarg, - N2N_SN_MIN_AUTO_IP_NET_DEFAULT, N2N_SN_MAX_AUTO_IP_NET_DEFAULT, N2N_SN_AUTO_IP_NET_BIT_DEFAULT); - break; - } - - if((bitlen > 30) || (bitlen == 0)) { - traceEvent(TRACE_WARNING, "Bad prefix '%hhu' in '%s', defaulting to '%s...%s/%d'", - bitlen, _optarg, - N2N_SN_MIN_AUTO_IP_NET_DEFAULT, N2N_SN_MAX_AUTO_IP_NET_DEFAULT, N2N_SN_AUTO_IP_NET_BIT_DEFAULT); - break; - } - - traceEvent(TRACE_NORMAL, "The network range for community ip address service is '%s...%s/%hhu'.", ip_min_str, ip_max_str, bitlen); - - sss->min_auto_ip_net.net_addr = ntohl(net_min); - sss->min_auto_ip_net.net_bitlen = bitlen; - sss->max_auto_ip_net.net_addr = ntohl(net_max); - sss->max_auto_ip_net.net_bitlen = bitlen; - - break; - } + case 'a': { + dec_ip_str_t ip_min_str = {'\0'}; + dec_ip_str_t ip_max_str = {'\0'}; + in_addr_t net_min, net_max; + uint8_t bitlen; + uint32_t mask; + + if(sscanf(_optarg, "%15[^\\-]-%15[^/]/%hhu", ip_min_str, ip_max_str, &bitlen) != 3) { + traceEvent(TRACE_WARNING, "Bad net-net/bit format '%s'. See -h.", _optarg); + break; + } + + net_min = inet_addr(ip_min_str); + net_max = inet_addr(ip_max_str); + mask = bitlen2mask(bitlen); + if((net_min == (in_addr_t)(-1)) || (net_min == INADDR_NONE) || (net_min == INADDR_ANY) + || (net_max == (in_addr_t)(-1)) || (net_max == INADDR_NONE) || (net_max == INADDR_ANY) + || (ntohl(net_min) > ntohl(net_max)) + || ((ntohl(net_min) & ~mask) != 0) || ((ntohl(net_max) & ~mask) != 0)) { + traceEvent(TRACE_WARNING, "Bad network range '%s...%s/%u' in '%s', defaulting to '%s...%s/%d'", + ip_min_str, ip_max_str, bitlen, _optarg, + N2N_SN_MIN_AUTO_IP_NET_DEFAULT, N2N_SN_MAX_AUTO_IP_NET_DEFAULT, N2N_SN_AUTO_IP_NET_BIT_DEFAULT); + break; + } + + if((bitlen > 30) || (bitlen == 0)) { + traceEvent(TRACE_WARNING, "Bad prefix '%hhu' in '%s', defaulting to '%s...%s/%d'", + bitlen, _optarg, + N2N_SN_MIN_AUTO_IP_NET_DEFAULT, N2N_SN_MAX_AUTO_IP_NET_DEFAULT, N2N_SN_AUTO_IP_NET_BIT_DEFAULT); + break; + } + + traceEvent(TRACE_NORMAL, "The network range for community ip address service is '%s...%s/%hhu'.", ip_min_str, ip_max_str, bitlen); + + sss->min_auto_ip_net.net_addr = ntohl(net_min); + sss->min_auto_ip_net.net_bitlen = bitlen; + sss->max_auto_ip_net.net_addr = ntohl(net_max); + sss->max_auto_ip_net.net_bitlen = bitlen; + + break; + } #ifndef WIN32 - case 'u': /* unprivileged uid */ - sss->userid = atoi(_optarg); - break; + case 'u': /* unprivileged uid */ + sss->userid = atoi(_optarg); + break; - case 'g': /* unprivileged uid */ - sss->groupid = atoi(_optarg); - break; + case 'g': /* unprivileged uid */ + sss->groupid = atoi(_optarg); + break; #endif - case 'F': { /* federation name */ - snprintf(sss->federation->community, N2N_COMMUNITY_SIZE - 1, "*%s", _optarg); - sss->federation->community[N2N_COMMUNITY_SIZE - 1] = '\0'; + case 'F': { /* federation name */ - break; - } + snprintf(sss->federation->community, N2N_COMMUNITY_SIZE - 1 ,"*%s", _optarg); + sss->federation->community[N2N_COMMUNITY_SIZE - 1] = '\0'; + + break; + } #if 0 - case 'm': {/* MAC address */ - str2mac(sss->mac_addr,_optarg); - break; - } + case 'm': {/* MAC address */ + str2mac(sss->mac_addr,_optarg); + break; + } #endif /* #if 0 */ - case 'c': /* community file */ - load_allowed_sn_community(sss, _optarg); - break; + case 'c': /* community file */ + load_allowed_sn_community(sss, _optarg); + break; - case 'f': /* foreground */ - sss->daemon = 0; - break; + case 'f': /* foreground */ + sss->daemon = 0; + break; - case 'h': /* help */ - help(); - break; + case 'h': /* help */ + help(); + break; - case 'v': /* verbose */ - setTraceLevel(getTraceLevel() + 1); - break; + case 'v': /* verbose */ + setTraceLevel(getTraceLevel() + 1); + break; - default: - traceEvent(TRACE_WARNING, "Unknown option -%c: Ignored.", (char)optkey); - return (-1); - } + default: + traceEvent(TRACE_WARNING, "Unknown option -%c: Ignored.", (char) optkey); + return (-1); + } - return (0); + return (0); } /* *********************************************** */ static const struct option long_options[] = { - {"communities", required_argument, NULL, 'c'}, - {"foreground", no_argument, NULL, 'f'}, - {"local-port", required_argument, NULL, 'p'}, - {"mgmt-port", required_argument, NULL, 't'}, - {"autoip", required_argument, NULL, 'a'}, - {"help", no_argument, NULL, 'h'}, - {"verbose", no_argument, NULL, 'v'}, - {NULL, 0, NULL, 0} + {"communities", required_argument, NULL, 'c'}, + {"foreground", no_argument, NULL, 'f'}, + {"local-port", required_argument, NULL, 'p'}, + {"mgmt-port", required_argument, NULL, 't'}, + {"autoip", required_argument, NULL, 'a'}, + {"help", no_argument, NULL, 'h'}, + {"verbose", no_argument, NULL, 'v'}, + {NULL, 0, NULL, 0} }; /* *************************************************** */ @@ -410,40 +414,40 @@ static const struct option long_options[] = { /* read command line options */ static int loadFromCLI (int argc, char * const argv[], n2n_sn_t *sss) { - u_char c; + u_char c; - while((c = getopt_long(argc, argv, "fp:l:u:g:t:a:c:F:m:vh", - long_options, NULL)) != '?') { - if(c == 255) { - break; + while((c = getopt_long(argc, argv, "fp:l:u:g:t:a:c:F:m:vh", + long_options, NULL)) != '?') { + if(c == 255) { + break; + } + setOption(c, optarg, sss); } - setOption(c, optarg, sss); - } - return 0; + return 0; } /* *************************************************** */ static char *trim (char *s) { - char *end; + char *end; - while(isspace(s[0]) || (s[0] == '"') || (s[0] == '\'')) { - s++; - } + while(isspace(s[0]) || (s[0] == '"') || (s[0] == '\'')) { + s++; + } - if(s[0] == 0) { - return s; - } + if(s[0] == 0) { + return s; + } - end = &s[strlen(s) - 1]; - while(end > s && (isspace(end[0])|| (end[0] == '"') || (end[0] == '\''))) { - end--; - } - end[1] = 0; + end = &s[strlen(s) - 1]; + while(end > s && (isspace(end[0])|| (end[0] == '"') || (end[0] == '\''))) { + end--; + } + end[1] = 0; - return s; + return s; } /* *************************************************** */ @@ -451,72 +455,69 @@ static char *trim (char *s) { /* parse the configuration file */ static int loadFromFile (const char *path, n2n_sn_t *sss) { - char buffer[4096], *line, *key, *value; - u_int line_len, opt_name_len; - FILE *fd; - const struct option *opt; + char buffer[4096], *line, *key, *value; + u_int line_len, opt_name_len; + FILE *fd; + const struct option *opt; - fd = fopen(path, "r"); + fd = fopen(path, "r"); - if(fd == NULL) { - traceEvent(TRACE_WARNING, "Config file %s not found", path); - return -1; - } + if(fd == NULL) { + traceEvent(TRACE_WARNING, "Config file %s not found", path); + return -1; + } - while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { - line = trim(line); - value = NULL; + while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { - if((line_len = strlen(line)) < 2 || line[0] == '#') { - continue; - } + line = trim(line); + value = NULL; - if(!strncmp(line, "--", 2)) { /* long opt */ - key = &line[2], line_len -= 2; - - opt = long_options; - while(opt->name != NULL) { - opt_name_len = strlen(opt->name); - - if(!strncmp(key, opt->name, opt_name_len) - && (line_len <= opt_name_len - || key[opt_name_len] == '\0' - || key[opt_name_len] == ' ' - || key[opt_name_len] == '=')) { - if(line_len > opt_name_len) { - key[opt_name_len] = '\0'; - } - if(line_len > opt_name_len + 1) { - value = trim(&key[opt_name_len + 1]); - } - - // traceEvent(TRACE_NORMAL, "long key: %s value: %s", key, value); - setOption(opt->val, value, sss); - break; + if((line_len = strlen(line)) < 2 || line[0] == '#') { + continue; } - opt++; - } - } else if(line[0] == '-') { /* short opt */ - key = &line[1], line_len--; - if(line_len > 1) { - key[1] = '\0'; - } - if(line_len > 2) { - value = trim(&key[2]); - } - - // traceEvent(TRACE_NORMAL, "key: %c value: %s", key[0], value); - setOption(key[0], value, sss); - } else { - traceEvent(TRACE_WARNING, "Skipping unrecognized line: %s", line); - continue; + if(!strncmp(line, "--", 2)) { /* long opt */ + key = &line[2], line_len -= 2; + + opt = long_options; + while(opt->name != NULL) { + opt_name_len = strlen(opt->name); + + if(!strncmp(key, opt->name, opt_name_len) + && (line_len <= opt_name_len + || key[opt_name_len] == '\0' + || key[opt_name_len] == ' ' + || key[opt_name_len] == '=')) { + if(line_len > opt_name_len) { + key[opt_name_len] = '\0'; + } + if(line_len > opt_name_len + 1) { + value = trim(&key[opt_name_len + 1]); + } + + // traceEvent(TRACE_NORMAL, "long key: %s value: %s", key, value); + setOption(opt->val, value, sss); + break; + } + + opt++; + } + } else if(line[0] == '-') { /* short opt */ + key = &line[1], line_len--; + if(line_len > 1) key[1] = '\0'; + if(line_len > 2) value = trim(&key[2]); + + // traceEvent(TRACE_NORMAL, "key: %c value: %s", key[0], value); + setOption(key[0], value, sss); + } else { + traceEvent(TRACE_WARNING, "Skipping unrecognized line: %s", line); + continue; + } } - } - fclose(fd); + fclose(fd); - return 0; + return 0; } /* *************************************************** */ @@ -524,16 +525,18 @@ static int loadFromFile (const char *path, n2n_sn_t *sss) { /* Add the federation to the communities list of a supernode */ static int add_federation_to_communities (n2n_sn_t *sss) { - uint32_t num_communities = 0; + uint32_t num_communities = 0; + + if(sss->federation != NULL) { + HASH_ADD_STR(sss->communities, community, sss->federation); - if(sss->federation != NULL) { - HASH_ADD_STR(sss->communities, community, sss->federation); - num_communities = HASH_COUNT(sss->communities); - traceEvent(TRACE_INFO, "Added federation '%s' to the list of communities [total: %u]", - (char*)sss->federation->community, num_communities); - } + num_communities = HASH_COUNT(sss->communities); - return 0; + traceEvent(TRACE_INFO, "Added federation '%s' to the list of communities [total: %u]", + (char*)sss->federation->community, num_communities); + } + + return 0; } /* *************************************************** */ @@ -541,33 +544,33 @@ static int add_federation_to_communities (n2n_sn_t *sss) { #ifdef __linux__ static void dump_registrations (int signo) { - struct sn_community *comm, *ctmp; - struct peer_info *list, *tmp; - char buf[32]; - time_t now = time(NULL); - u_int num = 0; - - traceEvent(TRACE_NORMAL, "===================================="); - - HASH_ITER(hh, sss_node.communities, comm, ctmp) { - traceEvent(TRACE_NORMAL, "Dumping community: %s", comm->community); - - HASH_ITER(hh, comm->edges, list, tmp) { - if(list->sock.family == AF_INET) { - traceEvent(TRACE_NORMAL, "[id: %u][MAC: %s][edge: %u.%u.%u.%u:%u][last seen: %u sec ago]", - ++num, macaddr_str(buf, list->mac_addr), - list->sock.addr.v4[0], list->sock.addr.v4[1], list->sock.addr.v4[2], list->sock.addr.v4[3], - list->sock.port, - now-list->last_seen); - } else { - traceEvent(TRACE_NORMAL, "[id: %u][MAC: %s][edge: IPv6:%u][last seen: %u sec ago]", - ++num, macaddr_str(buf, list->mac_addr), list->sock.port, - now-list->last_seen); - } + struct sn_community *comm, *ctmp; + struct peer_info *list, *tmp; + char buf[32]; + time_t now = time(NULL); + u_int num = 0; + + traceEvent(TRACE_NORMAL, "===================================="); + + HASH_ITER(hh, sss_node.communities, comm, ctmp) { + traceEvent(TRACE_NORMAL, "Dumping community: %s", comm->community); + + HASH_ITER(hh, comm->edges, list, tmp) { + if(list->sock.family == AF_INET) { + traceEvent(TRACE_NORMAL, "[id: %u][MAC: %s][edge: %u.%u.%u.%u:%u][last seen: %u sec ago]", + ++num, macaddr_str(buf, list->mac_addr), + list->sock.addr.v4[0], list->sock.addr.v4[1], list->sock.addr.v4[2], list->sock.addr.v4[3], + list->sock.port, + now - list->last_seen); + } else { + traceEvent(TRACE_NORMAL, "[id: %u][MAC: %s][edge: IPv6:%u][last seen: %u sec ago]", + ++num, macaddr_str(buf, list->mac_addr), list->sock.port, + now - list->last_seen); + } + } } - } - traceEvent(TRACE_NORMAL, "===================================="); + traceEvent(TRACE_NORMAL, "===================================="); } #endif @@ -579,22 +582,22 @@ static int keep_running; #ifdef WIN32 BOOL WINAPI term_handler (DWORD sig) #else - static void term_handler (int sig) + static void term_handler(int sig) #endif { - static int called = 0; + static int called = 0; - if(called) { - traceEvent(TRACE_NORMAL, "Ok I am leaving now"); - _exit(0); - } else { - traceEvent(TRACE_NORMAL, "Shutting down..."); - called = 1; - } + if(called) { + traceEvent(TRACE_NORMAL, "Ok I am leaving now"); + _exit(0); + } else { + traceEvent(TRACE_NORMAL, "Shutting down..."); + called = 1; + } - keep_running = 0; + keep_running = 0; #ifdef WIN32 - return(TRUE); + return(TRUE); #endif } #endif /* defined(__linux__) || defined(WIN32) */ @@ -604,94 +607,98 @@ BOOL WINAPI term_handler (DWORD sig) /** Main program entry point from kernel. */ int main (int argc, char * const argv[]) { - int rc; + int rc; + #ifndef WIN32 - struct passwd *pw = NULL; + struct passwd *pw = NULL; #endif - sn_init(&sss_node); - add_federation_to_communities(&sss_node); + sn_init(&sss_node); + add_federation_to_communities(&sss_node); - if((argc >= 2) && (argv[1][0] != '-')) { - rc = loadFromFile(argv[1], &sss_node); - if(argc > 2) { - rc = loadFromCLI(argc, argv, &sss_node); - } - } else if(argc > 1) { - rc = loadFromCLI(argc, argv, &sss_node); - } else + if((argc >= 2) && (argv[1][0] != '-')) { + rc = loadFromFile(argv[1], &sss_node); + if(argc > 2) { + rc = loadFromCLI(argc, argv, &sss_node); + } + } else if(argc > 1) { + rc = loadFromCLI(argc, argv, &sss_node); + } else + #ifdef WIN32 - /* Load from current directory */ - rc = loadFromFile("supernode.conf", &sss_node); + /* Load from current directory */ + rc = loadFromFile("supernode.conf", &sss_node); #else - rc = -1; + rc = -1; #endif - if(rc < 0) { - help(); - } + if(rc < 0) { + help(); + } + #if defined(N2N_HAVE_DAEMON) - if(sss_node.daemon) { - setUseSyslog(1); /* traceEvent output now goes to syslog. */ + if(sss_node.daemon) { + setUseSyslog(1); /* traceEvent output now goes to syslog. */ - if(-1 == daemon(0, 0)) { - traceEvent(TRACE_ERROR, "Failed to become daemon."); - exit(-5); + if(-1 == daemon(0, 0)) { + traceEvent(TRACE_ERROR, "Failed to become daemon."); + exit(-5); + } } - } #endif /* #if defined(N2N_HAVE_DAEMON) */ - traceEvent(TRACE_DEBUG, "traceLevel is %d", getTraceLevel()); - - sss_node.sock = open_socket(sss_node.lport, 1 /*bind ANY*/); - if(-1 == sss_node.sock) { - traceEvent(TRACE_ERROR, "Failed to open main socket. %s", strerror(errno)); - exit(-2); - } else { - traceEvent(TRACE_NORMAL, "supernode is listening on UDP %u (main)", sss_node.lport); - } - - sss_node.mgmt_sock = open_socket(sss_node.mport, 0 /* bind LOOPBACK */); - if(-1 == sss_node.mgmt_sock) { - traceEvent(TRACE_ERROR, "Failed to open management socket. %s", strerror(errno)); - exit(-2); - } else { - traceEvent(TRACE_NORMAL, "supernode is listening on UDP %u (management)", sss_node.mport); - } + traceEvent(TRACE_DEBUG, "traceLevel is %d", getTraceLevel()); + + sss_node.sock = open_socket(sss_node.lport, 1 /*bind ANY*/); + if(-1 == sss_node.sock) { + traceEvent(TRACE_ERROR, "Failed to open main socket. %s", strerror(errno)); + exit(-2); + } else { + traceEvent(TRACE_NORMAL, "supernode is listening on UDP %u (main)", sss_node.lport); + } + + sss_node.mgmt_sock = open_socket(sss_node.mport, 0 /* bind LOOPBACK */); + if(-1 == sss_node.mgmt_sock) { + traceEvent(TRACE_ERROR, "Failed to open management socket. %s", strerror(errno)); + exit(-2); + } else { + traceEvent(TRACE_NORMAL, "supernode is listening on UDP %u (management)", sss_node.mport); + } + #ifndef WIN32 - if(((pw = getpwnam ("n2n")) != NULL) || ((pw = getpwnam ("nobody")) != NULL)) { - sss_node.userid = sss_node.userid == 0 ? pw->pw_uid : 0; - sss_node.groupid = sss_node.groupid == 0 ? pw->pw_gid : 0; - } - if((sss_node.userid != 0) || (sss_node.groupid != 0)) { - traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d", - (signed int)sss_node.userid, (signed int)sss_node.groupid); - - /* Finished with the need for root privileges. Drop to unprivileged user. */ - if((setgid(sss_node.groupid) != 0) - || (setuid(sss_node.userid) != 0)) { - traceEvent(TRACE_ERROR, "Unable to drop privileges [%u/%s]", errno, strerror(errno)); - exit(1); + if(((pw = getpwnam ("n2n")) != NULL) || ((pw = getpwnam ("nobody")) != NULL)) { + sss_node.userid = sss_node.userid == 0 ? pw->pw_uid : 0; + sss_node.groupid = sss_node.groupid == 0 ? pw->pw_gid : 0; + } + if((sss_node.userid != 0) || (sss_node.groupid != 0)) { + traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d", + (signed int)sss_node.userid, (signed int)sss_node.groupid); + + /* Finished with the need for root privileges. Drop to unprivileged user. */ + if((setgid(sss_node.groupid) != 0) + || (setuid(sss_node.userid) != 0)) { + traceEvent(TRACE_ERROR, "Unable to drop privileges [%u/%s]", errno, strerror(errno)); + exit(1); + } } - } - if((getuid() == 0) || (getgid() == 0)) { - traceEvent(TRACE_WARNING, "Running as root is discouraged, check out the -u/-g options"); - } + if((getuid() == 0) || (getgid() == 0)) { + traceEvent(TRACE_WARNING, "Running as root is discouraged, check out the -u/-g options"); + } #endif - traceEvent(TRACE_NORMAL, "supernode started"); + traceEvent(TRACE_NORMAL, "supernode started"); #ifdef __linux__ - signal(SIGTERM, term_handler); - signal(SIGINT, term_handler); - signal(SIGHUP, dump_registrations); + signal(SIGTERM, term_handler); + signal(SIGINT, term_handler); + signal(SIGHUP, dump_registrations); #endif #ifdef WIN32 - SetConsoleCtrlHandler(term_handler, TRUE); + SetConsoleCtrlHandler(term_handler, TRUE); #endif - keep_running = 1; - return run_sn_loop(&sss_node, &keep_running); + keep_running = 1; + return run_sn_loop(&sss_node, &keep_running); } diff --git a/src/sn_selection.c b/src/sn_selection.c index 4e7fdff..444caa3 100644 --- a/src/sn_selection.c +++ b/src/sn_selection.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -27,19 +27,19 @@ static int sn_selection_criterion_sort (peer_info_t *a, peer_info_t *b); /* Initialize selection_criterion field in peer_info structure*/ int sn_selection_criterion_init (peer_info_t *peer) { - if(peer != NULL) { - sn_selection_criterion_default(&(peer->selection_criterion)); - } + if(peer != NULL) { + sn_selection_criterion_default(&(peer->selection_criterion)); + } - return 0; /* OK */ + return 0; /* OK */ } /* Set selection_criterion field to default value according to selected strategy. */ int sn_selection_criterion_default (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion) { - *selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE) UINT32_MAX >> 1; + *selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE) UINT32_MAX >> 1; - return 0; /* OK */ + return 0; /* OK */ } /* Take data from PEER_INFO payload and transform them into a selection_criterion. @@ -47,84 +47,84 @@ int sn_selection_criterion_default (SN_SELECTION_CRITERION_DATA_TYPE *selection_ */ int sn_selection_criterion_calculate (n2n_edge_t *eee, peer_info_t *peer, SN_SELECTION_CRITERION_DATA_TYPE *data) { - SN_SELECTION_CRITERION_DATA_TYPE common_data; - int sum = 0; + SN_SELECTION_CRITERION_DATA_TYPE common_data; + int sum = 0; - common_data = sn_selection_criterion_common_read(eee); - peer->selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(be32toh(*data) + common_data); + common_data = sn_selection_criterion_common_read(eee); + peer->selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(be32toh(*data) + common_data); - /* Mitigation of the real supernode load in order to see less oscillations. - * Edges jump from a supernode to another back and forth due to purging. - * Because this behavior has a cost of switching, the real load is mitigated with a stickyness factor. - * This factor is dynamically calculated basing on network size and prevent that unnecessary switching */ - if(peer == eee->curr_sn) { - sum = HASH_COUNT(eee->known_peers) + HASH_COUNT(eee->pending_peers); - peer->selection_criterion = peer->selection_criterion * sum / (sum + 1); - } + /* Mitigation of the real supernode load in order to see less oscillations. + * Edges jump from a supernode to another back and forth due to purging. + * Because this behavior has a cost of switching, the real load is mitigated with a stickyness factor. + * This factor is dynamically calculated basing on network size and prevent that unnecessary switching */ + if(peer == eee->curr_sn) { + sum = HASH_COUNT(eee->known_peers) + HASH_COUNT(eee->pending_peers); + peer->selection_criterion = peer->selection_criterion * sum / (sum + 1); + } - return 0; /* OK */ + return 0; /* OK */ } /* Set sn_selection_criterion_common_data field to default value. */ int sn_selection_criterion_common_data_default (n2n_edge_t *eee) { - SN_SELECTION_CRITERION_DATA_TYPE tmp = 0; + SN_SELECTION_CRITERION_DATA_TYPE tmp = 0; - tmp = HASH_COUNT(eee->pending_peers); - if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { - tmp *= 2; - } - eee->sn_selection_criterion_common_data = tmp / HASH_COUNT(eee->conf.supernodes); + tmp = HASH_COUNT(eee->pending_peers); + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + tmp *= 2; + } + eee->sn_selection_criterion_common_data = tmp / HASH_COUNT(eee->conf.supernodes); - return 0; /* OK */ + return 0; /* OK */ } /* Return the value of sn_selection_criterion_common_data field. */ static SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_common_read (n2n_edge_t *eee) { - return eee->sn_selection_criterion_common_data; + return eee->sn_selection_criterion_common_data; } /* Function that compare two selection_criterion fields and sorts them in ascending order. */ static int sn_selection_criterion_sort (peer_info_t *a, peer_info_t *b) { - // comparison function for sorting supernodes in ascending order of their selection_criterion. - return (a->selection_criterion - b->selection_criterion); + // comparison function for sorting supernodes in ascending order of their selection_criterion. + return (a->selection_criterion - b->selection_criterion); } /* Function that sorts peer_list using sn_selection_criterion_sort. */ int sn_selection_sort (peer_info_t **peer_list) { - HASH_SORT(*peer_list, sn_selection_criterion_sort); + HASH_SORT(*peer_list, sn_selection_criterion_sort); - return 0; /* OK */ + return 0; /* OK */ } /* Function that gathers requested data on a supernode. */ SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_gather_data (n2n_sn_t *sss) { - SN_SELECTION_CRITERION_DATA_TYPE data = 0, tmp = 0; - struct sn_community *comm, *tmp_comm; + SN_SELECTION_CRITERION_DATA_TYPE data = 0, tmp = 0; + struct sn_community *comm, *tmp_comm; - HASH_ITER(hh, sss->communities, comm, tmp_comm) { - tmp = HASH_COUNT(comm->edges) + 1; /* number of nodes in the community + the community itself. */ - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { /*double-count encrypted communities (and their nodes): they exert more load on supernode. */ - tmp *= 2; + HASH_ITER(hh, sss->communities, comm, tmp_comm) { + tmp = HASH_COUNT(comm->edges) + 1; /* number of nodes in the community + the community itself. */ + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { /*double-count encrypted communities (and their nodes): they exert more load on supernode. */ + tmp *= 2; + } + data += tmp; } - data += tmp; - } - return htobe32(data); + return htobe32(data); } /* Convert selection_criterion field in a string for management port output. */ extern char * sn_selection_criterion_str (selection_criterion_str_t out, peer_info_t *peer) { - if(NULL == out) { - return NULL; - } - memset(out, 0, SN_SELECTION_CRITERION_BUF_SIZE); - snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE - 1, "ld = %d", (short int)(peer->selection_criterion)); + if(NULL == out) { + return NULL; + } + memset(out, 0, SN_SELECTION_CRITERION_BUF_SIZE); + snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE - 1, "ld = %d", (short int)(peer->selection_criterion)); - return out; + return out; } diff --git a/src/sn_utils.c b/src/sn_utils.c index e1b1020..2a9416a 100644 --- a/src/sn_utils.c +++ b/src/sn_utils.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -21,17 +21,17 @@ #define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out) static int try_forward (n2n_sn_t * sss, - const struct sn_community *comm, - const n2n_common_t * cmn, - const n2n_mac_t dstMac, - uint8_t from_supernode, - const uint8_t * pktbuf, - size_t pktsize); + const struct sn_community *comm, + const n2n_common_t * cmn, + const n2n_mac_t dstMac, + uint8_t from_supernode, + const uint8_t * pktbuf, + size_t pktsize); static ssize_t sendto_sock (n2n_sn_t *sss, - const n2n_sock_t *sock, - const uint8_t *pktbuf, - size_t pktsize); + const n2n_sock_t *sock, + const uint8_t *pktbuf, + size_t pktsize); static int sendto_mgmt (n2n_sn_t *sss, const struct sockaddr_in *sender_sock, @@ -87,80 +87,80 @@ static int try_forward (n2n_sn_t * sss, const uint8_t * pktbuf, size_t pktsize) { - struct peer_info * scan; - macstr_t mac_buf; - n2n_sock_str_t sockbuf; + struct peer_info * scan; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; - HASH_FIND_PEER(comm->edges, dstMac, scan); + HASH_FIND_PEER(comm->edges, dstMac, scan); - if(NULL != scan) { - int data_sent_len; - data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize); + if(NULL != scan) { + int data_sent_len; + data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize); - if(data_sent_len == pktsize) { - ++(sss->stats.fwd); - traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s", - pktsize, - sock_to_cstr(sockbuf, &(scan->sock)), - macaddr_str(mac_buf, scan->mac_addr)); - } else { - ++(sss->stats.errors); - traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)", - pktsize, - sock_to_cstr(sockbuf, &(scan->sock)), - macaddr_str(mac_buf, scan->mac_addr), - errno, strerror(errno)); - } - } else { - if(!from_supernode) { - /* Forwarding packet to all federated supernodes. */ - traceEvent(TRACE_DEBUG, "Unknown MAC. Broadcasting packet to all federated supernodes."); - try_broadcast(sss, NULL, cmn, sss->mac_addr, from_supernode, pktbuf, pktsize); + if(data_sent_len == pktsize) { + ++(sss->stats.fwd); + traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr)); + } else { + ++(sss->stats.errors); + traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr), + errno, strerror(errno)); + } } else { - traceEvent(TRACE_DEBUG, "try_forward unknown MAC. Dropping the packet."); - /* Not a known MAC so drop. */ - return(-2); + if(!from_supernode) { + /* Forwarding packet to all federated supernodes. */ + traceEvent(TRACE_DEBUG, "Unknown MAC. Broadcasting packet to all federated supernodes."); + try_broadcast(sss, NULL, cmn, sss->mac_addr, from_supernode, pktbuf, pktsize); + } else { + traceEvent(TRACE_DEBUG, "try_forward unknown MAC. Dropping the packet."); + /* Not a known MAC so drop. */ + return(-2); + } } - } - return(0); + return(0); } /** Send a datagram to the destination embodied in a n2n_sock_t. * - * @return -1 on error otherwise number of bytes sent + * @return -1 on error otherwise number of bytes sent */ static ssize_t sendto_sock (n2n_sn_t *sss, const n2n_sock_t *sock, const uint8_t *pktbuf, size_t pktsize) { + + n2n_sock_str_t sockbuf; - n2n_sock_str_t sockbuf; + if(AF_INET == sock->family) { + struct sockaddr_in udpsock; - if(AF_INET == sock->family) { - struct sockaddr_in udpsock; + udpsock.sin_family = AF_INET; + udpsock.sin_port = htons(sock->port); + memcpy(&(udpsock.sin_addr.s_addr), &(sock->addr.v4), IPV4_SIZE); - udpsock.sin_family = AF_INET; - udpsock.sin_port = htons(sock->port); - memcpy(&(udpsock.sin_addr.s_addr), &(sock->addr.v4), IPV4_SIZE); - - traceEvent(TRACE_DEBUG, "sendto_sock %lu to [%s]", - pktsize, - sock_to_cstr(sockbuf, sock)); + traceEvent(TRACE_DEBUG, "sendto_sock %lu to [%s]", + pktsize, + sock_to_cstr(sockbuf, sock)); - return sendto(sss->sock, pktbuf, pktsize, 0, - (const struct sockaddr *)&udpsock, sizeof(struct sockaddr_in)); - } else { - /* AF_INET6 not implemented */ - errno = EAFNOSUPPORT; - return -1; - } + return sendto(sss->sock, pktbuf, pktsize, 0, + (const struct sockaddr *)&udpsock, sizeof(struct sockaddr_in)); + } else { + /* AF_INET6 not implemented */ + errno = EAFNOSUPPORT; + return -1; + } } /** Try and broadcast a message to all edges in the community. * - * This will send the exact same datagram to zero or more edges registered to - * the supernode. + * This will send the exact same datagram to zero or more edges registered to + * the supernode. */ static int try_broadcast (n2n_sn_t * sss, const struct sn_community *comm, @@ -170,204 +170,204 @@ static int try_broadcast (n2n_sn_t * sss, const uint8_t * pktbuf, size_t pktsize) { - struct peer_info *scan, *tmp; - macstr_t mac_buf; - n2n_sock_str_t sockbuf; - - traceEvent(TRACE_DEBUG, "try_broadcast"); - - /* We have to make sure that a broadcast reaches the other supernodes and edges - * connected to them. try_broadcast needs a from_supernode parameter: if set - * do forward to edges of community only. If unset. forward to all locally known - * nodes and all supernodes */ - - if (!from_supernode) { - HASH_ITER(hh, sss->federation->edges, scan, tmp) { - int data_sent_len; - - data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize); - - if(data_sent_len != pktsize) { - ++(sss->stats.errors); - traceEvent(TRACE_WARNING, "multicast %lu to supernode [%s] %s failed %s", - pktsize, - sock_to_cstr(sockbuf, &(scan->sock)), - macaddr_str(mac_buf, scan->mac_addr), - strerror(errno)); - } else { - ++(sss->stats.broadcast); - traceEvent(TRACE_DEBUG, "multicast %lu to supernode [%s] %s", - pktsize, - sock_to_cstr(sockbuf, &(scan->sock)), - macaddr_str(mac_buf, scan->mac_addr)); - } + struct peer_info *scan, *tmp; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + traceEvent(TRACE_DEBUG, "try_broadcast"); + + /* We have to make sure that a broadcast reaches the other supernodes and edges + * connected to them. try_broadcast needs a from_supernode parameter: if set + * do forward to edges of community only. If unset. forward to all locally known + * nodes and all supernodes */ + + if (!from_supernode) { + HASH_ITER(hh, sss->federation->edges, scan, tmp) { + int data_sent_len; + + data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize); + + if(data_sent_len != pktsize) { + ++(sss->stats.errors); + traceEvent(TRACE_WARNING, "multicast %lu to supernode [%s] %s failed %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr), + strerror(errno)); + } else { + ++(sss->stats.broadcast); + traceEvent(TRACE_DEBUG, "multicast %lu to supernode [%s] %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr)); + } + } } - } - - if(comm) { - HASH_ITER(hh, comm->edges, scan, tmp) { - if(memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0) { - /* REVISIT: exclude if the destination socket is where the packet came from. */ - int data_sent_len; - data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize); - - if(data_sent_len != pktsize) { - ++(sss->stats.errors); - traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s", - pktsize, - sock_to_cstr(sockbuf, &(scan->sock)), - macaddr_str(mac_buf, scan->mac_addr), - strerror(errno)); - } else { - ++(sss->stats.broadcast); - traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s", - pktsize, - sock_to_cstr(sockbuf, &(scan->sock)), - macaddr_str(mac_buf, scan->mac_addr)); + if(comm) { + HASH_ITER(hh, comm->edges, scan, tmp) { + if(memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0) { + /* REVISIT: exclude if the destination socket is where the packet came from. */ + int data_sent_len; + + data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize); + + if(data_sent_len != pktsize) { + ++(sss->stats.errors); + traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr), + strerror(errno)); + } else { + ++(sss->stats.broadcast); + traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr)); + } + } } - } } - } - return 0; + return 0; } /** Initialise some fields of the community structure **/ int comm_init (struct sn_community *comm, char *cmn) { - strncpy((char*)comm->community, cmn, N2N_COMMUNITY_SIZE - 1); - comm->community[N2N_COMMUNITY_SIZE - 1] = '\0'; - comm->is_federation = IS_NO_FEDERATION; + strncpy((char*)comm->community, cmn, N2N_COMMUNITY_SIZE - 1); + comm->community[N2N_COMMUNITY_SIZE - 1] = '\0'; + comm->is_federation = IS_NO_FEDERATION; - return 0; /* OK */ + return 0; /* OK */ } /** Initialise the supernode structure */ int sn_init(n2n_sn_t *sss) { - int i; - size_t idx; + int i; + size_t idx; #ifdef WIN32 - initWin32(); + initWin32(); #endif - pearson_hash_init(); - - memset(sss, 0, sizeof(n2n_sn_t)); - - sss->daemon = 1; /* By defult run as a daemon. */ - sss->lport = N2N_SN_LPORT_DEFAULT; - sss->mport = N2N_SN_MGMT_PORT; - sss->sock = -1; - sss->mgmt_sock = -1; - sss->min_auto_ip_net.net_addr = inet_addr(N2N_SN_MIN_AUTO_IP_NET_DEFAULT); - sss->min_auto_ip_net.net_addr = ntohl(sss->min_auto_ip_net.net_addr); - sss->min_auto_ip_net.net_bitlen = N2N_SN_AUTO_IP_NET_BIT_DEFAULT; - sss->max_auto_ip_net.net_addr = inet_addr(N2N_SN_MAX_AUTO_IP_NET_DEFAULT); - sss->max_auto_ip_net.net_addr = ntohl(sss->max_auto_ip_net.net_addr); - sss->max_auto_ip_net.net_bitlen = N2N_SN_AUTO_IP_NET_BIT_DEFAULT; - sss->federation = (struct sn_community *)calloc(1, sizeof(struct sn_community)); - - /* Initialize the federation */ - if(sss->federation) { - strncpy(sss->federation->community, (char*)FEDERATION_NAME, N2N_COMMUNITY_SIZE - 1); - sss->federation->community[N2N_COMMUNITY_SIZE - 1] = '\0'; - /* enable the flag for federation */ - sss->federation->is_federation = IS_FEDERATION; - sss->federation->purgeable = COMMUNITY_UNPURGEABLE; - /* header encryption enabled by default */ - sss->federation->header_encryption = HEADER_ENCRYPTION_ENABLED; - /*setup the encryption key */ - packet_header_setup_key(sss->federation->community, &(sss->federation->header_encryption_ctx), &(sss->federation->header_iv_ctx)); - sss->federation->edges = NULL; - } - - n2n_srand(n2n_seed()); - - /* Random auth token */ - sss->auth.scheme = n2n_auth_simple_id; - - for(idx = 0; idx < N2N_AUTH_TOKEN_SIZE; ++idx) { - sss->auth.token[idx] = n2n_rand() % 0xff; - } - - sss->auth.toksize = sizeof(sss->auth.token); - - /* Random MAC address */ - for(i = 0; i < 6; i++) { - sss->mac_addr[i] = n2n_rand(); - } - sss->mac_addr[0] &= ~0x01; /* Clear multicast bit */ - sss->mac_addr[0] |= 0x02; /* Set locally-assigned bit */ - - return 0; /* OK */ + pearson_hash_init(); + + memset(sss, 0, sizeof(n2n_sn_t)); + + sss->daemon = 1; /* By defult run as a daemon. */ + sss->lport = N2N_SN_LPORT_DEFAULT; + sss->mport = N2N_SN_MGMT_PORT; + sss->sock = -1; + sss->mgmt_sock = -1; + sss->min_auto_ip_net.net_addr = inet_addr(N2N_SN_MIN_AUTO_IP_NET_DEFAULT); + sss->min_auto_ip_net.net_addr = ntohl(sss->min_auto_ip_net.net_addr); + sss->min_auto_ip_net.net_bitlen = N2N_SN_AUTO_IP_NET_BIT_DEFAULT; + sss->max_auto_ip_net.net_addr = inet_addr(N2N_SN_MAX_AUTO_IP_NET_DEFAULT); + sss->max_auto_ip_net.net_addr = ntohl(sss->max_auto_ip_net.net_addr); + sss->max_auto_ip_net.net_bitlen = N2N_SN_AUTO_IP_NET_BIT_DEFAULT; + sss->federation = (struct sn_community *)calloc(1, sizeof(struct sn_community)); + + /* Initialize the federation */ + if(sss->federation) { + strncpy(sss->federation->community, (char*)FEDERATION_NAME, N2N_COMMUNITY_SIZE - 1); + sss->federation->community[N2N_COMMUNITY_SIZE - 1] = '\0'; + /* enable the flag for federation */ + sss->federation->is_federation = IS_FEDERATION; + sss->federation->purgeable = COMMUNITY_UNPURGEABLE; + /* header encryption enabled by default */ + sss->federation->header_encryption = HEADER_ENCRYPTION_ENABLED; + /*setup the encryption key */ + packet_header_setup_key(sss->federation->community, &(sss->federation->header_encryption_ctx), &(sss->federation->header_iv_ctx)); + sss->federation->edges = NULL; + } + + n2n_srand(n2n_seed()); + + /* Random auth token */ + sss->auth.scheme = n2n_auth_simple_id; + + for(idx = 0; idx < N2N_AUTH_TOKEN_SIZE; ++idx) { + sss->auth.token[idx] = n2n_rand() % 0xff; + } + + sss->auth.toksize = sizeof(sss->auth.token); + + /* Random MAC address */ + for(i = 0; i < 6; i++) { + sss->mac_addr[i] = n2n_rand(); + } + sss->mac_addr[0] &= ~0x01; /* Clear multicast bit */ + sss->mac_addr[0] |= 0x02; /* Set locally-assigned bit */ + + return 0; /* OK */ } /** Deinitialise the supernode structure and deallocate any memory owned by - * it. */ + * it. */ void sn_term (n2n_sn_t *sss) { - struct sn_community *community, *tmp; - struct sn_community_regular_expression *re, *tmp_re; + struct sn_community *community, *tmp; + struct sn_community_regular_expression *re, *tmp_re; - if(sss->sock >= 0) { - closesocket(sss->sock); - } - sss->sock = -1; + if(sss->sock >= 0) { + closesocket(sss->sock); + } + sss->sock = -1; - if(sss->mgmt_sock >= 0) { - closesocket(sss->mgmt_sock); - } - sss->mgmt_sock = -1; + if(sss->mgmt_sock >= 0) { + closesocket(sss->mgmt_sock); + } + sss->mgmt_sock = -1; - HASH_ITER(hh, sss->communities, community, tmp) { - clear_peer_list(&community->edges); - if(NULL != community->header_encryption_ctx) { - free(community->header_encryption_ctx); + HASH_ITER(hh, sss->communities, community, tmp) { + clear_peer_list(&community->edges); + if(NULL != community->header_encryption_ctx) { + free(community->header_encryption_ctx); + } + HASH_DEL(sss->communities, community); + free(community); } - HASH_DEL(sss->communities, community); - free(community); - } - - HASH_ITER(hh, sss->rules, re, tmp_re) { - HASH_DEL(sss->rules, re); - if (NULL != re->rule) { - free(re->rule); + + HASH_ITER(hh, sss->rules, re, tmp_re) { + HASH_DEL(sss->rules, re); + if (NULL != re->rule) { + free(re->rule); + } + free(re); } - free(re); - } #ifdef WIN32 - destroyWin32(); + destroyWin32(); #endif } /** Determine the appropriate lifetime for new registrations. * - * If the supernode has been put into a pre-shutdown phase then this lifetime - * should not allow registrations to continue beyond the shutdown point. + * If the supernode has been put into a pre-shutdown phase then this lifetime + * should not allow registrations to continue beyond the shutdown point. */ static uint16_t reg_lifetime (n2n_sn_t *sss) { - /* NOTE: UDP firewalls usually have a 30 seconds timeout */ - return 15; + /* NOTE: UDP firewalls usually have a 30 seconds timeout */ + return 15; } /** Compare two authentication tokens. It is called by update_edge - * and in UNREGISTER_SUPER handling to compare the stored auth token - * with the one received from the packet. - */ + * and in UNREGISTER_SUPER handling to compare the stored auth token + * with the one received from the packet. + */ static int auth_edge (const n2n_auth_t *auth1, const n2n_auth_t *auth2) { - /* 0 = success (tokens are equal). */ - return (memcmp(auth1, auth2, sizeof(n2n_auth_t))); + /* 0 = success (tokens are equal). */ + return (memcmp(auth1, auth2, sizeof(n2n_auth_t))); } /** Update the edge table with the details of the edge which contacted the - * supernode. */ + * supernode. */ static int update_edge (n2n_sn_t *sss, const n2n_REGISTER_SUPER_t* reg, struct sn_community *comm, @@ -375,92 +375,92 @@ static int update_edge (n2n_sn_t *sss, int skip_add, time_t now) { - macstr_t mac_buf; - n2n_sock_str_t sockbuf; - struct peer_info *scan, *iter, *tmp; - int auth; - int ret; - - traceEvent(TRACE_DEBUG, "update_edge for %s [%s]", - macaddr_str(mac_buf, reg->edgeMac), - sock_to_cstr(sockbuf, sender_sock)); - - HASH_FIND_PEER(comm->edges, reg->edgeMac, scan); - - // if unknown, make sure it is also not known by IP address - if(NULL == scan) { - HASH_ITER(hh,comm->edges,iter,tmp) { - if(iter->dev_addr.net_addr == reg->dev_addr.net_addr) { - scan = iter; - HASH_DEL(comm->edges, scan); - memcpy(&(scan->mac_addr), reg->edgeMac, sizeof(n2n_mac_t)); - HASH_ADD_PEER(comm->edges, scan); - break; - } - } - } - - if(NULL == scan) { - /* Not known */ - if(skip_add == SN_ADD) { - scan = (struct peer_info *) calloc(1, sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */ - memcpy(&(scan->mac_addr), reg->edgeMac, sizeof(n2n_mac_t)); - scan->dev_addr.net_addr = reg->dev_addr.net_addr; - scan->dev_addr.net_bitlen = reg->dev_addr.net_bitlen; - memcpy((char*)scan->dev_desc, reg->dev_desc, N2N_DESC_SIZE); - memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); - memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); - memcpy(&(scan->auth), &(reg->auth), sizeof(n2n_auth_t)); - scan->last_valid_time_stamp = initial_time_stamp(); - - HASH_ADD_PEER(comm->edges, scan); - - traceEvent(TRACE_INFO, "update_edge created %s ==> %s", - macaddr_str(mac_buf, reg->edgeMac), - sock_to_cstr(sockbuf, sender_sock)); + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + struct peer_info *scan, *iter, *tmp; + int auth; + int ret; + + traceEvent(TRACE_DEBUG, "update_edge for %s [%s]", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); + + HASH_FIND_PEER(comm->edges, reg->edgeMac, scan); + + // if unknown, make sure it is also not known by IP address + if(NULL == scan) { + HASH_ITER(hh,comm->edges,iter,tmp) { + if(iter->dev_addr.net_addr == reg->dev_addr.net_addr) { + scan = iter; + HASH_DEL(comm->edges, scan); + memcpy(&(scan->mac_addr), reg->edgeMac, sizeof(n2n_mac_t)); + HASH_ADD_PEER(comm->edges, scan); + break; + } + } } - ret = update_edge_new_sn; - } else { - /* Known */ - if(!sock_equal(sender_sock, &(scan->sock))) { - if((auth = auth_edge(&(scan->auth), &(reg->auth))) == 0) { - memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); - memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); - - traceEvent(TRACE_INFO, "update_edge updated %s ==> %s", - macaddr_str(mac_buf, reg->edgeMac), - sock_to_cstr(sockbuf, sender_sock)); - ret = update_edge_sock_change; - } else { - traceEvent(TRACE_INFO, "authentication failed"); - - ret = update_edge_auth_fail; - } + + if(NULL == scan) { + /* Not known */ + if(skip_add == SN_ADD) { + scan = (struct peer_info *) calloc(1, sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */ + memcpy(&(scan->mac_addr), reg->edgeMac, sizeof(n2n_mac_t)); + scan->dev_addr.net_addr = reg->dev_addr.net_addr; + scan->dev_addr.net_bitlen = reg->dev_addr.net_bitlen; + memcpy((char*)scan->dev_desc, reg->dev_desc, N2N_DESC_SIZE); + memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); + memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); + memcpy(&(scan->auth), &(reg->auth), sizeof(n2n_auth_t)); + scan->last_valid_time_stamp = initial_time_stamp(); + + HASH_ADD_PEER(comm->edges, scan); + + traceEvent(TRACE_INFO, "update_edge created %s ==> %s", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); + } + ret = update_edge_new_sn; } else { - memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); + /* Known */ + if(!sock_equal(sender_sock, &(scan->sock))) { + if((auth = auth_edge(&(scan->auth), &(reg->auth))) == 0) { + memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); + memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); + + traceEvent(TRACE_INFO, "update_edge updated %s ==> %s", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); + ret = update_edge_sock_change; + } else { + traceEvent(TRACE_INFO, "authentication failed"); + + ret = update_edge_auth_fail; + } + } else { + memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); - traceEvent(TRACE_DEBUG, "update_edge unchanged %s ==> %s", - macaddr_str(mac_buf, reg->edgeMac), - sock_to_cstr(sockbuf, sender_sock)); + traceEvent(TRACE_DEBUG, "update_edge unchanged %s ==> %s", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); - ret = update_edge_no_change; + ret = update_edge_no_change; + } } - } - if(scan != NULL) { - scan->last_seen = now; - } + if(scan != NULL) { + scan->last_seen = now; + } - return ret; + return ret; } static signed int peer_tap_ip_sort (struct peer_info *a, struct peer_info *b) { - uint32_t a_host_id = a->dev_addr.net_addr & (~bitlen2mask(a->dev_addr.net_bitlen)); - uint32_t b_host_id = b->dev_addr.net_addr & (~bitlen2mask(b->dev_addr.net_bitlen)); + uint32_t a_host_id = a->dev_addr.net_addr & (~bitlen2mask(a->dev_addr.net_bitlen)); + uint32_t b_host_id = b->dev_addr.net_addr & (~bitlen2mask(b->dev_addr.net_bitlen)); - return ((signed int)a_host_id - (signed int)b_host_id); + return ((signed int)a_host_id - (signed int)b_host_id); } @@ -468,37 +468,37 @@ static signed int peer_tap_ip_sort (struct peer_info *a, struct peer_info *b) { static int assign_one_ip_addr (struct sn_community *comm, n2n_ip_subnet_t *ipaddr) { - struct peer_info *peer, *tmpPeer; - uint32_t net_id, mask, max_host, host_id = 1; - dec_ip_bit_str_t ip_bit_str = {'\0'}; + struct peer_info *peer, *tmpPeer; + uint32_t net_id, mask, max_host, host_id = 1; + dec_ip_bit_str_t ip_bit_str = {'\0'}; - mask = bitlen2mask(comm->auto_ip_net.net_bitlen); - net_id = comm->auto_ip_net.net_addr & mask; - max_host = ~mask; + mask = bitlen2mask(comm->auto_ip_net.net_bitlen); + net_id = comm->auto_ip_net.net_addr & mask; + max_host = ~mask; - HASH_SORT(comm->edges, peer_tap_ip_sort); - HASH_ITER(hh, comm->edges, peer, tmpPeer) { - if((peer->dev_addr.net_addr & bitlen2mask(peer->dev_addr.net_bitlen)) == net_id) { - if(host_id >= max_host) { - traceEvent(TRACE_WARNING, "No assignable IP to edge tap adapter."); - return -1; - } - if(peer->dev_addr.net_addr == 0) { - continue; - } - if((peer->dev_addr.net_addr & max_host) == host_id) { - ++host_id; - } else { - break; - } + HASH_SORT(comm->edges, peer_tap_ip_sort); + HASH_ITER(hh, comm->edges, peer, tmpPeer) { + if((peer->dev_addr.net_addr & bitlen2mask(peer->dev_addr.net_bitlen)) == net_id) { + if(host_id >= max_host) { + traceEvent(TRACE_WARNING, "No assignable IP to edge tap adapter."); + return -1; + } + if(peer->dev_addr.net_addr == 0) { + continue; + } + if((peer->dev_addr.net_addr & max_host) == host_id) { + ++host_id; + } else { + break; + } + } } - } - ipaddr->net_addr = net_id | host_id; - ipaddr->net_bitlen = comm->auto_ip_net.net_bitlen; + ipaddr->net_addr = net_id | host_id; + ipaddr->net_bitlen = comm->auto_ip_net.net_bitlen; - traceEvent(TRACE_INFO, "Assign IP %s to tap adapter of edge.", ip_subnet_to_str(ip_bit_str, ipaddr)); + traceEvent(TRACE_INFO, "Assign IP %s to tap adapter of edge.", ip_subnet_to_str(ip_bit_str, ipaddr)); - return 0; + return 0; } @@ -508,24 +508,24 @@ int subnet_available (n2n_sn_t *sss, uint32_t net_id, uint32_t mask) { - struct sn_community *cmn, *tmpCmn; - int success = 1; + struct sn_community *cmn, *tmpCmn; + int success = 1; - HASH_ITER(hh, sss->communities, cmn, tmpCmn) { - if(cmn == comm) { - continue; - } - if(cmn->is_federation == IS_FEDERATION) { - continue; - } - if((net_id <= (cmn->auto_ip_net.net_addr + ~bitlen2mask(cmn->auto_ip_net.net_bitlen))) - &&(net_id + ~mask >= cmn->auto_ip_net.net_addr)) { - success = 0; - break; + HASH_ITER(hh, sss->communities, cmn, tmpCmn) { + if(cmn == comm) { + continue; + } + if(cmn->is_federation == IS_FEDERATION) { + continue; + } + if((net_id <= (cmn->auto_ip_net.net_addr + ~bitlen2mask(cmn->auto_ip_net.net_bitlen))) + &&(net_id + ~mask >= cmn->auto_ip_net.net_addr)) { + success = 0; + break; + } } - } - return success; + return success; } @@ -533,55 +533,55 @@ int subnet_available (n2n_sn_t *sss, int assign_one_ip_subnet (n2n_sn_t *sss, struct sn_community *comm) { - uint32_t net_id, net_id_i, mask, net_increment; - uint32_t no_subnets; - uint8_t success; - in_addr_t net; - - mask = bitlen2mask(sss->min_auto_ip_net.net_bitlen); - // number of possible sub-networks - no_subnets = (sss->max_auto_ip_net.net_addr - sss->min_auto_ip_net.net_addr); - no_subnets >>= (32 - sss->min_auto_ip_net.net_bitlen); - no_subnets += 1; - - // proposal for sub-network to choose - net_id = pearson_hash_32((const uint8_t *)comm->community, N2N_COMMUNITY_SIZE) % no_subnets; - net_id = sss->min_auto_ip_net.net_addr + (net_id << (32 - sss->min_auto_ip_net.net_bitlen)); - - // check for availability starting from net_id, then downwards, ... - net_increment = (~mask+1); - for(net_id_i = net_id; net_id_i >= sss->min_auto_ip_net.net_addr; net_id_i -= net_increment) { - success = subnet_available(sss, comm, net_id_i, mask); - if(success) { - break; + uint32_t net_id, net_id_i, mask, net_increment; + uint32_t no_subnets; + uint8_t success; + in_addr_t net; + + mask = bitlen2mask(sss->min_auto_ip_net.net_bitlen); + // number of possible sub-networks + no_subnets = (sss->max_auto_ip_net.net_addr - sss->min_auto_ip_net.net_addr); + no_subnets >>= (32 - sss->min_auto_ip_net.net_bitlen); + no_subnets += 1; + + // proposal for sub-network to choose + net_id = pearson_hash_32((const uint8_t *)comm->community, N2N_COMMUNITY_SIZE) % no_subnets; + net_id = sss->min_auto_ip_net.net_addr + (net_id << (32 - sss->min_auto_ip_net.net_bitlen)); + + // check for availability starting from net_id, then downwards, ... + net_increment = (~mask+1); + for(net_id_i = net_id; net_id_i >= sss->min_auto_ip_net.net_addr; net_id_i -= net_increment) { + success = subnet_available(sss, comm, net_id_i, mask); + if(success) { + break; + } + } + // ... then upwards + if(!success) { + for(net_id_i = net_id + net_increment; net_id_i <= sss->max_auto_ip_net.net_addr; net_id_i += net_increment) { + success = subnet_available(sss, comm, net_id_i, mask); + if(success) { + break; + } + } } - } - // ... then upwards - if(!success) { - for(net_id_i = net_id + net_increment; net_id_i <= sss->max_auto_ip_net.net_addr; net_id_i += net_increment) { - success = subnet_available(sss, comm, net_id_i, mask); - if(success) { - break; - } + + if(success) { + comm->auto_ip_net.net_addr = net_id_i; + comm->auto_ip_net.net_bitlen = sss->min_auto_ip_net.net_bitlen; + net = htonl(comm->auto_ip_net.net_addr); + traceEvent(TRACE_INFO, "Assigned sub-network %s/%u to community '%s'.", + inet_ntoa(*(struct in_addr *) &net), + comm->auto_ip_net.net_bitlen, + comm->community); + return 0; + } else { + comm->auto_ip_net.net_addr = 0; + comm->auto_ip_net.net_bitlen = 0; + traceEvent(TRACE_WARNING, "No assignable sub-network left for community '%s'.", + comm->community); + return -1; } - } - - if(success) { - comm->auto_ip_net.net_addr = net_id_i; - comm->auto_ip_net.net_bitlen = sss->min_auto_ip_net.net_bitlen; - net = htonl(comm->auto_ip_net.net_addr); - traceEvent(TRACE_INFO, "Assigned sub-network %s/%u to community '%s'.", - inet_ntoa(*(struct in_addr *) &net), - comm->auto_ip_net.net_bitlen, - comm->community); - return 0; - } else { - comm->auto_ip_net.net_addr = 0; - comm->auto_ip_net.net_bitlen = 0; - traceEvent(TRACE_WARNING, "No assignable sub-network left for community '%s'.", - comm->community); - return -1; - } } @@ -594,155 +594,155 @@ static int find_edge_time_stamp_and_verify (struct peer_info * edges, int from_supernode, n2n_mac_t mac, uint64_t stamp, int allow_jitter) { - uint64_t * previous_stamp = NULL; + uint64_t * previous_stamp = NULL; - if(!from_supernode) { - struct peer_info *edge; - HASH_FIND_PEER(edges, mac, edge); - if(edge) { - // time_stamp_verify_and_update allows the pointer a previous stamp to be NULL - // if it is a (so far) unknown edge - previous_stamp = &(edge->last_valid_time_stamp); + if(!from_supernode) { + struct peer_info *edge; + HASH_FIND_PEER(edges, mac, edge); + if(edge) { + // time_stamp_verify_and_update allows the pointer a previous stamp to be NULL + // if it is a (so far) unknown edge + previous_stamp = &(edge->last_valid_time_stamp); + } } - } - // failure --> 0; success --> 1 - return (time_stamp_verify_and_update(stamp, previous_stamp, allow_jitter)); + // failure --> 0; success --> 1 + return (time_stamp_verify_and_update(stamp, previous_stamp, allow_jitter)); } static int re_register_and_purge_supernodes (n2n_sn_t *sss, struct sn_community *comm, time_t *p_last_re_reg_and_purge, time_t now) { - time_t time; - struct peer_info *peer, *tmp; + time_t time; + struct peer_info *peer, *tmp; - if((now - (*p_last_re_reg_and_purge)) < RE_REG_AND_PURGE_FREQUENCY) { - return 0; - } - - if(comm != NULL) { - HASH_ITER(hh,comm->edges,peer,tmp) { - time = now - peer->last_seen; - if(time <= LAST_SEEN_SN_ACTIVE) { - continue; - } - - if((time < LAST_SEEN_SN_INACTIVE) - || (peer->purgeable == SN_UNPURGEABLE)) { - /* re-regitser (send REGISTER_SUPER) */ - uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; - size_t idx; - /* ssize_t sent; */ - n2n_common_t cmn; - n2n_cookie_t cookie; - n2n_REGISTER_SUPER_t reg; - n2n_sock_str_t sockbuf; - - memset(&cmn, 0, sizeof(cmn)); - memset(®, 0, sizeof(reg)); - - cmn.ttl = N2N_DEFAULT_TTL; - cmn.pc = n2n_register_super; - cmn.flags = N2N_FLAGS_FROM_SUPERNODE; - memcpy(cmn.community, comm->community, N2N_COMMUNITY_SIZE); - - for(idx = 0; idx < N2N_COOKIE_SIZE; ++idx) { - cookie[idx] = n2n_rand() % 0xff; - } + if((now - (*p_last_re_reg_and_purge)) < RE_REG_AND_PURGE_FREQUENCY) { + return 0; + } + + if(comm != NULL) { + HASH_ITER(hh,comm->edges,peer,tmp) { + time = now - peer->last_seen; + if(time <= LAST_SEEN_SN_ACTIVE) { + continue; + } + + if((time < LAST_SEEN_SN_INACTIVE) + || (peer->purgeable == SN_UNPURGEABLE)) { + /* re-regitser (send REGISTER_SUPER) */ + uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_cookie_t cookie; + n2n_REGISTER_SUPER_t reg; + n2n_sock_str_t sockbuf; + + memset(&cmn, 0, sizeof(cmn)); + memset(®, 0, sizeof(reg)); - memcpy(reg.cookie, cookie, N2N_COOKIE_SIZE); - reg.dev_addr.net_addr = ntohl(peer->dev_addr.net_addr); - reg.dev_addr.net_bitlen = mask2bitlen(ntohl(peer->dev_addr.net_bitlen)); - memcpy(&(reg.auth), &(sss->auth), sizeof(n2n_auth_t)); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_register_super; + cmn.flags = N2N_FLAGS_FROM_SUPERNODE; + memcpy(cmn.community, comm->community, N2N_COMMUNITY_SIZE); - idx = 0; - encode_mac(reg.edgeMac, &idx, sss->mac_addr); + for(idx = 0; idx < N2N_COOKIE_SIZE; ++idx) { + cookie[idx] = n2n_rand() % 0xff; + } - idx = 0; - encode_REGISTER_SUPER(pktbuf, &idx, &cmn, ®); + memcpy(reg.cookie, cookie, N2N_COOKIE_SIZE); + reg.dev_addr.net_addr = ntohl(peer->dev_addr.net_addr); + reg.dev_addr.net_bitlen = mask2bitlen(ntohl(peer->dev_addr.net_bitlen)); + memcpy(&(reg.auth), &(sss->auth), sizeof(n2n_auth_t)); - traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s", - sock_to_cstr(sockbuf, &(peer->sock))); + idx = 0; + encode_mac(reg.edgeMac, &idx, sss->mac_addr); - packet_header_encrypt(pktbuf, idx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(pktbuf, idx)); + idx = 0; + encode_REGISTER_SUPER(pktbuf, &idx, &cmn, ®); - /* sent = */ sendto_sock(sss, &(peer->sock), pktbuf, idx); - } - if(time >= LAST_SEEN_SN_INACTIVE) { - purge_expired_registrations(&(comm->edges), &time, LAST_SEEN_SN_INACTIVE); /* purge not-seen-long-time supernodes*/ - } + traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s", + sock_to_cstr(sockbuf, &(peer->sock))); + + packet_header_encrypt(pktbuf, idx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(pktbuf, idx)); + + /* sent = */ sendto_sock(sss, &(peer->sock), pktbuf, idx); + } + if(time >= LAST_SEEN_SN_INACTIVE) { + purge_expired_registrations(&(comm->edges), &time, LAST_SEEN_SN_INACTIVE); /* purge not-seen-long-time supernodes*/ + } + } } - } - (*p_last_re_reg_and_purge) = now; + (*p_last_re_reg_and_purge) = now; - return 0; /* OK */ + return 0; /* OK */ } static int purge_expired_communities (n2n_sn_t *sss, time_t* p_last_purge, time_t now) { - struct sn_community *comm, *tmp; - size_t num_reg = 0; + struct sn_community *comm, *tmp; + size_t num_reg = 0; - if((now - (*p_last_purge)) < PURGE_REGISTRATION_FREQUENCY) { - return 0; - } - - traceEvent(TRACE_DEBUG, "Purging old communities and edges"); - - HASH_ITER(hh, sss->communities, comm, tmp) { - num_reg += purge_peer_list(&comm->edges, now - REGISTRATION_TIMEOUT); - if((comm->edges == NULL) && (comm->purgeable == COMMUNITY_PURGEABLE)) { - traceEvent(TRACE_INFO, "Purging idle community %s", comm->community); - if(NULL != comm->header_encryption_ctx) { - /* this should not happen as 'purgeable' and thus only communities w/o encrypted header here */ - free(comm->header_encryption_ctx); - } - HASH_DEL(sss->communities, comm); - free(comm); + if((now - (*p_last_purge)) < PURGE_REGISTRATION_FREQUENCY) { + return 0; } - } - (*p_last_purge) = now; - traceEvent(TRACE_DEBUG, "Remove %ld edges", num_reg); + traceEvent(TRACE_DEBUG, "Purging old communities and edges"); - return 0; + HASH_ITER(hh, sss->communities, comm, tmp) { + num_reg += purge_peer_list(&comm->edges, now - REGISTRATION_TIMEOUT); + if((comm->edges == NULL) && (comm->purgeable == COMMUNITY_PURGEABLE)) { + traceEvent(TRACE_INFO, "Purging idle community %s", comm->community); + if(NULL != comm->header_encryption_ctx) { + /* this should not happen as 'purgeable' and thus only communities w/o encrypted header here */ + free(comm->header_encryption_ctx); + } + HASH_DEL(sss->communities, comm); + free(comm); + } + } + (*p_last_purge) = now; + + traceEvent(TRACE_DEBUG, "Remove %ld edges", num_reg); + + return 0; } static int number_enc_packets_sort (struct sn_community *a, struct sn_community *b) { - // comparison function for sorting communities in descending order of their - // number_enc_packets-fields - return (b->number_enc_packets - a->number_enc_packets); + // comparison function for sorting communities in descending order of their + // number_enc_packets-fields + return (b->number_enc_packets - a->number_enc_packets); } static int sort_communities (n2n_sn_t *sss, time_t* p_last_sort, time_t now) { - struct sn_community *comm, *tmp; + struct sn_community *comm, *tmp; - if((now - (*p_last_sort)) < SORT_COMMUNITIES_INTERVAL) { - return 0; - } + if((now - (*p_last_sort)) < SORT_COMMUNITIES_INTERVAL) { + return 0; + } - // this routine gets periodically called as defined in SORT_COMMUNITIES_INTERVAL - // it sorts the communities in descending order of their number_enc_packets-fields... - HASH_SORT(sss->communities, number_enc_packets_sort); + // this routine gets periodically called as defined in SORT_COMMUNITIES_INTERVAL + // it sorts the communities in descending order of their number_enc_packets-fields... + HASH_SORT(sss->communities, number_enc_packets_sort); - // ... and afterward resets the number_enc__packets-fields to zero - // (other models could reset it to half of their value to respect history) - HASH_ITER(hh, sss->communities, comm, tmp) { - comm->number_enc_packets = 0; - } + // ... and afterward resets the number_enc__packets-fields to zero + // (other models could reset it to half of their value to respect history) + HASH_ITER(hh, sss->communities, comm, tmp) { + comm->number_enc_packets = 0; + } - (*p_last_sort) = now; + (*p_last_sort) = now; - return 0; + return 0; } @@ -752,87 +752,87 @@ static int process_mgmt (n2n_sn_t *sss, size_t mgmt_size, time_t now) { - char resbuf[N2N_SN_PKTBUF_SIZE]; - size_t ressize = 0; - uint32_t num_edges = 0; - uint32_t num = 0; - struct sn_community *community, *tmp; - struct peer_info *peer, *tmpPeer; - macstr_t mac_buf; - n2n_sock_str_t sockbuf; - dec_ip_bit_str_t ip_bit_str = {'\0'}; - - traceEvent(TRACE_DEBUG, "process_mgmt"); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - " id tun_tap MAC edge hint last_seen\n"); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "-------------------------------------------------------------------------------------------------\n"); - HASH_ITER(hh, sss->communities, community, tmp) { - num_edges += HASH_COUNT(community->edges); + char resbuf[N2N_SN_PKTBUF_SIZE]; + size_t ressize = 0; + uint32_t num_edges = 0; + uint32_t num = 0; + struct sn_community *community, *tmp; + struct peer_info *peer, *tmpPeer; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + dec_ip_bit_str_t ip_bit_str = {'\0'}; + + traceEvent(TRACE_DEBUG, "process_mgmt"); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "community: %s\n", community->community); - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - ressize = 0; - - num = 0; - HASH_ITER(hh, community->edges, peer, tmpPeer) { - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - " %-4u %-18s %-17s %-21s %-15s %lu\n", - ++num, ip_subnet_to_str(ip_bit_str, &peer->dev_addr), - macaddr_str(mac_buf, peer->mac_addr), - sock_to_cstr(sockbuf, &(peer->sock)), - peer->dev_desc, - now - peer->last_seen); - - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - ressize = 0; + " id tun_tap MAC edge hint last_seen\n"); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "-------------------------------------------------------------------------------------------------\n"); + HASH_ITER(hh, sss->communities, community, tmp) { + num_edges += HASH_COUNT(community->edges); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "community: %s\n", community->community); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + ressize = 0; + + num = 0; + HASH_ITER(hh, community->edges, peer, tmpPeer) { + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + " %-4u %-18s %-17s %-21s %-15s %lu\n", + ++num, ip_subnet_to_str(ip_bit_str, &peer->dev_addr), + macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + peer->dev_desc, + now - peer->last_seen); + + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + ressize = 0; + } } - } - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "----------------------------------------------------------------------------------------------------\n"); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "----------------------------------------------------------------------------------------------------\n"); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "uptime %lu | ", (now - sss->start_time)); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "uptime %lu | ", (now - sss->start_time)); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "edges %u | ", - num_edges); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "edges %u | ", + num_edges); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "reg_sup %u | ", - (unsigned int) sss->stats.reg_super); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "reg_sup %u | ", + (unsigned int) sss->stats.reg_super); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "reg_nak %u | ", - (unsigned int) sss->stats.reg_super_nak); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "reg_nak %u | ", + (unsigned int) sss->stats.reg_super_nak); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "errors %u \n", - (unsigned int) sss->stats.errors); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "errors %u \n", + (unsigned int) sss->stats.errors); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "fwd %u | ", - (unsigned int) sss->stats.fwd); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "fwd %u | ", + (unsigned int) sss->stats.fwd); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "broadcast %u | ", - (unsigned int) sss->stats.broadcast); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "broadcast %u | ", + (unsigned int) sss->stats.broadcast); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "cur_cmnts %u\n", HASH_COUNT(sss->communities)); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "cur_cmnts %u\n", HASH_COUNT(sss->communities)); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "last_fwd %lu sec ago | ", - (long unsigned int) (now - sss->stats.last_fwd)); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "last_fwd %lu sec ago | ", + (long unsigned int) (now - sss->stats.last_fwd)); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "last reg %lu sec ago\n\n", - (long unsigned int) (now - sss->stats.last_reg_super)); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "last reg %lu sec ago\n\n", + (long unsigned int) (now - sss->stats.last_reg_super)); - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - return 0; + return 0; } @@ -840,17 +840,17 @@ static int sendto_mgmt (n2n_sn_t *sss, const struct sockaddr_in *sender_sock, const uint8_t *mgmt_buf, size_t mgmt_size) { + + ssize_t r = sendto(sss->mgmt_sock, mgmt_buf, mgmt_size, 0 /*flags*/, + (struct sockaddr *)sender_sock, sizeof (struct sockaddr_in)); - ssize_t r = sendto(sss->mgmt_sock, mgmt_buf, mgmt_size, 0 /*flags*/, - (struct sockaddr *)sender_sock, sizeof (struct sockaddr_in)); - - if(r <= 0) { - ++(sss->stats.errors); - traceEvent (TRACE_ERROR, "sendto_mgmt : sendto failed. %s", strerror (errno)); - return -1; - } + if(r <= 0) { + ++(sss->stats.errors); + traceEvent (TRACE_ERROR, "sendto_mgmt : sendto failed. %s", strerror (errno)); + return -1; + } - return 0; + return 0; } /** Examine a datagram and determine what to do with it. @@ -862,907 +862,907 @@ static int process_udp (n2n_sn_t * sss, size_t udp_size, time_t now) { - n2n_common_t cmn; /* common fields in the packet header */ - size_t rem; - size_t idx; - size_t msg_type; - uint8_t from_supernode; - macstr_t mac_buf; - macstr_t mac_buf2; - n2n_sock_str_t sockbuf; - char buf[32]; - struct sn_community *comm, *tmp; - uint64_t stamp; - const n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0}; /* 00:00:00:00:00:00 */ - - traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]", - udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)), - ntohs(sender_sock->sin_port)); - - /* check if header is unenrypted. the following check is around 99.99962 percent reliable. - * it heavily relies on the structure of packet's common part - * changes to wire.c:encode/decode_common need to go together with this code */ - if(udp_size < 20) { - traceEvent(TRACE_DEBUG, "process_udp dropped a packet too short to be valid."); - return -1; - } - if((udp_buf[19] == (uint8_t)0x00) // null terminated community name - && (udp_buf[00] == N2N_PKT_VERSION) // correct packet version - && ((be16toh (*(uint16_t*)&(udp_buf[02])) & N2N_FLAGS_TYPE_MASK ) <= MSG_TYPE_MAX_TYPE ) // message type - && ( be16toh (*(uint16_t*)&(udp_buf[02])) < N2N_FLAGS_OPTIONS) // flags - ) { - /* most probably unencrypted */ - /* make sure, no downgrading happens here and no unencrypted packets can be - * injected in a community which definitely deals with encrypted headers */ - HASH_FIND_COMMUNITY(sss->communities, (char *)&udp_buf[04], comm); - if(comm) { - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - traceEvent(TRACE_DEBUG, "process_udp dropped a packet with unencrypted header " - "addressed to community '%s' which uses encrypted headers.", - comm->community); + n2n_common_t cmn; /* common fields in the packet header */ + size_t rem; + size_t idx; + size_t msg_type; + uint8_t from_supernode; + macstr_t mac_buf; + macstr_t mac_buf2; + n2n_sock_str_t sockbuf; + char buf[32]; + struct sn_community *comm, *tmp; + uint64_t stamp; + const n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0}; /* 00:00:00:00:00:00 */ + + traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]", + udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)), + ntohs(sender_sock->sin_port)); + + /* check if header is unencrypted. the following check is around 99.99962 percent reliable. + * it heavily relies on the structure of packet's common part + * changes to wire.c:encode/decode_common need to go together with this code */ + if(udp_size < 20) { + traceEvent(TRACE_DEBUG, "process_udp dropped a packet too short to be valid."); return -1; - } - if(comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) { - traceEvent(TRACE_INFO, "process_udp locked community '%s' to using " - "unencrypted headers.", comm->community); - /* set 'no encryption' in case it is not set yet */ - comm->header_encryption = HEADER_ENCRYPTION_NONE; - comm->header_encryption_ctx = NULL; - } } - } else { - /* most probably encrypted */ - /* cycle through the known communities (as keys) to eventually decrypt */ - uint32_t ret = 0; - HASH_ITER(hh, sss->communities, comm, tmp) { - /* skip the definitely unencrypted communities */ - if(comm->header_encryption == HEADER_ENCRYPTION_NONE) { - continue; - } - uint16_t checksum = 0; - if((ret = packet_header_decrypt(udp_buf, udp_size, comm->community, comm->header_encryption_ctx, - comm->header_iv_ctx, - &stamp, &checksum))) { - // time stamp verification follows in the packet specific section as it requires to determine the - // sender from the hash list by its MAC, this all depends on packet type and packet structure - // (MAC is not always in the same place) - if(checksum != pearson_hash_16(udp_buf, udp_size)) { - traceEvent(TRACE_DEBUG, "process_udp dropped packet due to checksum error."); - return -1; + if((udp_buf[19] == (uint8_t)0x00) // null terminated community name + && (udp_buf[00] == N2N_PKT_VERSION) // correct packet version + && ((be16toh(*(uint16_t*)&(udp_buf[02])) & N2N_FLAGS_TYPE_MASK) <= MSG_TYPE_MAX_TYPE) // message type + && ( be16toh(*(uint16_t*)&(udp_buf[02])) < N2N_FLAGS_OPTIONS) // flags + ) { + /* most probably unencrypted */ + /* make sure, no downgrading happens here and no unencrypted packets can be + * injected in a community which definitely deals with encrypted headers */ + HASH_FIND_COMMUNITY(sss->communities, (char *)&udp_buf[04], comm); + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + traceEvent(TRACE_DEBUG, "process_udp dropped a packet with unencrypted header " + "addressed to community '%s' which uses encrypted headers.", + comm->community); + return -1; + } + if(comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) { + traceEvent(TRACE_INFO, "process_udp locked community '%s' to using " + "unencrypted headers.", comm->community); + /* set 'no encryption' in case it is not set yet */ + comm->header_encryption = HEADER_ENCRYPTION_NONE; + comm->header_encryption_ctx = NULL; + } + } + } else { + /* most probably encrypted */ + /* cycle through the known communities (as keys) to eventually decrypt */ + uint32_t ret = 0; + HASH_ITER(hh, sss->communities, comm, tmp) { + /* skip the definitely unencrypted communities */ + if(comm->header_encryption == HEADER_ENCRYPTION_NONE) { + continue; + } + uint16_t checksum = 0; + if((ret = packet_header_decrypt(udp_buf, udp_size, comm->community, comm->header_encryption_ctx, + comm->header_iv_ctx, + &stamp, &checksum))) { + // time stamp verification follows in the packet specific section as it requires to determine the + // sender from the hash list by its MAC, this all depends on packet type and packet structure + // (MAC is not always in the same place) + if(checksum != pearson_hash_16(udp_buf, udp_size)) { + traceEvent(TRACE_DEBUG, "process_udp dropped packet due to checksum error."); + return -1; + } + if(comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) { + traceEvent(TRACE_INFO, "process_udp locked community '%s' to using " + "encrypted headers.", comm->community); + /* set 'encrypted' in case it is not set yet */ + comm->header_encryption = HEADER_ENCRYPTION_ENABLED; + } + // count the number of encrypted packets for sorting the communities from time to time + // for the HASH_ITER a few lines above gets faster for the more busy communities + (comm->number_enc_packets)++; + // no need to test further communities + break; + } } - if(comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) { - traceEvent(TRACE_INFO, "process_udp locked community '%s' to using " - "encrypted headers.", comm->community); - /* set 'encrypted' in case it is not set yet */ - comm->header_encryption = HEADER_ENCRYPTION_ENABLED; + if(!ret) { + // no matching key/community + traceEvent(TRACE_DEBUG, "process_udp dropped a packet with seemingly encrypted header " + "for which no matching community which uses encrypted headers was found."); + return -1; } - // count the number of encrypted packets for sorting the communities from time to time - // for the HASH_ITER a few lines above gets faster for the more busy communities - (comm->number_enc_packets)++; - // no need to test further communities - break; - } } - if(!ret) { - // no matching key/community - traceEvent(TRACE_DEBUG, "process_udp dropped a packet with seemingly encrypted header " - "for which no matching community which uses encrypted headers was found."); - return -1; + + /* Use decode_common() to determine the kind of packet then process it: + * + * REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK + * + * REGISTER, REGISTER_ACK and PACKET messages are forwarded to their + * destination edge. If the destination is not known then PACKETs are + * broadcast. + */ + + rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */ + idx = 0; /* marches through packet header as parts are decoded. */ + if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) { + traceEvent(TRACE_ERROR, "Failed to decode common section"); + return -1; /* failed to decode packet */ } - } - - /* Use decode_common() to determine the kind of packet then process it: - * - * REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK - * - * REGISTER, REGISTER_ACK and PACKET messages are forwarded to their - * destination edge. If the destination is not known then PACKETs are - * broadcast. - */ - - rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */ - idx = 0; /* marches through packet header as parts are decoded. */ - if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) { - traceEvent(TRACE_ERROR, "Failed to decode common section"); - return -1; /* failed to decode packet */ - } - - msg_type = cmn.pc; /* packet code */ - from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE; - - if(cmn.ttl < 1) { - traceEvent(TRACE_WARNING, "Expired TTL"); - return 0; /* Don't process further */ - } - - --(cmn.ttl); /* The value copied into all forwarded packets. */ - - switch(msg_type) { - case MSG_TYPE_PACKET: { - /* PACKET from one edge to another edge via supernode. */ - - /* pkt will be modified in place and recoded to an output of potentially - * different size due to addition of the socket.*/ - n2n_PACKET_t pkt; - n2n_common_t cmn2; - uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; - size_t encx = 0; - int unicast; /* non-zero if unicast */ - uint8_t * rec_buf; /* either udp_buf or encbuf */ - - if(!comm) { - traceEvent(TRACE_DEBUG, "process_udp PACKET with unknown community %s", cmn.community); - return -1; - } - sss->stats.last_fwd=now; - decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); + msg_type = cmn.pc; /* packet code */ + from_supernode = cmn.flags & N2N_FLAGS_FROM_SUPERNODE; - // already checked for valid comm - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, pkt.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) { - traceEvent(TRACE_DEBUG, "process_udp dropped PACKET due to time stamp error."); - return -1; - } - } + if(cmn.ttl < 1) { + traceEvent(TRACE_WARNING, "Expired TTL"); + return 0; /* Don't process further */ + } - unicast = (0 == is_multi_broadcast(pkt.dstMac)); + --(cmn.ttl); /* The value copied into all forwarded packets. */ - traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s", - (unicast ? "unicast" : "multicast"), - macaddr_str(mac_buf, pkt.srcMac), - macaddr_str(mac_buf2, pkt.dstMac), - (from_supernode ? "from sn" : "local")); + switch(msg_type) { + case MSG_TYPE_PACKET: { + /* PACKET from one edge to another edge via supernode. */ - if(!from_supernode) { - memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); + /* pkt will be modified in place and recoded to an output of potentially + * different size due to addition of the socket.*/ + n2n_PACKET_t pkt; + n2n_common_t cmn2; + uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx = 0; + int unicast; /* non-zero if unicast */ + uint8_t * rec_buf; /* either udp_buf or encbuf */ - /* We are going to add socket even if it was not there before */ - cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + if(!comm) { + traceEvent(TRACE_DEBUG, "process_udp PACKET with unknown community %s", cmn.community); + return -1; + } - pkt.sock.family = AF_INET; - pkt.sock.port = ntohs(sender_sock->sin_port); - memcpy(pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + sss->stats.last_fwd = now; + decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); - rec_buf = encbuf; - /* Re-encode the header. */ - encode_PACKET(encbuf, &encx, &cmn2, &pkt); - uint16_t oldEncx = encx; + // already checked for valid comm + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, from_supernode, pkt.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped PACKET due to time stamp error."); + return -1; + } + } - /* Copy the original payload unchanged */ - encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx)); + unicast = (0 == is_multi_broadcast(pkt.dstMac)); - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(rec_buf, oldEncx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(rec_buf, encx)); - } - } else { - /* Already from a supernode. Nothing to modify, just pass to - * destination. */ + traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s", + (unicast ? "unicast" : "multicast"), + macaddr_str(mac_buf, pkt.srcMac), + macaddr_str(mac_buf2, pkt.dstMac), + (from_supernode ? "from sn" : "local")); - traceEvent(TRACE_DEBUG, "Rx PACKET fwd unmodified"); + if(!from_supernode) { + memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); - rec_buf = udp_buf; - encx = udp_size; + /* We are going to add socket even if it was not there before */ + cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(rec_buf, idx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(rec_buf, udp_size)); - } - } - - /* Common section to forward the final product. */ - if(unicast) { - try_forward(sss, comm, &cmn, pkt.dstMac, from_supernode, rec_buf, encx); - } else { - try_broadcast(sss, comm, &cmn, pkt.srcMac, from_supernode, rec_buf, encx); - } - break; - } + pkt.sock.family = AF_INET; + pkt.sock.port = ntohs(sender_sock->sin_port); + memcpy(pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); - case MSG_TYPE_REGISTER: { - /* Forwarding a REGISTER from one edge to the next */ + rec_buf = encbuf; + /* Re-encode the header. */ + encode_PACKET(encbuf, &encx, &cmn2, &pkt); + uint16_t oldEncx = encx; - n2n_REGISTER_t reg; - n2n_common_t cmn2; - uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; - size_t encx = 0; - int unicast; /* non-zero if unicast */ - uint8_t * rec_buf; /* either udp_buf or encbuf */ + /* Copy the original payload unchanged */ + encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx)); - if(!comm) { - traceEvent(TRACE_DEBUG, "process_udp REGISTER from unknown community %s", cmn.community); - return -1; - } + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(rec_buf, oldEncx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(rec_buf, encx)); + } + } else { + /* Already from a supernode. Nothing to modify, just pass to + * destination. */ - sss->stats.last_fwd=now; - decode_REGISTER(®, &cmn, udp_buf, &rem, &idx); + traceEvent(TRACE_DEBUG, "Rx PACKET fwd unmodified"); - // already checked for valid comm - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_edge_time_stamp_and_verify(comm->edges, from_supernode, reg.srcMac, stamp, TIME_STAMP_NO_JITTER)) { - traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER due to time stamp error."); - return -1; - } - } + rec_buf = udp_buf; + encx = udp_size; - unicast = (0 == is_multi_broadcast(reg.dstMac)); + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(rec_buf, idx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(rec_buf, udp_size)); + } + } - if(unicast) { - traceEvent(TRACE_DEBUG, "Rx REGISTER %s -> %s %s", - macaddr_str(mac_buf, reg.srcMac), - macaddr_str(mac_buf2, reg.dstMac), - ((cmn.flags & N2N_FLAGS_FROM_SUPERNODE) ? "from sn" : "local")); + /* Common section to forward the final product. */ + if(unicast) { + try_forward(sss, comm, &cmn, pkt.dstMac, from_supernode, rec_buf, encx); + } else { + try_broadcast(sss, comm, &cmn, pkt.srcMac, from_supernode, rec_buf, encx); + } + break; + } - if(0 == (cmn.flags & N2N_FLAGS_FROM_SUPERNODE)) { - memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); + case MSG_TYPE_REGISTER: { + /* Forwarding a REGISTER from one edge to the next */ - /* We are going to add socket even if it was not there before */ - cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + n2n_REGISTER_t reg; + n2n_common_t cmn2; + uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx = 0; + int unicast; /* non-zero if unicast */ + uint8_t * rec_buf; /* either udp_buf or encbuf */ - reg.sock.family = AF_INET; - reg.sock.port = ntohs(sender_sock->sin_port); - memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + if(!comm) { + traceEvent(TRACE_DEBUG, "process_udp REGISTER from unknown community %s", cmn.community); + return -1; + } - /* Re-encode the header. */ - encode_REGISTER(encbuf, &encx, &cmn2, ®); + sss->stats.last_fwd = now; + decode_REGISTER(®, &cmn, udp_buf, &rem, &idx); - rec_buf = encbuf; - } else { - /* Already from a supernode. Nothing to modify, just pass to - * destination. */ + // already checked for valid comm + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, from_supernode, reg.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER due to time stamp error."); + return -1; + } + } - rec_buf = udp_buf; - encx = udp_size; - } + unicast = (0 == is_multi_broadcast(reg.dstMac)); - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(rec_buf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(rec_buf, encx)); - } - try_forward(sss, comm, &cmn, reg.dstMac, from_supernode, rec_buf, encx); /* unicast only */ - } else { - traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination"); - } - break; - } + if(unicast) { + traceEvent(TRACE_DEBUG, "Rx REGISTER %s -> %s %s", + macaddr_str(mac_buf, reg.srcMac), + macaddr_str(mac_buf2, reg.dstMac), + ((cmn.flags & N2N_FLAGS_FROM_SUPERNODE) ? "from sn" : "local")); - case MSG_TYPE_REGISTER_ACK: { - traceEvent(TRACE_DEBUG, "Rx REGISTER_ACK (NOT IMPLEMENTED) Should not be via supernode"); - break; - } + if(0 == (cmn.flags & N2N_FLAGS_FROM_SUPERNODE)) { + memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); - case MSG_TYPE_REGISTER_SUPER: { - n2n_REGISTER_SUPER_t reg; - n2n_REGISTER_SUPER_ACK_t ack; - n2n_REGISTER_SUPER_NAK_t nak; - n2n_common_t cmn2; - uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; - uint8_t tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; - uint8_t *tmp_dst; - uint8_t payload_buf[REG_SUPER_ACK_PAYLOAD_SPACE]; - n2n_REGISTER_SUPER_ACK_payload_t *payload; - size_t encx = 0; - struct sn_community *fed; - struct sn_community_regular_expression *re, *tmp_re; - struct peer_info *peer, *tmp_peer, *p; - int8_t allowed_match = -1; - uint8_t match = 0; - int match_length = 0; - n2n_ip_subnet_t ipaddr; - int num = 0; - int skip_add; - int skip; - int ret_value; - - memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); - memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); - - /* Edge/supernode requesting registration with us. */ - sss->stats.last_reg_super=now; - ++(sss->stats.reg_super); - decode_REGISTER_SUPER(®, &cmn, udp_buf, &rem, &idx); - - if(comm) { - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_edge_time_stamp_and_verify(comm->edges, from_supernode, reg.edgeMac, stamp, TIME_STAMP_NO_JITTER)) { - traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER due to time stamp error."); - return -1; - } - } - } - - /* - Before we move any further, we need to check if the requested - community is allowed by the supernode. In case it is not we do - not report any message back to the edge to hide the supernode - existance (better from the security standpoint) - */ - - if(!comm && sss->lock_communities) { - HASH_ITER(hh, sss->rules, re, tmp_re) { - allowed_match = re_matchp(re->rule, (const char *)cmn.community, &match_length); - - if((allowed_match != -1) - && (match_length == strlen((const char *)cmn.community)) // --- only full matches allowed (remove, if also partial matches wanted) - && (allowed_match == 0)) { // --- only full matches allowed (remove, if also partial matches wanted) - match = 1; - break; - } - } - if(match != 1) { - traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'", - (char*)cmn.community); - return -1; - } - } + /* We are going to add socket even if it was not there before */ + cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; - if(!comm && (!sss->lock_communities || (match == 1))) { - comm = (struct sn_community*)calloc(1, sizeof(struct sn_community)); + reg.sock.family = AF_INET; + reg.sock.port = ntohs(sender_sock->sin_port); + memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); - if(comm) { - comm_init(comm, (char *)cmn.community); - /* new communities introduced by REGISTERs could not have had encrypted header... */ - comm->header_encryption = HEADER_ENCRYPTION_NONE; - comm->header_encryption_ctx = NULL; - /* ... and also are purgeable during periodic purge */ - comm->purgeable = COMMUNITY_PURGEABLE; - comm->number_enc_packets = 0; - HASH_ADD_STR(sss->communities, community, comm); - - traceEvent(TRACE_INFO, "New community: %s", comm->community); - assign_one_ip_subnet(sss, comm); - } - } + /* Re-encode the header. */ + encode_REGISTER(encbuf, &encx, &cmn2, ®); - if(comm) { - cmn2.ttl = N2N_DEFAULT_TTL; - cmn2.pc = n2n_register_super_ack; - cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; - memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); + rec_buf = encbuf; + } else { + /* Already from a supernode. Nothing to modify, just pass to + * destination. */ - memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t)); + rec_buf = udp_buf; + encx = udp_size; + } - if(comm->is_federation == IS_FEDERATION) { - memcpy(&(ack.edgeMac), &(sss->mac_addr), sizeof(n2n_mac_t)); - } else { - memcpy(&(ack.edgeMac), &(reg.edgeMac), sizeof(n2n_mac_t)); + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(rec_buf, encx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(rec_buf, encx)); + } + try_forward(sss, comm, &cmn, reg.dstMac, from_supernode, rec_buf, encx); /* unicast only */ + } else { + traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination"); + } + break; } - if((reg.dev_addr.net_addr == 0) || (reg.dev_addr.net_addr == 0xFFFFFFFF) || (reg.dev_addr.net_bitlen == 0) || - ((reg.dev_addr.net_addr & 0xFFFF0000) == 0xA9FE0000 /* 169.254.0.0 */)) { - memset(&ipaddr, 0, sizeof(n2n_ip_subnet_t)); - assign_one_ip_addr(comm, &ipaddr); - ack.dev_addr.net_addr = ipaddr.net_addr; - ack.dev_addr.net_bitlen = ipaddr.net_bitlen; + case MSG_TYPE_REGISTER_ACK: { + traceEvent(TRACE_DEBUG, "Rx REGISTER_ACK (NOT IMPLEMENTED) Should not be via supernode"); + break; } - ack.lifetime = reg_lifetime(sss); - ack.sock.family = AF_INET; - ack.sock.port = ntohs(sender_sock->sin_port); - memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); - - /* Add sender's data to federation (or update it) */ - if(comm->is_federation == IS_FEDERATION) { - skip_add = SN_ADD; - p = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &(ack.sock), &(reg.edgeMac), &skip_add); - } + case MSG_TYPE_REGISTER_SUPER: { + n2n_REGISTER_SUPER_t reg; + n2n_REGISTER_SUPER_ACK_t ack; + n2n_REGISTER_SUPER_NAK_t nak; + n2n_common_t cmn2; + uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; + uint8_t tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; + uint8_t *tmp_dst; + uint8_t payload_buf[REG_SUPER_ACK_PAYLOAD_SPACE]; + n2n_REGISTER_SUPER_ACK_payload_t *payload; + size_t encx = 0; + struct sn_community *fed; + struct sn_community_regular_expression *re, *tmp_re; + struct peer_info *peer, *tmp_peer, *p; + int8_t allowed_match = -1; + uint8_t match = 0; + int match_length = 0; + n2n_ip_subnet_t ipaddr; + int num = 0; + int skip_add; + int skip; + int ret_value; + + memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); + memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + + /* Edge/supernode requesting registration with us. */ + sss->stats.last_reg_super=now; + ++(sss->stats.reg_super); + decode_REGISTER_SUPER(®, &cmn, udp_buf, &rem, &idx); + + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, from_supernode, reg.edgeMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER due to time stamp error."); + return -1; + } + } + } - // REVISIT: consider adding last_seen + /* + Before we move any further, we need to check if the requested + community is allowed by the supernode. In case it is not we do + not report any message back to the edge to hide the supernode + existance (better from the security standpoint) + */ + + if(!comm && sss->lock_communities) { + HASH_ITER(hh, sss->rules, re, tmp_re) { + allowed_match = re_matchp(re->rule, (const char *)cmn.community, &match_length); + + if((allowed_match != -1) + && (match_length == strlen((const char *)cmn.community)) // --- only full matches allowed (remove, if also partial matches wanted) + && (allowed_match == 0)) { // --- only full matches allowed (remove, if also partial matches wanted) + match = 1; + break; + } + } + if(match != 1) { + traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'", + (char*)cmn.community); + return -1; + } + } - /* Skip random numbers of supernodes before payload assembling, calculating an appropriate random_number. - * That way, all supernodes have a chance to be propagated with REGISTER_SUPER_ACK. */ - skip = HASH_COUNT(sss->federation->edges) - (int)(REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE / REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE); - skip = (skip < 0) ? 0 : n2n_rand_sqr(skip); + if(!comm && (!sss->lock_communities || (match == 1))) { + comm = (struct sn_community*)calloc(1, sizeof(struct sn_community)); + + if(comm) { + comm_init(comm, (char *)cmn.community); + /* new communities introduced by REGISTERs could not have had encrypted header... */ + comm->header_encryption = HEADER_ENCRYPTION_NONE; + comm->header_encryption_ctx = NULL; + /* ... and also are purgeable during periodic purge */ + comm->purgeable = COMMUNITY_PURGEABLE; + comm->number_enc_packets = 0; + HASH_ADD_STR(sss->communities, community, comm); + + traceEvent(TRACE_INFO, "New community: %s", comm->community); + assign_one_ip_subnet(sss, comm); + } + } - /* Assembling supernode list for REGISTER_SUPER_ACK payload */ - payload = (n2n_REGISTER_SUPER_ACK_payload_t*)payload_buf; - HASH_ITER(hh, sss->federation->edges, peer, tmp_peer) { - if(skip) { - skip--; - continue; - } - if(memcmp(&(peer->sock), &(ack.sock), sizeof(n2n_sock_t)) == 0) continue; /* a supernode doesn't add itself to the payload */ - if((now - peer->last_seen) >= (2*LAST_SEEN_SN_ACTIVE)) continue; /* skip long-time-not-seen supernodes. - * We need to allow for a little extra time because supernodes sometimes exceed - * their SN_ACTIVE time before they get re-registred to. */ - if(((++num)*REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE) > REG_SUPER_ACK_PAYLOAD_SPACE) break; /* no more space available in REGISTER_SUPER_ACK payload */ - memcpy(&(payload->sock), &(peer->sock), sizeof(n2n_sock_t)); - memcpy(&(payload->mac), &(peer->mac_addr), sizeof(n2n_mac_t)); - // shift to next payload entry - payload++; - } - ack.num_sn = num; - - traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]", - macaddr_str(mac_buf, reg.edgeMac), - sock_to_cstr(sockbuf, &(ack.sock))); - - if(memcmp(reg.edgeMac, &null_mac, N2N_MAC_SIZE) != 0) { - if(cmn.flags & N2N_FLAGS_SOCKET) { - ret_value = update_edge(sss, ®, comm, &(ack.sock), SN_ADD_SKIP, now); - } else { - ret_value = update_edge(sss, ®, comm, &(ack.sock), SN_ADD, now); - } + if(comm) { + cmn2.ttl = N2N_DEFAULT_TTL; + cmn2.pc = n2n_register_super_ack; + cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); + + memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t)); + + if(comm->is_federation == IS_FEDERATION) { + memcpy(&(ack.edgeMac), &(sss->mac_addr), sizeof(n2n_mac_t)); + } else { + memcpy(&(ack.edgeMac), &(reg.edgeMac), sizeof(n2n_mac_t)); + } + + if((reg.dev_addr.net_addr == 0) || (reg.dev_addr.net_addr == 0xFFFFFFFF) || (reg.dev_addr.net_bitlen == 0) || + ((reg.dev_addr.net_addr & 0xFFFF0000) == 0xA9FE0000 /* 169.254.0.0 */)) { + memset(&ipaddr, 0, sizeof(n2n_ip_subnet_t)); + assign_one_ip_addr(comm, &ipaddr); + ack.dev_addr.net_addr = ipaddr.net_addr; + ack.dev_addr.net_bitlen = ipaddr.net_bitlen; + } + ack.lifetime = reg_lifetime(sss); + + ack.sock.family = AF_INET; + ack.sock.port = ntohs(sender_sock->sin_port); + memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + /* Add sender's data to federation (or update it) */ + if(comm->is_federation == IS_FEDERATION) { + skip_add = SN_ADD; + p = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &(ack.sock), &(reg.edgeMac), &skip_add); + } + + // REVISIT: consider adding last_seen + + /* Skip random numbers of supernodes before payload assembling, calculating an appropriate random_number. + * That way, all supernodes have a chance to be propagated with REGISTER_SUPER_ACK. */ + skip = HASH_COUNT(sss->federation->edges) - (int)(REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE / REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE); + skip = (skip < 0) ? 0 : n2n_rand_sqr(skip); + + /* Assembling supernode list for REGISTER_SUPER_ACK payload */ + payload = (n2n_REGISTER_SUPER_ACK_payload_t*)payload_buf; + HASH_ITER(hh, sss->federation->edges, peer, tmp_peer) { + if(skip) { + skip--; + continue; + } + if(memcmp(&(peer->sock), &(ack.sock), sizeof(n2n_sock_t)) == 0) continue; /* a supernode doesn't add itself to the payload */ + if((now - peer->last_seen) >= (2*LAST_SEEN_SN_ACTIVE)) continue; /* skip long-time-not-seen supernodes. + * We need to allow for a little extra time because supernodes sometimes exceed + * their SN_ACTIVE time before they get re-registred to. */ + if(((++num)*REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE) > REG_SUPER_ACK_PAYLOAD_SPACE) break; /* no more space available in REGISTER_SUPER_ACK payload */ + memcpy(&(payload->sock), &(peer->sock), sizeof(n2n_sock_t)); + memcpy(&(payload->mac), &(peer->mac_addr), sizeof(n2n_mac_t)); + // shift to next payload entry + payload++; + } + ack.num_sn = num; + + traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]", + macaddr_str(mac_buf, reg.edgeMac), + sock_to_cstr(sockbuf, &(ack.sock))); + + if(memcmp(reg.edgeMac, &null_mac, N2N_MAC_SIZE) != 0) { + if(cmn.flags & N2N_FLAGS_SOCKET) { + ret_value = update_edge(sss, ®, comm, &(ack.sock), SN_ADD_SKIP, now); + } else { + ret_value = update_edge(sss, ®, comm, &(ack.sock), SN_ADD, now); + } + } + + if(ret_value == update_edge_auth_fail) { + cmn2.pc = n2n_register_super_nak; + memcpy(&(nak.cookie), &(reg.cookie), sizeof(n2n_cookie_t)); + memcpy(&(nak.srcMac), &(reg.edgeMac), sizeof(n2n_mac_t)); + + encode_REGISTER_SUPER_NAK(ackbuf, &encx, &cmn2, &nak); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(ackbuf, encx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(ackbuf, encx)); + } + sendto(sss->sock, ackbuf, encx, 0, + (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); + + if(cmn.flags & N2N_FLAGS_SOCKET) { + sendto_sock(sss, ®.sock, ackbuf, encx); + } + + traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_NAK for %s", + macaddr_str(mac_buf, reg.edgeMac)); + } else { + if(!(cmn.flags & N2N_FLAGS_SOCKET)) { + reg.sock.family = AF_INET; + reg.sock.port = ntohs(sender_sock->sin_port); + memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + cmn2.pc = n2n_register_super; + encode_REGISTER_SUPER(ackbuf, &encx, &cmn2, ®); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(ackbuf, encx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(ackbuf, encx)); + } + + try_broadcast(sss, NULL, &cmn, reg.edgeMac, from_supernode, ackbuf, encx); + + encx = 0; + cmn2.pc = n2n_register_super_ack; + + encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack, tmpbuf); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(ackbuf, encx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(ackbuf, encx)); + } + + sendto(sss->sock, ackbuf, encx, 0, + (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); + + traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]", + macaddr_str(mac_buf, reg.edgeMac), + sock_to_cstr(sockbuf, &(ack.sock))); + } + } + } else { + traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'", + (char*)cmn.community); + return -1; + } + break; } - if(ret_value == update_edge_auth_fail) { - cmn2.pc = n2n_register_super_nak; - memcpy(&(nak.cookie), &(reg.cookie), sizeof(n2n_cookie_t)); - memcpy(&(nak.srcMac), &(reg.edgeMac), sizeof(n2n_mac_t)); + case MSG_TYPE_UNREGISTER_SUPER: { + n2n_UNREGISTER_SUPER_t unreg; + struct peer_info *peer; + int auth; - encode_REGISTER_SUPER_NAK(ackbuf, &encx, &cmn2, &nak); - - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(ackbuf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(ackbuf, encx)); - } - sendto(sss->sock, ackbuf, encx, 0, - (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); - - if(cmn.flags & N2N_FLAGS_SOCKET) { - sendto_sock(sss, ®.sock, ackbuf, encx); - } - - traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_NAK for %s", - macaddr_str(mac_buf, reg.edgeMac)); - } else { - if(!(cmn.flags & N2N_FLAGS_SOCKET)) { - reg.sock.family = AF_INET; - reg.sock.port = ntohs(sender_sock->sin_port); - memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); - cmn2.pc = n2n_register_super; - encode_REGISTER_SUPER(ackbuf, &encx, &cmn2, ®); + memset(&unreg, 0, sizeof(n2n_UNREGISTER_SUPER_t)); - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(ackbuf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(ackbuf, encx)); + if(!comm) { + traceEvent(TRACE_DEBUG, "process_udp UNREGISTER_SUPER with unknown community %s", cmn.community); + return -1; } - try_broadcast(sss, NULL, &cmn, reg.edgeMac, from_supernode, ackbuf, encx); - - encx = 0; - cmn2.pc = n2n_register_super_ack; + if((from_supernode == 0) != (comm->is_federation == IS_NO_FEDERATION)) { + traceEvent(TRACE_DEBUG, "process_udp dropped UNREGISTER_SUPER: from_supernode value doesn't correspond to the internal federation marking."); + return -1; + } - encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack, tmpbuf); + decode_UNREGISTER_SUPER(&unreg, &cmn, udp_buf, &rem, &idx); if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(ackbuf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(ackbuf, encx)); + if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, unreg.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped UNREGISTER_SUPER due to time stamp error."); + return -1; + } } - sendto(sss->sock, ackbuf, encx, 0, - (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); - - traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]", - macaddr_str(mac_buf, reg.edgeMac), - sock_to_cstr(sockbuf, &(ack.sock))); - } - } - } else { - traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'", - (char*)cmn.community); - return -1; - } - break; - } - - case MSG_TYPE_UNREGISTER_SUPER: { - n2n_UNREGISTER_SUPER_t unreg; - struct peer_info *peer; - int auth; + traceEvent(TRACE_DEBUG, "Rx UNREGISTER_SUPER from %s", + macaddr_str(mac_buf, unreg.srcMac)); + HASH_FIND_PEER(comm->edges, unreg.srcMac, peer); + if(peer != NULL) { + if((auth = auth_edge(&(peer->auth), &unreg.auth)) == 0) { + HASH_DEL(comm->edges, peer); + } + } - memset(&unreg, 0, sizeof(n2n_UNREGISTER_SUPER_t)); - - if(!comm) { - traceEvent(TRACE_DEBUG, "process_udp UNREGISTER_SUPER with unknown community %s", cmn.community); - return -1; - } - - if((from_supernode == 0) != (comm->is_federation == IS_NO_FEDERATION)) { - traceEvent(TRACE_DEBUG, "process_udp dropped UNREGISTER_SUPER: from_supernode value doesn't correspond to the internal federation marking."); - return -1; - } - - decode_UNREGISTER_SUPER(&unreg, &cmn, udp_buf, &rem, &idx); - - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, unreg.srcMac, stamp, TIME_STAMP_NO_JITTER)) { - traceEvent(TRACE_DEBUG, "process_udp dropped UNREGISTER_SUPER due to time stamp error."); - return -1; + break; } - } - traceEvent(TRACE_DEBUG, "Rx UNREGISTER_SUPER from %s", - macaddr_str(mac_buf, unreg.srcMac)); + case MSG_TYPE_REGISTER_SUPER_ACK: { + n2n_REGISTER_SUPER_ACK_t ack; + size_t encx = 0; + struct sn_community *fed; + struct peer_info *scan, *tmp; + n2n_sock_str_t sockbuf1; + n2n_sock_str_t sockbuf2; + macstr_t mac_buf1; + n2n_sock_t sender; + n2n_sock_t *orig_sender; + n2n_sock_t *tmp_sock; + n2n_mac_t *tmp_mac; + int i; + uint8_t dec_tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; + int skip_add; + n2n_REGISTER_SUPER_ACK_payload_t *payload; + + memset(&sender, 0, sizeof(n2n_sock_t)); + sender.family = AF_INET; + sender.port = ntohs(sender_sock->sin_port); + memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + orig_sender = &sender; + + memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); + + if(!comm) { + traceEvent(TRACE_DEBUG, "process_udp REGISTER_SUPER_ACK with unknown community %s", cmn.community); + return -1; + } - HASH_FIND_PEER(comm->edges, unreg.srcMac, peer); - if(peer != NULL) { - if((auth = auth_edge(&(peer->auth), &unreg.auth)) == 0) { - HASH_DEL(comm->edges, peer); - } - } + if((from_supernode == 0) != (comm->is_federation == IS_NO_FEDERATION)) { + traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK: from_supernode value doesn't correspond to the internal federation marking."); + return -1; + } - break; - } + decode_REGISTER_SUPER_ACK(&ack, &cmn, udp_buf, &rem, &idx, dec_tmpbuf); + orig_sender = &(ack.sock); - case MSG_TYPE_REGISTER_SUPER_ACK: { - n2n_REGISTER_SUPER_ACK_t ack; - size_t encx = 0; - struct sn_community *fed; - struct peer_info *scan, *tmp; - n2n_sock_str_t sockbuf1; - n2n_sock_str_t sockbuf2; - macstr_t mac_buf1; - n2n_sock_t sender; - n2n_sock_t *orig_sender; - n2n_sock_t *tmp_sock; - n2n_mac_t *tmp_mac; - int i; - uint8_t dec_tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; - int skip_add; - n2n_REGISTER_SUPER_ACK_payload_t *payload; - - memset(&sender, 0, sizeof(n2n_sock_t)); - sender.family = AF_INET; - sender.port = ntohs(sender_sock->sin_port); - memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE); - orig_sender = &sender; - - memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); - - if(!comm) { - traceEvent(TRACE_DEBUG, "process_udp REGISTER_SUPER_ACK with unknown community %s", cmn.community); - return -1; - } + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, ack.edgeMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK due to time stamp error."); + return -1; + } + } + } - if((from_supernode == 0) != (comm->is_federation == IS_NO_FEDERATION)) { - traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK: from_supernode value doesn't correspond to the internal federation marking."); - return -1; - } + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s)", + macaddr_str(mac_buf1, ack.edgeMac), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender)); + + if(comm->is_federation == IS_FEDERATION) { + skip_add = SN_ADD_SKIP; + scan = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &sender, &(ack.edgeMac), &skip_add); + if(scan != NULL) { + scan->last_seen = now; + } else { + traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK due to an unknown supernode."); + break; + } + } - decode_REGISTER_SUPER_ACK(&ack, &cmn, udp_buf, &rem, &idx, dec_tmpbuf); - orig_sender = &(ack.sock); + payload = (n2n_REGISTER_SUPER_ACK_payload_t *)dec_tmpbuf; - if(comm) { - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, ack.edgeMac, stamp, TIME_STAMP_NO_JITTER)) { - traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK due to time stamp error."); - return -1; - } - } - } - - traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s)", - macaddr_str(mac_buf1, ack.edgeMac), - sock_to_cstr(sockbuf1, &sender), - sock_to_cstr(sockbuf2, orig_sender)); - - if(comm->is_federation == IS_FEDERATION) { - skip_add = SN_ADD_SKIP; - scan = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &sender, &(ack.edgeMac), &skip_add); - if(scan != NULL) { - scan->last_seen = now; - } else { - traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_ACK due to an unknown supernode."); - break; - } - } + for(i = 0; i < ack.num_sn; i++) { + skip_add = SN_ADD; + tmp = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &(payload->sock), &(payload->mac), &skip_add); - payload = (n2n_REGISTER_SUPER_ACK_payload_t *)dec_tmpbuf; + if(skip_add == SN_ADD_ADDED) { + tmp->last_seen = now - LAST_SEEN_SN_NEW; + } - for(i = 0; i < ack.num_sn; i++) { - skip_add = SN_ADD; - tmp = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &(payload->sock), &(payload->mac), &skip_add); + // shift to next payload entry + payload++; + } - if(skip_add == SN_ADD_ADDED) { - tmp->last_seen = now - LAST_SEEN_SN_NEW; + break; } - // shift to next payload entry - payload++; - } + case MSG_TYPE_REGISTER_SUPER_NAK: { + n2n_REGISTER_SUPER_NAK_t nak; + size_t encx = 0; + struct peer_info *peer; + n2n_sock_str_t sockbuf; + macstr_t mac_buf; + n2n_sock_t sender; - break; - } - - case MSG_TYPE_REGISTER_SUPER_NAK: { - n2n_REGISTER_SUPER_NAK_t nak; - size_t encx = 0; - struct peer_info *peer; - n2n_sock_str_t sockbuf; - macstr_t mac_buf; - n2n_sock_t sender; + memset(&sender, 0, sizeof(n2n_sock_t)); + sender.family = AF_INET; + sender.port = ntohs(sender_sock->sin_port); + memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE); - memset(&sender, 0, sizeof(n2n_sock_t)); - sender.family = AF_INET; - sender.port = ntohs(sender_sock->sin_port); - memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); - memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); - - if(!comm) { - traceEvent(TRACE_DEBUG, "process_udp REGISTER_SUPER_NAK with unknown community %s", cmn.community); - return -1; - } - - decode_REGISTER_SUPER_NAK(&nak, &cmn, udp_buf, &rem, &idx); + if(!comm) { + traceEvent(TRACE_DEBUG, "process_udp REGISTER_SUPER_NAK with unknown community %s", cmn.community); + return -1; + } - if(comm) { - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, nak.srcMac, stamp, TIME_STAMP_NO_JITTER)) { - traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_NAK due to time stamp error."); - return -1; - } - } - } + decode_REGISTER_SUPER_NAK(&nak, &cmn, udp_buf, &rem, &idx); - traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_NAK from %s [%s]", - macaddr_str(mac_buf, nak.srcMac), - sock_to_cstr(sockbuf, &sender)); + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, nak.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_NAK due to time stamp error."); + return -1; + } + } + } - HASH_FIND_PEER(comm->edges, nak.srcMac, peer); - if(comm->is_federation == IS_NO_FEDERATION) { - if(peer != NULL) { - HASH_DEL(comm->edges, peer); - } - } + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_NAK from %s [%s]", + macaddr_str(mac_buf, nak.srcMac), + sock_to_cstr(sockbuf, &sender)); - break; - } + HASH_FIND_PEER(comm->edges, nak.srcMac, peer); + if(comm->is_federation == IS_NO_FEDERATION) { + if(peer != NULL) { + HASH_DEL(comm->edges, peer); + } + } - case MSG_TYPE_QUERY_PEER: { - n2n_QUERY_PEER_t query; - uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; - size_t encx = 0; - n2n_common_t cmn2; - n2n_PEER_INFO_t pi; - struct sn_community_regular_expression *re, *tmp_re; - struct peer_info *peer, *tmp_peer, *p; - int8_t allowed_match = -1; - uint8_t match = 0; - int match_length = 0; - uint8_t *rec_buf; /* either udp_buf or encbuf */ - - if(!comm && sss->lock_communities) { - HASH_ITER(hh, sss->rules, re, tmp_re) { - allowed_match = re_matchp(re->rule, (const char *)cmn.community, &match_length); - - if((allowed_match != -1) - && (match_length == strlen((const char *)cmn.community)) // --- only full match… - && (allowed_match == 0)) { // --- only full matches allowed (re… - match = 1; break; - } } - if(match != 1) { - traceEvent(TRACE_DEBUG, "process_udp QUERY_PEER from unknown community %s", cmn.community); - return -1; - } - } - - if(!comm && sss->lock_communities && (match == 0)) { - traceEvent(TRACE_DEBUG, "process_udp QUERY_PEER from not allowed community %s", cmn.community); - return -1; - } - - decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx ); - - // already checked for valid comm - if(comm) { - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, query.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) { - traceEvent(TRACE_DEBUG, "process_udp dropped QUERY_PEER due to time stamp error."); - return -1; - } - } - } - - if(memcmp(query.targetMac, null_mac, sizeof(n2n_mac_t)) == 0) { - traceEvent(TRACE_DEBUG, "Rx PING from %s.", - macaddr_str(mac_buf, query.srcMac)); - - cmn2.ttl = N2N_DEFAULT_TTL; - cmn2.pc = n2n_peer_info; - cmn2.flags = N2N_FLAGS_FROM_SUPERNODE; - memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); - - pi.aflags = 0; - memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t)); - memcpy(pi.srcMac, sss->mac_addr, sizeof(n2n_mac_t)); - pi.sock.family = AF_INET; - pi.sock.port = ntohs(sender_sock->sin_port); - memcpy(pi.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); - pi.data = sn_selection_criterion_gather_data(sss); - - encode_PEER_INFO(encbuf, &encx, &cmn2, &pi); - - if(comm) { - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(encbuf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(encbuf, encx)); - } - } - - sendto(sss->sock, encbuf, encx, 0, - (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); - - traceEvent(TRACE_DEBUG, "Tx PONG to %s", - macaddr_str(mac_buf, query.srcMac)); - - } else { - traceEvent(TRACE_DEBUG, "Rx QUERY_PEER from %s for %s", - macaddr_str(mac_buf, query.srcMac), - macaddr_str(mac_buf2, query.targetMac)); - - struct peer_info *scan; - HASH_FIND_PEER(comm->edges, query.targetMac, scan); - if(scan) { - cmn2.ttl = N2N_DEFAULT_TTL; - cmn2.pc = n2n_peer_info; - cmn2.flags = N2N_FLAGS_FROM_SUPERNODE; - memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); - - pi.aflags = 0; - memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t)); - pi.sock = scan->sock; - - encode_PEER_INFO(encbuf, &encx, &cmn2, &pi); - - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(encbuf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(encbuf, encx)); - } - - if(cmn.flags & N2N_FLAGS_SOCKET) { - sendto_sock(sss, &query.sock, encbuf, encx); - } else { - sendto(sss->sock, encbuf, encx, 0, - (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); - } - traceEvent(TRACE_DEBUG, "Tx PEER_INFO to %s", - macaddr_str(mac_buf, query.srcMac)); - - } else { - if(from_supernode) { - traceEvent(TRACE_DEBUG, "QUERY_PEER on unknown edge from supernode %s. Dropping the packet.", - macaddr_str(mac_buf, query.srcMac)); - } else { - traceEvent(TRACE_DEBUG, "QUERY_PEER from unknown edge %s. Forwarding to all other supernodes.", - macaddr_str(mac_buf, query.srcMac)); + case MSG_TYPE_QUERY_PEER: { + n2n_QUERY_PEER_t query; + uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx = 0; + n2n_common_t cmn2; + n2n_PEER_INFO_t pi; + struct sn_community_regular_expression *re, *tmp_re; + struct peer_info *peer, *tmp_peer, *p; + int8_t allowed_match = -1; + uint8_t match = 0; + int match_length = 0; + uint8_t *rec_buf; /* either udp_buf or encbuf */ + + if(!comm && sss->lock_communities) { + HASH_ITER(hh, sss->rules, re, tmp_re) { + allowed_match = re_matchp(re->rule, (const char *)cmn.community, &match_length); + + if((allowed_match != -1) + && (match_length == strlen((const char *)cmn.community)) // --- only full match… + && (allowed_match == 0)) { // --- only full matches allowed (re… + match = 1; + break; + } + } + if(match != 1) { + traceEvent(TRACE_DEBUG, "process_udp QUERY_PEER from unknown community %s", cmn.community); + return -1; + } + } - memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); + if(!comm && sss->lock_communities && (match == 0)) { + traceEvent(TRACE_DEBUG, "process_udp QUERY_PEER from not allowed community %s", cmn.community); + return -1; + } - /* We are going to add socket even if it was not there before */ - cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; - query.sock.family = AF_INET; - query.sock.port = ntohs(sender_sock->sin_port); - memcpy(query.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx ); - encode_QUERY_PEER(encbuf, &encx, &cmn2, &query); + // already checked for valid comm + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify (comm->edges, from_supernode, query.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped QUERY_PEER due to time stamp error."); + return -1; + } + } + } - if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { - packet_header_encrypt(encbuf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, - time_stamp(), pearson_hash_16(encbuf, encx)); + if(memcmp(query.targetMac, null_mac, sizeof(n2n_mac_t)) == 0) { + traceEvent(TRACE_DEBUG, "Rx PING from %s.", + macaddr_str(mac_buf, query.srcMac)); + + cmn2.ttl = N2N_DEFAULT_TTL; + cmn2.pc = n2n_peer_info; + cmn2.flags = N2N_FLAGS_FROM_SUPERNODE; + memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); + + pi.aflags = 0; + memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t)); + memcpy(pi.srcMac, sss->mac_addr, sizeof(n2n_mac_t)); + pi.sock.family = AF_INET; + pi.sock.port = ntohs(sender_sock->sin_port); + memcpy(pi.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + pi.data = sn_selection_criterion_gather_data(sss); + + encode_PEER_INFO(encbuf, &encx, &cmn2, &pi); + + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(encbuf, encx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(encbuf, encx)); + } + } + + sendto(sss->sock, encbuf, encx, 0, + (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); + + traceEvent(TRACE_DEBUG, "Tx PONG to %s", + macaddr_str(mac_buf, query.srcMac)); + + } else { + traceEvent(TRACE_DEBUG, "Rx QUERY_PEER from %s for %s", + macaddr_str(mac_buf, query.srcMac), + macaddr_str(mac_buf2, query.targetMac)); + + struct peer_info *scan; + HASH_FIND_PEER(comm->edges, query.targetMac, scan); + if(scan) { + cmn2.ttl = N2N_DEFAULT_TTL; + cmn2.pc = n2n_peer_info; + cmn2.flags = N2N_FLAGS_FROM_SUPERNODE; + memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); + + pi.aflags = 0; + memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t)); + pi.sock = scan->sock; + + encode_PEER_INFO(encbuf, &encx, &cmn2, &pi); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(encbuf, encx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(encbuf, encx)); + } + + if(cmn.flags & N2N_FLAGS_SOCKET) { + sendto_sock(sss, &query.sock, encbuf, encx); + } else { + sendto(sss->sock, encbuf, encx, 0, + (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); + } + traceEvent(TRACE_DEBUG, "Tx PEER_INFO to %s", + macaddr_str(mac_buf, query.srcMac)); + + } else { + + if(from_supernode) { + traceEvent(TRACE_DEBUG, "QUERY_PEER on unknown edge from supernode %s. Dropping the packet.", + macaddr_str(mac_buf, query.srcMac)); + } else { + traceEvent(TRACE_DEBUG, "QUERY_PEER from unknown edge %s. Forwarding to all other supernodes.", + macaddr_str(mac_buf, query.srcMac)); + + memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); + + /* We are going to add socket even if it was not there before */ + cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + query.sock.family = AF_INET; + query.sock.port = ntohs(sender_sock->sin_port); + memcpy(query.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + encode_QUERY_PEER(encbuf, &encx, &cmn2, &query); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(encbuf, encx, comm->header_encryption_ctx, + comm->header_iv_ctx, + time_stamp(), pearson_hash_16(encbuf, encx)); + } + + try_broadcast(sss, NULL, &cmn, query.srcMac, from_supernode, encbuf, encx); + } + } } - try_broadcast(sss, NULL, &cmn, query.srcMac, from_supernode, encbuf, encx); - } + break; } - } - break; - } - - default: - /* Not a known message type */ - traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type); - } /* switch(msg_type) */ + default: + /* Not a known message type */ + traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type); + } /* switch(msg_type) */ - return 0; + return 0; } /** Long lived processing entry point. Split out from main to simply * daemonisation on some platforms. */ int run_sn_loop (n2n_sn_t *sss, int *keep_running) { - uint8_t pktbuf[N2N_SN_PKTBUF_SIZE]; - time_t last_purge_edges = 0; - time_t last_sort_communities = 0; - time_t last_re_reg_and_purge = 0; + uint8_t pktbuf[N2N_SN_PKTBUF_SIZE]; + time_t last_purge_edges = 0; + time_t last_sort_communities = 0; + time_t last_re_reg_and_purge = 0; - sss->start_time = time(NULL); + sss->start_time = time(NULL); - while(*keep_running) { - int rc; - ssize_t bread; - int max_sock; - fd_set socket_mask; - struct timeval wait_time; - time_t now = 0; + while(*keep_running) { + int rc; + ssize_t bread; + int max_sock; + fd_set socket_mask; + struct timeval wait_time; + time_t now = 0; - FD_ZERO(&socket_mask); - max_sock = MAX(sss->sock, sss->mgmt_sock); + FD_ZERO(&socket_mask); + max_sock = MAX(sss->sock, sss->mgmt_sock); - FD_SET(sss->sock, &socket_mask); - FD_SET(sss->mgmt_sock, &socket_mask); + FD_SET(sss->sock, &socket_mask); + FD_SET(sss->mgmt_sock, &socket_mask); - wait_time.tv_sec = 10; - wait_time.tv_usec = 0; - rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time); + wait_time.tv_sec = 10; + wait_time.tv_usec = 0; + rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time); - now = time(NULL); + now = time(NULL); - if(rc > 0) { - if(FD_ISSET(sss->sock, &socket_mask)) { - struct sockaddr_in sender_sock; - socklen_t i; + if(rc > 0) { + if(FD_ISSET(sss->sock, &socket_mask)) { + struct sockaddr_in sender_sock; + socklen_t i; - i = sizeof(sender_sock); - bread = recvfrom(sss->sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/, - (struct sockaddr *)&sender_sock, (socklen_t *)&i); + i = sizeof(sender_sock); + bread = recvfrom(sss->sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t *)&i); - if((bread < 0) + if((bread < 0) #ifdef WIN32 - && (WSAGetLastError() != WSAECONNRESET) + && (WSAGetLastError() != WSAECONNRESET) #endif - ) { - /* For UDP bread of zero just means no data (unlike TCP). */ - /* The fd is no good now. Maybe we lost our interface. */ - traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno)); + ) { + /* For UDP bread of zero just means no data (unlike TCP). */ + /* The fd is no good now. Maybe we lost our interface. */ + traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno)); #ifdef WIN32 - traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); + traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); #endif - *keep_running = 0; - break; - } + *keep_running = 0; + break; + } + + /* We have a datagram to process */ + if(bread > 0) { + /* And the datagram has data (not just a header) */ + process_udp(sss, &sender_sock, pktbuf, bread, now); + } + } - /* We have a datagram to process */ - if(bread > 0) { - /* And the datagram has data (not just a header) */ - process_udp(sss, &sender_sock, pktbuf, bread, now); - } - } + if(FD_ISSET(sss->mgmt_sock, &socket_mask)) { + struct sockaddr_in sender_sock; + size_t i; - if(FD_ISSET(sss->mgmt_sock, &socket_mask)) { - struct sockaddr_in sender_sock; - size_t i; + i = sizeof(sender_sock); + bread = recvfrom(sss->mgmt_sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t *)&i); - i = sizeof(sender_sock); - bread = recvfrom(sss->mgmt_sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/, - (struct sockaddr *)&sender_sock, (socklen_t *)&i); + if(bread <= 0) { + traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno)); + *keep_running = 0; + break; + } - if(bread <= 0) { - traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno)); - *keep_running = 0; - break; + /* We have a datagram to process */ + process_mgmt(sss, &sender_sock, pktbuf, bread, now); + } + } else { + traceEvent(TRACE_DEBUG, "timeout"); } - /* We have a datagram to process */ - process_mgmt(sss, &sender_sock, pktbuf, bread, now); - } - } else { - traceEvent(TRACE_DEBUG, "timeout"); - } + re_register_and_purge_supernodes(sss, sss->federation, &last_re_reg_and_purge, now); + purge_expired_communities(sss, &last_purge_edges, now); + sort_communities(sss, &last_sort_communities, now); + } /* while */ - re_register_and_purge_supernodes(sss, sss->federation, &last_re_reg_and_purge, now); - purge_expired_communities(sss, &last_purge_edges, now); - sort_communities(sss, &last_sort_communities, now); - } /* while */ + sn_term(sss); - sn_term(sss); - - return 0; + return 0; } diff --git a/src/wire.c b/src/wire.c index 4b7356c..ebec712 100644 --- a/src/wire.c +++ b/src/wire.c @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -33,10 +33,10 @@ int encode_uint8 (uint8_t * base, size_t * idx, const uint8_t v) { - *(base + (*idx)) = (v & 0xff); - ++(*idx); + *(base + (*idx)) = (v & 0xff); + ++(*idx); - return 1; + return 1; } int decode_uint8 (uint8_t * out, @@ -44,26 +44,26 @@ int decode_uint8 (uint8_t * out, size_t * rem, size_t * idx) { - if(*rem < 1) { - return 0; - } + if(*rem < 1) { + return 0; + } - *out = ( base[*idx] & 0xff ); - ++(*idx); - --(*rem); + *out = ( base[*idx] & 0xff ); + ++(*idx); + --(*rem); - return 1; + return 1; } int encode_uint16 (uint8_t * base, size_t * idx, const uint16_t v) { - *(base + (*idx)) = ( v >> 8) & 0xff; - *(base + (1 + *idx)) = ( v & 0xff ); - *idx += 2; + *(base + (*idx)) = ( v >> 8) & 0xff; + *(base + (1 + *idx)) = ( v & 0xff ); + *idx += 2; - return 2; + return 2; } int decode_uint16 (uint16_t * out, @@ -71,29 +71,29 @@ int decode_uint16 (uint16_t * out, size_t * rem, size_t * idx) { - if (*rem < 2) { - return 0; - } + if (*rem < 2) { + return 0; + } - *out = ( base[*idx] & 0xff ) << 8; - *out |= ( base[1 + *idx] & 0xff ); - *idx += 2; - *rem -= 2; + *out = ( base[*idx] & 0xff ) << 8; + *out |= ( base[1 + *idx] & 0xff ); + *idx += 2; + *rem -= 2; - return 2; + return 2; } int encode_uint32 (uint8_t * base, size_t * idx, const uint32_t v) { - *(base + (0 + *idx)) = ( v >> 24) & 0xff; - *(base + (1 + *idx)) = ( v >> 16) & 0xff; - *(base + (2 + *idx)) = ( v >> 8) & 0xff; - *(base + (3 + *idx)) = ( v & 0xff ); - *idx += 4; + *(base + (0 + *idx)) = ( v >> 24) & 0xff; + *(base + (1 + *idx)) = ( v >> 16) & 0xff; + *(base + (2 + *idx)) = ( v >> 8) & 0xff; + *(base + (3 + *idx)) = ( v & 0xff ); + *idx += 4; - return 4; + return 4; } int decode_uint32 (uint32_t * out, @@ -101,28 +101,28 @@ int decode_uint32 (uint32_t * out, size_t * rem, size_t * idx) { - if (*rem < 4) { - return 0; - } + if (*rem < 4) { + return 0; + } - *out = ( base[0 + *idx] & 0xff ) << 24; - *out |= ( base[1 + *idx] & 0xff ) << 16; - *out |= ( base[2 + *idx] & 0xff ) << 8; - *out |= ( base[3 + *idx] & 0xff ); - *idx += 4; - *rem -= 4; + *out = ( base[0 + *idx] & 0xff ) << 24; + *out |= ( base[1 + *idx] & 0xff ) << 16; + *out |= ( base[2 + *idx] & 0xff ) << 8; + *out |= ( base[3 + *idx] & 0xff ); + *idx += 4; + *rem -= 4; - return 4; + return 4; } int encode_uint64 (uint8_t * base, size_t * idx, const uint64_t v) { - *(uint64_t*)(base + *idx) = htobe64(v); - *idx += 8; + *(uint64_t*)(base + *idx) = htobe64(v); + *idx += 8; - return 8; + return 8; } int decode_uint64 (uint64_t * out, @@ -130,15 +130,15 @@ int decode_uint64 (uint64_t * out, size_t * rem, size_t * idx) { - if (*rem < 8) { - return 0; - } + if (*rem < 8) { + return 0; + } - *out = be64toh(*(uint64_t*)base + *idx); - *idx += 8; - *rem -= 8; + *out = be64toh(*(uint64_t*)base + *idx); + *idx += 8; + *rem -= 8; - return 8; + return 8; } int encode_buf (uint8_t * base, @@ -146,10 +146,10 @@ int encode_buf (uint8_t * base, const void * p, size_t s) { - memcpy((base + (*idx)), p, s); - *idx += s; + memcpy((base + (*idx)), p, s); + *idx += s; - return s; + return s; } /* Copy from base to out of size bufsize */ @@ -159,15 +159,15 @@ int decode_buf (uint8_t * out, size_t * rem, size_t * idx) { - if (*rem < bufsize) { - return 0; - } + if (*rem < bufsize) { + return 0; + } - memcpy(out, (base + *idx), bufsize); - *idx += bufsize; - *rem -= bufsize; + memcpy(out, (base + *idx), bufsize); + *idx += bufsize; + *rem -= bufsize; - return bufsize; + return bufsize; } @@ -176,7 +176,7 @@ int encode_mac (uint8_t * base, size_t * idx, const n2n_mac_t m) { - return encode_buf(base, idx, m, N2N_MAC_SIZE); + return encode_buf(base, idx, m, N2N_MAC_SIZE); } int decode_mac (uint8_t * out, /* of size N2N_MAC_SIZE. This clearer than passing a n2n_mac_t */ @@ -184,7 +184,7 @@ int decode_mac (uint8_t * out, /* of size N2N_MAC_SIZE. This clearer than passin size_t * rem, size_t * idx) { - return decode_buf(out, N2N_MAC_SIZE, base, rem, idx); + return decode_buf(out, N2N_MAC_SIZE, base, rem, idx); } @@ -193,18 +193,18 @@ int encode_common (uint8_t * base, size_t * idx, const n2n_common_t * common) { - uint16_t flags = 0; + uint16_t flags = 0; - encode_uint8(base, idx, N2N_PKT_VERSION); - encode_uint8(base, idx, common->ttl); + encode_uint8(base, idx, N2N_PKT_VERSION); + encode_uint8(base, idx, common->ttl); - flags = common->pc & N2N_FLAGS_TYPE_MASK; - flags |= common->flags & N2N_FLAGS_BITS_MASK; + flags = common->pc & N2N_FLAGS_TYPE_MASK; + flags |= common->flags & N2N_FLAGS_BITS_MASK; - encode_uint16(base, idx, flags); - encode_buf(base, idx, common->community, N2N_COMMUNITY_SIZE); + encode_uint16(base, idx, flags); + encode_buf(base, idx, common->community, N2N_COMMUNITY_SIZE); - return -1; + return -1; } int decode_common (n2n_common_t * out, @@ -212,23 +212,23 @@ int decode_common (n2n_common_t * out, size_t * rem, size_t * idx) { - size_t idx0 = *idx; - uint8_t dummy = 0; + size_t idx0 = *idx; + uint8_t dummy = 0; - decode_uint8(&dummy, base, rem, idx); + decode_uint8(&dummy, base, rem, idx); - if (N2N_PKT_VERSION != dummy) { - return -1; - } + if(N2N_PKT_VERSION != dummy) { + return -1; + } - decode_uint8(&(out->ttl), base, rem, idx); - decode_uint16(&(out->flags), base, rem, idx); - out->pc = ( out->flags & N2N_FLAGS_TYPE_MASK ); - out->flags &= N2N_FLAGS_BITS_MASK; + decode_uint8(&(out->ttl), base, rem, idx); + decode_uint16(&(out->flags), base, rem, idx); + out->pc = (out->flags & N2N_FLAGS_TYPE_MASK); + out->flags &= N2N_FLAGS_BITS_MASK; - decode_buf(out->community, N2N_COMMUNITY_SIZE, base, rem, idx); + decode_buf(out->community, N2N_COMMUNITY_SIZE, base, rem, idx); - return (*idx - idx0); + return (*idx - idx0); } @@ -236,31 +236,31 @@ int encode_sock (uint8_t * base, size_t * idx, const n2n_sock_t * sock) { - int retval = 0; - uint16_t f; - - switch(sock->family) { - case AF_INET: { - f = 0; - retval += encode_uint16(base, idx, f); - retval += encode_uint16(base, idx, sock->port); - retval += encode_buf(base, idx, sock->addr.v4, IPV4_SIZE); - break; - } - - case AF_INET6: { - f = 0x8000; - retval += encode_uint16(base, idx, f); - retval += encode_uint16(base, idx, sock->port); - retval += encode_buf(base, idx, sock->addr.v6, IPV6_SIZE); - break; + int retval = 0; + uint16_t f; + + switch(sock->family) { + case AF_INET: { + f = 0; + retval += encode_uint16(base, idx, f); + retval += encode_uint16(base, idx, sock->port); + retval += encode_buf(base, idx, sock->addr.v4, IPV4_SIZE); + break; + } + + case AF_INET6: { + f = 0x8000; + retval += encode_uint16(base, idx, f); + retval += encode_uint16(base, idx, sock->port); + retval += encode_buf(base, idx, sock->addr.v6, IPV6_SIZE); + break; + } + + default: + retval = -1; } - default: - retval = -1; - } - - return retval; + return retval; } @@ -269,26 +269,26 @@ int decode_sock (n2n_sock_t * sock, size_t * rem, size_t * idx) { - size_t * idx0 = idx; - uint16_t f = 0; + size_t * idx0 = idx; + uint16_t f = 0; - decode_uint16(&f, base, rem, idx); + decode_uint16(&f, base, rem, idx); - if(f & 0x8000) { + if(f & 0x8000) { - /* IPv6 */ - sock->family = AF_INET6; - decode_uint16(&(sock->port), base, rem, idx); - decode_buf(sock->addr.v6, IPV6_SIZE, base, rem, idx); - } else { - /* IPv4 */ - sock->family = AF_INET; - decode_uint16(&(sock->port), base, rem, idx); - memset(sock->addr.v6, 0, IPV6_SIZE); /* so memcmp() works for equality. */ - decode_buf(sock->addr.v4, IPV4_SIZE, base, rem, idx); - } + /* IPv6 */ + sock->family = AF_INET6; + decode_uint16(&(sock->port), base, rem, idx); + decode_buf(sock->addr.v6, IPV6_SIZE, base, rem, idx); + } else { + /* IPv4 */ + sock->family = AF_INET; + decode_uint16(&(sock->port), base, rem, idx); + memset(sock->addr.v6, 0, IPV6_SIZE); /* so memcmp() works for equality. */ + decode_buf(sock->addr.v4, IPV4_SIZE, base, rem, idx); + } - return (idx-idx0); + return (idx - idx0); } @@ -297,20 +297,20 @@ int encode_REGISTER (uint8_t *base, const n2n_common_t *common, const n2n_REGISTER_t *reg) { - int retval = 0; + int retval = 0; - retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); - retval += encode_mac(base, idx, reg->srcMac); - retval += encode_mac(base, idx, reg->dstMac); - if(0 != reg->sock.family) { - retval += encode_sock(base, idx, &(reg->sock)); - } - retval += encode_uint32(base, idx, reg->dev_addr.net_addr); - retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); - retval += encode_buf(base, idx, reg->dev_desc, N2N_DESC_SIZE); + retval += encode_common(base, idx, common); + retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); + retval += encode_mac(base, idx, reg->srcMac); + retval += encode_mac(base, idx, reg->dstMac); + if(0 != reg->sock.family) { + retval += encode_sock(base, idx, &(reg->sock)); + } + retval += encode_uint32(base, idx, reg->dev_addr.net_addr); + retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); + retval += encode_buf(base, idx, reg->dev_desc, N2N_DESC_SIZE); - return retval; + return retval; } @@ -320,20 +320,20 @@ int decode_REGISTER (n2n_REGISTER_t *reg, size_t *rem, size_t *idx) { - size_t retval = 0; - memset(reg, 0, sizeof(n2n_REGISTER_t)); + size_t retval = 0; + memset(reg, 0, sizeof(n2n_REGISTER_t)); - retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); - retval += decode_mac(reg->srcMac, base, rem, idx); - retval += decode_mac(reg->dstMac, base, rem, idx); - if(cmn->flags & N2N_FLAGS_SOCKET) { - retval += decode_sock(&(reg->sock), base, rem, idx); - } - retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); - retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); - retval += decode_buf(reg->dev_desc, N2N_DESC_SIZE, base, rem, idx); + retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_mac(reg->srcMac, base, rem, idx); + retval += decode_mac(reg->dstMac, base, rem, idx); + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&(reg->sock), base, rem, idx); + } + retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); + retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); + retval += decode_buf(reg->dev_desc, N2N_DESC_SIZE, base, rem, idx); - return retval; + return retval; } @@ -342,22 +342,22 @@ int encode_REGISTER_SUPER (uint8_t *base, const n2n_common_t *common, const n2n_REGISTER_SUPER_t *reg) { - int retval = 0; + int retval = 0; - retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); - retval += encode_mac(base, idx, reg->edgeMac); - if(0 != reg->sock.family) { - retval += encode_sock(base, idx, &(reg->sock)); - } - retval += encode_uint32(base, idx, reg->dev_addr.net_addr); - retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); - retval += encode_buf(base, idx, reg->dev_desc, N2N_DESC_SIZE); - retval += encode_uint16(base, idx, reg->auth.scheme); - retval += encode_uint16(base, idx, reg->auth.toksize); - retval += encode_buf(base, idx, reg->auth.token, reg->auth.toksize); + retval += encode_common(base, idx, common); + retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); + retval += encode_mac(base, idx, reg->edgeMac); + if(0 != reg->sock.family) { + retval += encode_sock(base, idx, &(reg->sock)); + } + retval += encode_uint32(base, idx, reg->dev_addr.net_addr); + retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); + retval += encode_buf(base, idx, reg->dev_desc, N2N_DESC_SIZE); + retval += encode_uint16(base, idx, reg->auth.scheme); + retval += encode_uint16(base, idx, reg->auth.toksize); + retval += encode_buf(base, idx, reg->auth.token, reg->auth.toksize); - return retval; + return retval; } @@ -367,22 +367,22 @@ int decode_REGISTER_SUPER (n2n_REGISTER_SUPER_t *reg, size_t *rem, size_t *idx) { - size_t retval = 0; - memset(reg, 0, sizeof(n2n_REGISTER_SUPER_t)); + size_t retval = 0; + memset(reg, 0, sizeof(n2n_REGISTER_SUPER_t)); - retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); - retval += decode_mac(reg->edgeMac, base, rem, idx); - if(cmn->flags & N2N_FLAGS_SOCKET) { - retval += decode_sock(&(reg->sock), base, rem, idx); - } - retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); - retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); - retval += decode_buf(reg->dev_desc, N2N_DESC_SIZE, base, rem, idx); - retval += decode_uint16(&(reg->auth.scheme), base, rem, idx); - retval += decode_uint16(&(reg->auth.toksize), base, rem, idx); - retval += decode_buf(reg->auth.token, reg->auth.toksize, base, rem, idx); + retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_mac(reg->edgeMac, base, rem, idx); + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&(reg->sock), base, rem, idx); + } + retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); + retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); + retval += decode_buf(reg->dev_desc, N2N_DESC_SIZE, base, rem, idx); + retval += decode_uint16(&(reg->auth.scheme), base, rem, idx); + retval += decode_uint16(&(reg->auth.toksize), base, rem, idx); + retval += decode_buf(reg->auth.token, reg->auth.toksize, base, rem, idx); - return retval; + return retval; } @@ -391,15 +391,15 @@ int encode_UNREGISTER_SUPER (uint8_t *base, const n2n_common_t *common, const n2n_UNREGISTER_SUPER_t *unreg) { - int retval = 0; + int retval = 0; - retval += encode_common(base, idx, common); - retval += encode_uint16(base, idx, unreg->auth.scheme); - retval += encode_uint16(base, idx, unreg->auth.toksize); - retval += encode_buf(base, idx, unreg->auth.token, unreg->auth.toksize); - retval += encode_mac(base, idx, unreg->srcMac); + retval += encode_common(base, idx, common); + retval += encode_uint16(base, idx, unreg->auth.scheme); + retval += encode_uint16(base, idx, unreg->auth.toksize); + retval += encode_buf(base, idx, unreg->auth.token, unreg->auth.toksize); + retval += encode_mac(base, idx, unreg->srcMac); - return retval; + return retval; } @@ -409,15 +409,15 @@ int decode_UNREGISTER_SUPER (n2n_UNREGISTER_SUPER_t *unreg, size_t *rem, size_t *idx) { - size_t retval = 0; - memset(unreg, 0, sizeof(n2n_UNREGISTER_SUPER_t)); + size_t retval = 0; + memset(unreg, 0, sizeof(n2n_UNREGISTER_SUPER_t)); - retval += decode_uint16(&(unreg->auth.scheme), base, rem, idx); - retval += decode_uint16(&(unreg->auth.toksize), base, rem, idx); - retval += decode_buf(unreg->auth.token, unreg->auth.toksize, base, rem, idx); - retval += decode_mac(unreg->srcMac, base, rem, idx); + retval += decode_uint16(&(unreg->auth.scheme), base, rem, idx); + retval += decode_uint16(&(unreg->auth.toksize), base, rem, idx); + retval += decode_buf(unreg->auth.token, unreg->auth.toksize, base, rem, idx); + retval += decode_mac(unreg->srcMac, base, rem, idx); - return retval; + return retval; } @@ -426,21 +426,21 @@ int encode_REGISTER_ACK (uint8_t *base, const n2n_common_t *common, const n2n_REGISTER_ACK_t *reg) { - int retval = 0; + int retval = 0; - retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); - retval += encode_mac(base, idx, reg->dstMac); - retval += encode_mac(base, idx, reg->srcMac); + retval += encode_common(base, idx, common); + retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); + retval += encode_mac(base, idx, reg->dstMac); + retval += encode_mac(base, idx, reg->srcMac); - /* The socket in REGISTER_ACK is the socket from which the REGISTER - * arrived. This is sent back to the sender so it knows what its public - * socket is. */ - if(0 != reg->sock.family) { - retval += encode_sock(base, idx, &(reg->sock)); - } + /* The socket in REGISTER_ACK is the socket from which the REGISTER + * arrived. This is sent back to the sender so it knows what its public + * socket is. */ + if(0 != reg->sock.family) { + retval += encode_sock(base, idx, &(reg->sock)); + } - return retval; + return retval; } @@ -450,21 +450,21 @@ int decode_REGISTER_ACK (n2n_REGISTER_ACK_t *reg, size_t *rem, size_t *idx) { - size_t retval = 0; - memset(reg, 0, sizeof(n2n_REGISTER_ACK_t)); + size_t retval = 0; + memset(reg, 0, sizeof(n2n_REGISTER_ACK_t)); - retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); - retval += decode_mac(reg->dstMac, base, rem, idx); - retval += decode_mac(reg->srcMac, base, rem, idx); + retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_mac(reg->dstMac, base, rem, idx); + retval += decode_mac(reg->srcMac, base, rem, idx); - /* The socket in REGISTER_ACK is the socket from which the REGISTER - * arrived. This is sent back to the sender so it knows what its public - * socket is. */ - if(cmn->flags & N2N_FLAGS_SOCKET) { - retval += decode_sock(&(reg->sock), base, rem, idx); - } + /* The socket in REGISTER_ACK is the socket from which the REGISTER + * arrived. This is sent back to the sender so it knows what its public + * socket is. */ + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&(reg->sock), base, rem, idx); + } - return retval; + return retval; } @@ -474,19 +474,19 @@ int encode_REGISTER_SUPER_ACK (uint8_t *base, const n2n_REGISTER_SUPER_ACK_t *reg, uint8_t *tmpbuf) { - int retval = 0; + int retval = 0; - retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); - retval += encode_mac(base, idx, reg->edgeMac); - retval += encode_uint32(base, idx, reg->dev_addr.net_addr); - retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); - retval += encode_uint16(base, idx, reg->lifetime); - retval += encode_sock(base, idx, &(reg->sock)); - retval += encode_uint8(base, idx, reg->num_sn); - retval += encode_buf(base, idx, tmpbuf, (reg->num_sn*REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE)); + retval += encode_common(base, idx, common); + retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); + retval += encode_mac(base, idx, reg->edgeMac); + retval += encode_uint32(base, idx, reg->dev_addr.net_addr); + retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); + retval += encode_uint16(base, idx, reg->lifetime); + retval += encode_sock(base, idx, &(reg->sock)); + retval += encode_uint8(base, idx, reg->num_sn); + retval += encode_buf(base, idx, tmpbuf, (reg->num_sn*REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE)); - return retval; + return retval; } @@ -497,23 +497,23 @@ int decode_REGISTER_SUPER_ACK (n2n_REGISTER_SUPER_ACK_t *reg, size_t *idx, uint8_t *tmpbuf) { - size_t retval = 0; - memset(reg, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); + size_t retval = 0; + memset(reg, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); - retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); - retval += decode_mac(reg->edgeMac, base, rem, idx); - retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); - retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); - retval += decode_uint16(&(reg->lifetime), base, rem, idx); + retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_mac(reg->edgeMac, base, rem, idx); + retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); + retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); + retval += decode_uint16(&(reg->lifetime), base, rem, idx); - /* Socket is mandatory in this message type */ - retval += decode_sock(&(reg->sock), base, rem, idx); + /* Socket is mandatory in this message type */ + retval += decode_sock(&(reg->sock), base, rem, idx); - /* Following the edge socket are an array of backup supernodes. */ - retval += decode_uint8(&(reg->num_sn), base, rem, idx); - retval += decode_buf(tmpbuf, (reg->num_sn*REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE), base, rem, idx); + /* Following the edge socket are an array of backup supernodes. */ + retval += decode_uint8(&(reg->num_sn), base, rem, idx); + retval += decode_buf(tmpbuf, (reg->num_sn * REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE), base, rem, idx); - return retval; + return retval; } @@ -522,13 +522,13 @@ int encode_REGISTER_SUPER_NAK (uint8_t *base, const n2n_common_t *common, const n2n_REGISTER_SUPER_NAK_t *nak) { - int retval = 0; + int retval = 0; - retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, nak->cookie, N2N_COOKIE_SIZE); - retval += encode_mac(base, idx, nak->srcMac); + retval += encode_common(base, idx, common); + retval += encode_buf(base, idx, nak->cookie, N2N_COOKIE_SIZE); + retval += encode_mac(base, idx, nak->srcMac); - return retval; + return retval; } @@ -538,13 +538,13 @@ int decode_REGISTER_SUPER_NAK (n2n_REGISTER_SUPER_NAK_t *nak, size_t *rem, size_t *idx) { - size_t retval = 0; - memset(nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + size_t retval = 0; + memset(nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); - retval += decode_buf(nak->cookie, N2N_COOKIE_SIZE, base, rem, idx); - retval += decode_mac(nak->srcMac, base, rem, idx); + retval += decode_buf(nak->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_mac(nak->srcMac, base, rem, idx); - return retval; + return retval; } @@ -552,19 +552,19 @@ int fill_sockaddr (struct sockaddr * addr, size_t addrlen, const n2n_sock_t * sock) { - int retval = -1; + int retval = -1; - if(AF_INET == sock->family) { - if(addrlen >= sizeof(struct sockaddr_in)) { - struct sockaddr_in * si = (struct sockaddr_in *)addr; - si->sin_family = sock->family; - si->sin_port = htons(sock->port); - memcpy(&(si->sin_addr.s_addr), sock->addr.v4, IPV4_SIZE); - retval = 0; + if(AF_INET == sock->family) { + if(addrlen >= sizeof(struct sockaddr_in)) { + struct sockaddr_in * si = (struct sockaddr_in *)addr; + si->sin_family = sock->family; + si->sin_port = htons(sock->port); + memcpy(&(si->sin_addr.s_addr), sock->addr.v4, IPV4_SIZE); + retval = 0; + } } - } - return retval; + return retval; } @@ -573,18 +573,18 @@ int encode_PACKET (uint8_t * base, const n2n_common_t * common, const n2n_PACKET_t * pkt) { - int retval = 0; + int retval = 0; - retval += encode_common(base, idx, common); - retval += encode_mac(base, idx, pkt->srcMac); - retval += encode_mac(base, idx, pkt->dstMac); - if(0 != pkt->sock.family) { - retval += encode_sock(base, idx, &(pkt->sock)); - } - retval += encode_uint8(base, idx, pkt->compression); - retval += encode_uint8(base, idx, pkt->transform); + retval += encode_common(base, idx, common); + retval += encode_mac(base, idx, pkt->srcMac); + retval += encode_mac(base, idx, pkt->dstMac); + if(0 != pkt->sock.family) { + retval += encode_sock(base, idx, &(pkt->sock)); + } + retval += encode_uint8(base, idx, pkt->compression); + retval += encode_uint8(base, idx, pkt->transform); - return retval; + return retval; } @@ -594,20 +594,20 @@ int decode_PACKET (n2n_PACKET_t * pkt, size_t * rem, size_t * idx) { - size_t retval = 0; - memset(pkt, 0, sizeof(n2n_PACKET_t)); + size_t retval = 0; + memset(pkt, 0, sizeof(n2n_PACKET_t)); - retval += decode_mac(pkt->srcMac, base, rem, idx); - retval += decode_mac(pkt->dstMac, base, rem, idx); + retval += decode_mac(pkt->srcMac, base, rem, idx); + retval += decode_mac(pkt->dstMac, base, rem, idx); - if(cmn->flags & N2N_FLAGS_SOCKET) { - retval += decode_sock(&(pkt->sock), base, rem, idx); - } + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&(pkt->sock), base, rem, idx); + } - retval += decode_uint8(&(pkt->compression), base, rem, idx); - retval += decode_uint8(&(pkt->transform), base, rem, idx); + retval += decode_uint8(&(pkt->compression), base, rem, idx); + retval += decode_uint8(&(pkt->transform), base, rem, idx); - return retval; + return retval; } @@ -616,16 +616,16 @@ int encode_PEER_INFO (uint8_t *base, const n2n_common_t *common, const n2n_PEER_INFO_t *pkt) { - int retval = 0; + int retval = 0; - retval += encode_common(base, idx, common); - retval += encode_uint16(base, idx, pkt->aflags); - retval += encode_mac(base, idx, pkt->srcMac); - retval += encode_mac(base, idx, pkt->mac); - retval += encode_sock(base, idx, &pkt->sock); - retval += encode_buf(base, idx, &pkt->data, sizeof(SN_SELECTION_CRITERION_DATA_TYPE)); + retval += encode_common(base, idx, common); + retval += encode_uint16(base, idx, pkt->aflags); + retval += encode_mac(base, idx, pkt->srcMac); + retval += encode_mac(base, idx, pkt->mac); + retval += encode_sock(base, idx, &pkt->sock); + retval += encode_buf(base, idx, &pkt->data, sizeof(SN_SELECTION_CRITERION_DATA_TYPE)); - return retval; + return retval; } @@ -635,16 +635,16 @@ int decode_PEER_INFO (n2n_PEER_INFO_t *pkt, size_t *rem, size_t *idx) { - size_t retval = 0; - memset(pkt, 0, sizeof(n2n_PEER_INFO_t)); + size_t retval = 0; + memset(pkt, 0, sizeof(n2n_PEER_INFO_t)); - retval += decode_uint16(&(pkt->aflags), base, rem, idx); - retval += decode_mac(pkt->srcMac, base, rem, idx); - retval += decode_mac(pkt->mac, base, rem, idx); - retval += decode_sock(&pkt->sock, base, rem, idx); - retval += decode_buf((uint8_t*)&pkt->data, sizeof(SN_SELECTION_CRITERION_DATA_TYPE), base, rem, idx); + retval += decode_uint16(&(pkt->aflags), base, rem, idx); + retval += decode_mac(pkt->srcMac, base, rem, idx); + retval += decode_mac(pkt->mac, base, rem, idx); + retval += decode_sock(&pkt->sock, base, rem, idx); + retval += decode_buf((uint8_t*)&pkt->data, sizeof(SN_SELECTION_CRITERION_DATA_TYPE), base, rem, idx); - return retval; + return retval; } @@ -653,13 +653,13 @@ int encode_QUERY_PEER (uint8_t * base, const n2n_common_t * common, const n2n_QUERY_PEER_t * pkt) { - int retval = 0; + int retval = 0; - retval += encode_common(base, idx, common); - retval += encode_mac(base, idx, pkt->srcMac); - retval += encode_mac(base, idx, pkt->targetMac); + retval += encode_common(base, idx, common); + retval += encode_mac(base, idx, pkt->srcMac); + retval += encode_mac(base, idx, pkt->targetMac); - return retval; + return retval; } int decode_QUERY_PEER (n2n_QUERY_PEER_t * pkt, @@ -668,11 +668,11 @@ int decode_QUERY_PEER (n2n_QUERY_PEER_t * pkt, size_t * rem, size_t * idx) { - size_t retval = 0; - memset(pkt, 0, sizeof(n2n_QUERY_PEER_t)); + size_t retval = 0; + memset(pkt, 0, sizeof(n2n_QUERY_PEER_t)); - retval += decode_mac(pkt->srcMac, base, rem, idx); - retval += decode_mac(pkt->targetMac, base, rem, idx); + retval += decode_mac(pkt->srcMac, base, rem, idx); + retval += decode_mac(pkt->targetMac, base, rem, idx); - return retval; + return retval; }