utils: fix ipv4 checksum issue
[project/unetd.git] / network.c
index cb3e94b5e03e91931c497524fc3cad98d95fa279..0578ad0c70205c4824a978ed2bdf8746065c7dd8 100644 (file)
--- a/network.c
+++ b/network.c
@@ -32,6 +32,7 @@ enum {
        NETCONF_ATTR_PORT,
        NETCONF_ATTR_PEX_PORT,
        NETCONF_ATTR_KEEPALIVE,
+       NETCONF_ATTR_STUN_SERVERS,
        __NETCONF_ATTR_MAX
 };
 
@@ -40,6 +41,7 @@ static const struct blobmsg_policy netconf_policy[__NETCONF_ATTR_MAX] = {
        [NETCONF_ATTR_PORT] = { "port", BLOBMSG_TYPE_INT32 },
        [NETCONF_ATTR_PEX_PORT] = { "peer-exchange-port", BLOBMSG_TYPE_INT32 },
        [NETCONF_ATTR_KEEPALIVE] = { "keepalive", BLOBMSG_TYPE_INT32 },
+       [NETCONF_ATTR_STUN_SERVERS] = { "stun-servers", BLOBMSG_TYPE_ARRAY },
 };
 
 const struct blobmsg_policy network_policy[__NETWORK_ATTR_MAX] = {
@@ -61,6 +63,15 @@ const struct blobmsg_policy network_policy[__NETWORK_ATTR_MAX] = {
 AVL_TREE(networks, avl_strcmp, false, NULL);
 static struct blob_buf b;
 
+static void network_load_stun_servers(struct network *net, struct blob_attr *data)
+{
+       struct blob_attr *cur;
+       int rem;
+
+       blobmsg_for_each_attr(cur, data, rem)
+               network_stun_server_add(net, blobmsg_get_string(cur));
+}
+
 static void network_load_config_data(struct network *net, struct blob_attr *data)
 {
        struct blob_attr *tb[__NETCONF_ATTR_MAX];
@@ -95,6 +106,10 @@ static void network_load_config_data(struct network *net, struct blob_attr *data
                net->net_config.keepalive = blobmsg_get_u32(cur);
        else
                net->net_config.keepalive = 0;
+
+       if ((cur = tb[NETCONF_ATTR_STUN_SERVERS]) != NULL &&
+           blobmsg_check_array(cur, BLOBMSG_TYPE_STRING) > 0)
+               network_load_stun_servers(net, cur);
 }
 
 static int network_load_data(struct network *net, struct blob_attr *data)
@@ -348,6 +363,84 @@ network_fill_subnets(struct network *net, struct blob_buf *buf)
        __network_fill_subnets(net, buf, true);
 }
 
+static bool
+__network_skip_endpoint_route(struct network *net, struct network_host *host,
+                             union network_endpoint *ep)
+{
+       bool ipv6 = ep->sa.sa_family == AF_INET6;
+       uint32_t *subnet32, *addr32, mask32;
+       union network_addr addr = {};
+       struct blob_attr *cur;
+       int mask, rem;
+
+       blobmsg_for_each_attr(cur, host->peer.ipaddr, rem) {
+               const char *str = blobmsg_get_string(cur);
+
+               if (!!strchr(str, ':') != ipv6)
+                       continue;
+
+               if (inet_pton(ep->sa.sa_family, str, &addr) != 1)
+                       continue;
+
+               if (ipv6) {
+                       if (!memcmp(&addr.in6, &ep->in6.sin6_addr, sizeof(addr.in6)))
+                               return true;
+               } else {
+                       if (!memcmp(&addr.in, &ep->in.sin_addr, sizeof(addr.in)))
+                               return true;
+               }
+       }
+
+       if (ipv6)
+               addr32 = (uint32_t *)&ep->in6.sin6_addr;
+       else
+               addr32 = (uint32_t *)&ep->in.sin_addr;
+
+       subnet32 = (uint32_t *)&addr;
+       blobmsg_for_each_attr(cur, host->peer.subnet, rem) {
+               const char *str = blobmsg_get_string(cur);
+               int i;
+
+               if (!!strchr(str, ':') != ipv6)
+                       continue;
+
+               if (network_get_subnet(ep->sa.sa_family, &addr, &mask, str))
+                       continue;
+
+               if (mask <= 1)
+                       continue;
+
+               for (i = 0; i < (ipv6 ? 4 : 1); i++) {
+                       int cur_mask = mask > 32 ? 32 : mask;
+
+                       if (mask > 32)
+                               mask -= 32;
+                       else
+                               mask = 0;
+
+                       mask32 = ~0ULL << (32 - cur_mask);
+                       if (ntohl(subnet32[i] ^ addr32[i]) & mask32)
+                               continue;
+               }
+
+               return true;
+       }
+
+       return false;
+}
+
+bool network_skip_endpoint_route(struct network *net, union network_endpoint *ep)
+{
+       struct network_host *host;
+
+       avl_for_each_element(&net->hosts, host, node)
+               if (__network_skip_endpoint_route(net, host, ep))
+                       return true;
+
+       return false;
+}
+
+
 static void
 network_do_update(struct network *net, bool up)
 {
@@ -398,6 +491,7 @@ static void network_reload(struct uloop_timeout *t)
 
        memset(&net->net_config, 0, sizeof(net->net_config));
 
+       network_stun_free(net);
        network_pex_close(net);
        network_services_free(net);
        network_hosts_update_start(net);
@@ -424,6 +518,8 @@ static void network_reload(struct uloop_timeout *t)
        unetd_write_hosts();
        network_do_update(net, true);
        network_pex_open(net);
+       network_stun_start(net);
+       unetd_ubus_notify(net);
 }
 
 void network_soft_reload(struct network *net)
@@ -468,6 +564,7 @@ static void network_teardown(struct network *net)
        uloop_timeout_cancel(&net->connect_timer);
        uloop_timeout_cancel(&net->reload_timer);
        network_do_update(net, false);
+       network_stun_free(net);
        network_pex_close(net);
        network_pex_free(net);
        network_hosts_free(net);
@@ -599,6 +696,7 @@ network_alloc(const char *name)
        avl_insert(&networks, &net->node);
 
        network_pex_init(net);
+       network_stun_init(net);
        network_hosts_init(net);
        network_services_init(net);