]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
ACL: Rewrite a bit the IP address parsing and handling
authorJaroslav Kysela <perex@perex.cz>
Tue, 16 Sep 2014 18:30:18 +0000 (20:30 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 16 Sep 2014 18:30:18 +0000 (20:30 +0200)
src/access.c
src/access.h

index a2dfc7b9139aa9f7811d63c66d553bfb9db0ac86..41547d5cab78032844c058a2aa3d6c8a29c618e3 100644 (file)
@@ -179,37 +179,35 @@ netmask_verify(access_entry_t *ae, struct sockaddr *src)
   int isv4v6 = 0;
   uint32_t v4v6 = 0;
   
-  if(src->sa_family == AF_INET6)
-  {
+  if (src->sa_family == AF_INET6) {
     struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr);
     uint32_t *a32 = (uint32_t*)in6->s6_addr;
-    if(a32[0] == 0 && a32[1] == 0 && ntohl(a32[2]) == 0x0000FFFFu)
-    {
+    if (a32[0] == 0 && a32[1] == 0 && ntohl(a32[2]) == 0x0000FFFFu) {
       isv4v6 = 1;
       v4v6 = ntohl(a32[3]);
     }
   }
 
-  TAILQ_FOREACH(ai, &ae->ae_ipmasks, ai_link)
-  {
-    if(ai->ai_ipv6 == 0 && src->sa_family == AF_INET)
-    {
+  TAILQ_FOREACH(ai, &ae->ae_ipmasks, ai_link) {
+
+    if (ai->ai_family == AF_INET && src->sa_family == AF_INET) {
+
       struct sockaddr_in *in4 = (struct sockaddr_in *)src;
       uint32_t b = ntohl(in4->sin_addr.s_addr);
-      if((b & ai->ai_netmask) == ai->ai_network)
+      if ((b & ai->ai_netmask) == ai->ai_network)
         return 1;
-    }
-    else if(ai->ai_ipv6 == 0 && isv4v6)
-    {
+
+    } else if (ai->ai_family == AF_INET && isv4v6) {
+
       if((v4v6 & ai->ai_netmask) == ai->ai_network)
         return 1;
-    }
-    else if(ai->ai_ipv6 && isv4v6)
-    {
+
+    } else if (ai->ai_family == AF_INET6 && isv4v6) {
+
       continue;
-    }
-    else if(ai->ai_ipv6 && src->sa_family == AF_INET6)
-    {
+
+    } else if (ai->ai_family == AF_INET6 && src->sa_family == AF_INET6) {
+
       struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr);
       uint8_t *a8 = (uint8_t*)in6->s6_addr;
       uint8_t *m8 = (uint8_t*)ai->ai_ip6.s6_addr;
@@ -496,69 +494,101 @@ access_set_prefix_default(access_entry_t *ae)
   access_ipmask_t *ai;
 
   ai = calloc(1, sizeof(access_ipmask_t));
-  ai->ai_ipv6 = 1;
+  ai->ai_family = AF_INET6;
   TAILQ_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link);
 
   ai = calloc(1, sizeof(access_ipmask_t));
-  ai->ai_ipv6 = 0;
+  ai->ai_family = AF_INET;
   TAILQ_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link);
 }
 
+/**
+ *
+ */
+static int access_addr4_empty(const char *s)
+{
+  int empty = 1;
+  while (*s) {
+    if (*s == '0') {
+      /* nothing */
+    } else if (isdigit(*s)) {
+      empty = 0;
+    } else if (*s == '.') {
+      empty = 0;
+    } else {
+      return 1;
+    }
+    s++;
+  }
+  return empty;
+}
+
+/**
+ *
+ */
+static int access_addr6_empty(const char *s)
+{
+  int empty = 1;
+  while (*s) {
+    if (*s == '0') {
+      /* nothing */
+    } else if (isdigit(*s)) {
+      empty = 0;
+    } else if (*s == ':') {
+      empty = 0;
+    } else {
+      return 1;
+    }
+    s++;
+  }
+  return empty;
+}
+
 /**
  *
  */
 static void
 access_set_prefix(access_entry_t *ae, const char *prefix)
 {
+  static const char *delim = ",;| ";
   char buf[100];
   char tokbuf[4096];
   int prefixlen;
   char *p, *tok, *saveptr;
-  access_ipmask_t *ai;
+  in_addr_t s_addr;
+  access_ipmask_t *ai = NULL;
 
-  while((ai = TAILQ_FIRST(&ae->ae_ipmasks)) != NULL)
-  {
+  while((ai = TAILQ_FIRST(&ae->ae_ipmasks)) != NULL) {
     TAILQ_REMOVE(&ae->ae_ipmasks, ai, ai_link);
     free(ai);
   }
 
-  strncpy(tokbuf, prefix, 4095);
-  tokbuf[4095] = 0;
-  tok = strtok_r(tokbuf, ",;| ", &saveptr);
+  strncpy(tokbuf, prefix, sizeof(tokbuf)-1);
+  tokbuf[sizeof(tokbuf) - 1] = 0;
+  tok = strtok_r(tokbuf, delim, &saveptr);
 
-  while(tok != NULL)
-  {
-    ai = calloc(1, sizeof(access_ipmask_t));
+  while (tok != NULL) {
+    if (ai == NULL)
+      ai = calloc(1, sizeof(access_ipmask_t));
 
-    if(strlen(tok) > 90 || strlen(tok) == 0)
-    {
-      free(ai);
-      tok = strtok_r(NULL, ",;| ", &saveptr);
-      continue;
-    }
+    if (strlen(tok) > sizeof(buf) - 1 || *tok == '\0')
+      goto fnext;
 
     strcpy(buf, tok);
 
-    if(strchr(buf, ':') != NULL)
-      ai->ai_ipv6 = 1;
+    if (strchr(buf, ':') != NULL)
+      ai->ai_family = AF_INET6;
     else
-      ai->ai_ipv6 = 0;
+      ai->ai_family = AF_INET;
 
-    if(ai->ai_ipv6)
-    {
-      p = strchr(buf, '/');
-      if(p)
-      {
+    if (ai->ai_family == AF_INET6) {
+      if ((p = strchr(buf, '/')) != NULL) {
         *p++ = 0;
         prefixlen = atoi(p);
-        if(prefixlen > 128)
-        {
-          free(ai);
-          tok = strtok_r(NULL, ",;| ", &saveptr);
-          continue;
-        }
+        if (prefixlen < 0 || prefixlen > 128)
+          goto fnext;
       } else {
-        prefixlen = 128;
+        prefixlen = !access_addr4_empty(buf) ? 128 : 0;
       }
 
       ai->ai_prefixlen = prefixlen;
@@ -566,34 +596,35 @@ access_set_prefix(access_entry_t *ae, const char *prefix)
 
       ai->ai_netmask = 0xffffffff;
       ai->ai_network = 0x00000000;
-    }
-    else
-    {
-      p = strchr(buf, '/');
-      if(p)
-      {
+    } else {
+      if ((p = strchr(buf, '/')) != NULL) {
         *p++ = 0;
         prefixlen = atoi(p);
-        if(prefixlen > 32)
-        {
-          free(ai);
-          tok = strtok_r(NULL, ",;| ", &saveptr);
-          continue;
-        }
+        if (prefixlen < 0 || prefixlen > 32)
+          goto fnext;
       } else {
-        prefixlen = 32;
+        prefixlen = !access_addr6_empty(buf) ? 32 : 0;
       }
 
-      ai->ai_ip.s_addr = inet_addr(buf);
+      s_addr = inet_addr(buf);
       ai->ai_prefixlen = prefixlen;
 
       ai->ai_netmask   = prefixlen ? 0xffffffff << (32 - prefixlen) : 0;
-      ai->ai_network   = ntohl(ai->ai_ip.s_addr) & ai->ai_netmask;
+      ai->ai_network   = ntohl(s_addr) & ai->ai_netmask;
     }
 
     TAILQ_INSERT_TAIL(&ae->ae_ipmasks, ai, ai_link);
+    ai = NULL;
+
+    tok = strtok_r(NULL, delim, &saveptr);
+    continue;
 
-    tok = strtok_r(NULL, ",;| ", &saveptr);
+fnext:
+    tok = strtok_r(NULL, delim, &saveptr);
+    if (tok == NULL) {
+      free(ai);
+      ai = NULL;
+    }
   }
 
   if (!TAILQ_FIRST(&ae->ae_ipmasks))
@@ -631,7 +662,6 @@ static int access_entry_class_password_set(void *o, const void *v);
 access_entry_t *
 access_entry_create(const char *uuid, htsmsg_t *conf)
 {
-  access_ipmask_t *ai;
   access_entry_t *ae, *ae2;
   const char *s;
 
@@ -671,14 +701,8 @@ access_entry_create(const char *uuid, htsmsg_t *conf)
     ae->ae_comment = strdup("New entry");
   if (ae->ae_password == NULL)
     access_entry_class_password_set(ae, "*");
-  if (TAILQ_FIRST(&ae->ae_ipmasks) == NULL) {
-    ai = calloc(1, sizeof(access_ipmask_t));
-    ai->ai_ipv6 = 1;
-    TAILQ_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link);
-    ai = calloc(1, sizeof(access_ipmask_t));
-    ai->ai_ipv6 = 0;
-    TAILQ_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link);
-  }
+  if (TAILQ_FIRST(&ae->ae_ipmasks) == NULL)
+    access_set_prefix_default(ae);
 
   access_entry_reindex();
 
@@ -845,18 +869,20 @@ access_entry_class_prefix_get(void *o)
   access_entry_t *ae = (access_entry_t *)o;
   access_ipmask_t *ai;
   size_t pos = 0;
+  uint32_t s_addr;
 
   buf[0] = buf[1] = '\0';
   TAILQ_FOREACH(ai, &ae->ae_ipmasks, ai_link)   {
     if(sizeof(buf)-pos <= 0)
       break;
 
-    if(ai->ai_ipv6) {
+    if(ai->ai_family == AF_INET6) {
       inet_ntop(AF_INET6, &ai->ai_ip6, addrbuf, sizeof(addrbuf));
-      pos += snprintf(buf+pos, sizeof(buf)-pos, ",%s/%d", addrbuf, ai->ai_prefixlen);
     } else {
-      pos += snprintf(buf+pos, sizeof(buf)-pos, ",%s/%d", inet_ntoa(ai->ai_ip), ai->ai_prefixlen);
+      s_addr = htonl(ai->ai_network);
+      inet_ntop(AF_INET, &s_addr, addrbuf, sizeof(addrbuf));
     }
+    pos += snprintf(buf+pos, sizeof(buf)-pos, ",%s/%d", addrbuf, ai->ai_prefixlen);
   }
   return &ret;
 }
index b6adad0dc99bde5c6bb371b6889cfe86cf8371a2..f93667cfa360938bd171aa4a9475ece0eccc2fa6 100644 (file)
@@ -28,15 +28,14 @@ struct channel_tag;
 typedef struct access_ipmask {
   TAILQ_ENTRY(access_ipmask) ai_link;
 
-  int ai_ipv6;
+  int ai_family;
 
-  struct in_addr ai_ip;
   struct in6_addr ai_ip6;
 
   int ai_prefixlen;
 
-  uint32_t ai_network;
   uint32_t ai_netmask;
+  uint32_t ai_network;
 } access_ipmask_t;
 
 TAILQ_HEAD(access_entry_queue, access_entry);