From 89c3271368cd2807e1976f8dc7314bbe4ca32b27 Mon Sep 17 00:00:00 2001 From: BtbN Date: Tue, 15 Jan 2013 15:27:44 +0100 Subject: [PATCH] Convert prefix to a , seperated list of multiple prefixes --- src/access.c | 246 +++++++++++++++++++++++++++++++-------------------- src/access.h | 21 +++-- 2 files changed, 163 insertions(+), 104 deletions(-) diff --git a/src/access.c b/src/access.c index 4be611df..514e8707 100644 --- a/src/access.c +++ b/src/access.c @@ -155,6 +155,7 @@ access_ticket_verify(const char *id, const char *resource) static int netmask_verify(access_entry_t *ae, struct sockaddr *src) { + access_ipmask_t *ai; int isv4v6 = 0; uint32_t v4v6 = 0; @@ -169,45 +170,48 @@ netmask_verify(access_entry_t *ae, struct sockaddr *src) } } - if(ae->ae_ipv6 == 0 && src->sa_family == AF_INET) + LIST_FOREACH(ai, &ae->ae_ipmasks, ai_link) { - struct sockaddr_in *in4 = (struct sockaddr_in *)src; - uint32_t b = ntohl(in4->sin_addr.s_addr); - return (b & ae->ae_netmask) == ae->ae_network; - } - else if(ae->ae_ipv6 == 0 && isv4v6) - { - return (v4v6 & ae->ae_netmask) == ae->ae_network; - } - else if(ae->ae_ipv6 && isv4v6) - { - return 0; - } - else if(ae->ae_ipv6 && 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*)ae->ae_ip6.s6_addr; - int slen = ae->ae_prefixlen; - uint32_t apos = 0; - uint8_t lastMask = (0xFFu << (8 - (slen % 8))); - - if(slen < 0 || slen > 128) - return 0; - - while(slen >= 8) + if(ai->ai_ipv6 == 0 && src->sa_family == AF_INET) { - if(a8[apos] != m8[apos]) - return 0; - - apos += 1; - slen -= 8; + 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) + return 1; } + else if(ai->ai_ipv6 == 0 && isv4v6) + { + if((v4v6 & ai->ai_netmask) == ai->ai_network) + return 1; + } + else if(ai->ai_ipv6 && isv4v6) + { + continue; + } + else if(ai->ai_ipv6 && 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; + int slen = ai->ai_prefixlen; + uint32_t apos = 0; + uint8_t lastMask = (0xFFu << (8 - (slen % 8))); - if(slen == 0) - return 1; + if(slen < 0 || slen > 128) + continue; - return (a8[apos] & lastMask) == (m8[apos] & lastMask); + while(slen >= 8) + { + if(a8[apos] != m8[apos]) + continue; + + apos += 1; + slen -= 8; + } + + if(slen == 0 || (a8[apos] & lastMask) == (m8[apos] & lastMask)) + return 1; + } } return 0; @@ -351,56 +355,89 @@ static void access_set_prefix(access_entry_t *ae, const char *prefix) { char buf[100]; + char tokbuf[4096]; int prefixlen; - char *p; + char *p, *tok, *saveptr; + access_ipmask_t *ai; - if(strlen(prefix) > 90) - return; - - strcpy(buf, prefix); - - if(strchr(buf, ':') != NULL) - ae->ae_ipv6 = 1; - else - ae->ae_ipv6 = 0; - - if(ae->ae_ipv6) + while((ai = LIST_FIRST(&ae->ae_ipmasks)) != NULL) { - p = strchr(buf, '/'); - if(p) - { - *p++ = 0; - prefixlen = atoi(p); - if(prefixlen > 128) - return; - } else { - prefixlen = 128; - } - - ae->ae_prefixlen = prefixlen; - inet_pton(AF_INET6, buf, &ae->ae_ip6); - - ae->ae_netmask = 0xffffffff; - ae->ae_network = 0x00000000; + LIST_REMOVE(ai, ai_link); + free(ai); } - else + + strncpy(tokbuf, prefix, 4095); + tokbuf[4095] = 0; + tok = strtok_r(tokbuf, ",;| ", &saveptr); + + while(tok != NULL) { - p = strchr(buf, '/'); - if(p) + ai = calloc(1, sizeof(access_ipmask_t)); + + if(strlen(tok) > 90 || strlen(tok) == 0) { - *p++ = 0; - prefixlen = atoi(p); - if(prefixlen > 32) - return; - } else { - prefixlen = 32; + free(ai); + tok = strtok_r(NULL, ",;| ", &saveptr); + continue; } - ae->ae_ip.s_addr = inet_addr(buf); - ae->ae_prefixlen = prefixlen; + strcpy(buf, tok); - ae->ae_netmask = prefixlen ? 0xffffffff << (32 - prefixlen) : 0; - ae->ae_network = ntohl(ae->ae_ip.s_addr) & ae->ae_netmask; + if(strchr(buf, ':') != NULL) + ai->ai_ipv6 = 1; + else + ai->ai_ipv6 = 0; + + if(ai->ai_ipv6) + { + p = strchr(buf, '/'); + if(p) + { + *p++ = 0; + prefixlen = atoi(p); + if(prefixlen > 128) + { + free(ai); + tok = strtok_r(NULL, ",;| ", &saveptr); + continue; + } + } else { + prefixlen = 128; + } + + ai->ai_prefixlen = prefixlen; + inet_pton(AF_INET6, buf, &ai->ai_ip6); + + ai->ai_netmask = 0xffffffff; + ai->ai_network = 0x00000000; + } + else + { + p = strchr(buf, '/'); + if(p) + { + *p++ = 0; + prefixlen = atoi(p); + if(prefixlen > 32) + { + free(ai); + tok = strtok_r(NULL, ",;| ", &saveptr); + continue; + } + } else { + prefixlen = 32; + } + + ai->ai_ip.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; + } + + LIST_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link); + + tok = strtok_r(NULL, ",;| ", &saveptr); } } @@ -450,6 +487,14 @@ access_entry_find(const char *id, int create) static void access_entry_destroy(access_entry_t *ae) { + access_ipmask_t *ai; + + while((ai = LIST_FIRST(&ae->ae_ipmasks)) != NULL) + { + LIST_REMOVE(ai, ai_link); + free(ai); + } + free(ae->ae_id); free(ae->ae_username); free(ae->ae_password); @@ -465,8 +510,12 @@ static htsmsg_t * access_record_build(access_entry_t *ae) { htsmsg_t *e = htsmsg_create_map(); + access_ipmask_t *ai; char addrbuf[50]; - char buf[100]; + char buf[4096]; + int pos = 0; + + memset(buf, 0, 4096); htsmsg_add_u32(e, "enabled", !!ae->ae_enabled); @@ -474,14 +523,22 @@ access_record_build(access_entry_t *ae) htsmsg_add_str(e, "password", ae->ae_password); htsmsg_add_str(e, "comment", ae->ae_comment); - if(ae->ae_ipv6) + LIST_FOREACH(ai, &ae->ae_ipmasks, ai_link) { - inet_ntop(AF_INET6, &ae->ae_ip6, addrbuf, 50); - snprintf(buf, sizeof(buf), "%s/%d", addrbuf, ae->ae_prefixlen); + if(sizeof(buf)-pos <= 0) + break; + + if(ai->ai_ipv6) + { + inet_ntop(AF_INET6, &ai->ai_ip6, addrbuf, 50); + 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); + } } - else - snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(ae->ae_ip), ae->ae_prefixlen); - htsmsg_add_str(e, "prefix", buf); + htsmsg_add_str(e, "prefix", buf + 1); htsmsg_add_u32(e, "streaming", ae->ae_rights & ACCESS_STREAMING ? 1 : 0); htsmsg_add_u32(e, "dvr" , ae->ae_rights & ACCESS_RECORDER ? 1 : 0); @@ -631,6 +688,7 @@ access_init(int createdefault) dtable_t *dt; htsmsg_t *r, *m; access_entry_t *ae; + access_ipmask_t *ai; const char *s; static struct { @@ -652,33 +710,25 @@ access_init(int createdefault) ae = access_entry_find(NULL, 1); free(ae->ae_comment); - ae->ae_comment = strdup("Default IPv6 access entry"); + ae->ae_comment = strdup("Default access entry"); ae->ae_enabled = 1; ae->ae_rights = 0xffffffff; - ae->ae_ipv6 = 1; + ai = calloc(1, sizeof(access_ipmask_t)); + ai->ai_ipv6 = 0; + LIST_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link); - r = access_record_build(ae); - dtable_record_store(dt, ae->ae_id, r); - htsmsg_destroy(r); - - ae = access_entry_find(NULL, 1); - - free(ae->ae_comment); - ae->ae_comment = strdup("Default IPv4 access entry"); - - ae->ae_enabled = 1; - ae->ae_rights = 0xffffffff; - - ae->ae_ipv6 = 0; + ai = calloc(1, sizeof(access_ipmask_t)); + ai->ai_ipv6 = 1; + LIST_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link); r = access_record_build(ae); dtable_record_store(dt, ae->ae_id, r); htsmsg_destroy(r); tvhlog(LOG_WARNING, "accesscontrol", - "Created default wide open access controle entrys"); + "Created default wide open access controle entry"); } /* Load superuser account */ diff --git a/src/access.h b/src/access.h index 3562b0ac..466e380f 100644 --- a/src/access.h +++ b/src/access.h @@ -20,6 +20,20 @@ #define ACCESS_H_ +typedef struct access_ipmask { + LIST_ENTRY(access_ipmask) ai_link; + + int ai_ipv6; + + struct in_addr ai_ip; + struct in6_addr ai_ip6; + + int ai_prefixlen; + + uint32_t ai_network; + uint32_t ai_netmask; +} access_ipmask_t; + TAILQ_HEAD(access_entry_queue, access_entry); extern struct access_entry_queue access_entries; @@ -31,17 +45,12 @@ typedef struct access_entry { char *ae_username; char *ae_password; char *ae_comment; - int ae_ipv6; - struct in_addr ae_ip; - struct in6_addr ae_ip6; - int ae_prefixlen; int ae_enabled; uint32_t ae_rights; - uint32_t ae_network; /* derived from ae_ip */ - uint32_t ae_netmask; /* derived from ae_prefixlen */ + LIST_HEAD(, access_ipmask) ae_ipmasks; } access_entry_t; TAILQ_HEAD(access_ticket_queue, access_ticket);