Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4512300
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/poc-code/access-list/Makefile.am b/poc-code/access-list/Makefile.am
new file mode 100644
index 00000000..1a96a37e
--- /dev/null
+++ b/poc-code/access-list/Makefile.am
@@ -0,0 +1,4 @@
+
+test_ipcheck: test_ipcheck.c ipcheck.c
+ $(CC) -Wall -O0 -g ipcheck.c test_ipcheck.c -o test_ipcheck
+
diff --git a/poc-code/access-list/ipcheck.c b/poc-code/access-list/ipcheck.c
new file mode 100644
index 00000000..b71ac5c1
--- /dev/null
+++ b/poc-code/access-list/ipcheck.c
@@ -0,0 +1,210 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <string.h>
+#include <malloc.h>
+#include "ipcheck.h"
+
+struct ip_match_entry {
+ ipcheck_type_t type;
+ ipcheck_acceptreject_t acceptreject;
+ struct sockaddr_storage addr1; /* Actual IP address, mask top or low IP */
+ struct sockaddr_storage addr2; /* high IP address or address bitmask */
+ struct ip_match_entry *next;
+};
+
+
+/* Lists of things to match against. These are dummy structs to provide a quick list head */
+static struct ip_match_entry match_entry_head_v4;
+static struct ip_match_entry match_entry_head_v6;
+
+/*
+ * IPv4 See if the address we have matches the current match entry
+ *
+ */
+static int ip_matches_v4(struct sockaddr_storage *checkip, struct ip_match_entry *match_entry)
+{
+ struct sockaddr_in *ip_to_check;
+ struct sockaddr_in *match1;
+ struct sockaddr_in *match2;
+
+ ip_to_check = (struct sockaddr_in *)checkip;
+ match1 = (struct sockaddr_in *)&match_entry->addr1;
+ match2 = (struct sockaddr_in *)&match_entry->addr2;
+
+ switch(match_entry->type) {
+ case IPCHECK_TYPE_ADDRESS:
+ if (ip_to_check->sin_addr.s_addr == match1->sin_addr.s_addr)
+ return 1;
+ break;
+ case IPCHECK_TYPE_MASK:
+ if ((ip_to_check->sin_addr.s_addr & match2->sin_addr.s_addr) ==
+ match1->sin_addr.s_addr)
+ return 1;
+ break;
+ case IPCHECK_TYPE_RANGE:
+ if ((ntohl(ip_to_check->sin_addr.s_addr) >= ntohl(match1->sin_addr.s_addr)) &&
+ (ntohl(ip_to_check->sin_addr.s_addr) <= ntohl(match2->sin_addr.s_addr)))
+ return 1;
+ break;
+
+ }
+ return 0;
+}
+
+/* Compare two IPv6 addresses */
+static int ip6addr_cmp(struct in6_addr *a, struct in6_addr *b)
+{
+ uint64_t a_high, a_low;
+ uint64_t b_high, b_low;
+
+ /* Not sure why '&' doesn't work below, so I used '+' instead which is effectively
+ the same thing because the bottom 32bits are always zero and the value unsigned */
+ a_high = ((uint64_t)htonl(a->s6_addr32[0]) << 32) + (uint64_t)htonl(a->s6_addr32[1]);
+ a_low = ((uint64_t)htonl(a->s6_addr32[2]) << 32) + (uint64_t)htonl(a->s6_addr32[3]);
+
+ b_high = ((uint64_t)htonl(b->s6_addr32[0]) << 32) + (uint64_t)htonl(b->s6_addr32[1]);
+ b_low = ((uint64_t)htonl(b->s6_addr32[2]) << 32) + (uint64_t)htonl(b->s6_addr32[3]);
+
+ if (a_high > b_high)
+ return 1;
+ if (a_high < b_high)
+ return -1;
+
+ if (a_low > b_low)
+ return 1;
+ if (a_low < b_low)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * IPv6 See if the address we have matches the current match entry
+ *
+ */
+static int ip_matches_v6(struct sockaddr_storage *checkip, struct ip_match_entry *match_entry)
+{
+ struct sockaddr_in6 *ip_to_check;
+ struct sockaddr_in6 *match1;
+ struct sockaddr_in6 *match2;
+ int i;
+
+ ip_to_check = (struct sockaddr_in6 *)checkip;
+ match1 = (struct sockaddr_in6 *)&match_entry->addr1;
+ match2 = (struct sockaddr_in6 *)&match_entry->addr2;
+
+ switch(match_entry->type) {
+ case IPCHECK_TYPE_ADDRESS:
+ if (!memcmp(ip_to_check->sin6_addr.s6_addr32, match1->sin6_addr.s6_addr32, sizeof(struct in6_addr)))
+ return 1;
+ break;
+
+ case IPCHECK_TYPE_MASK:
+ /*
+ * Note that this little loop will quit early if there is a non-match so the
+ * comparison might look backwards compared to the IPv4 one
+ */
+ for (i=sizeof(struct in6_addr)/4-1; i>=0; i--) {
+ if ((ip_to_check->sin6_addr.s6_addr32[i] & match2->sin6_addr.s6_addr32[i]) !=
+ match1->sin6_addr.s6_addr32[i])
+ return 0;
+ }
+ return 1;
+ case IPCHECK_TYPE_RANGE:
+ if ((ip6addr_cmp(&ip_to_check->sin6_addr, &match1->sin6_addr) >= 0) &&
+ (ip6addr_cmp(&ip_to_check->sin6_addr, &match2->sin6_addr) <= 0))
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+
+/*
+ * YOU ARE HERE
+ */
+int ipcheck_validate(struct sockaddr_storage *checkip)
+{
+ struct ip_match_entry *match_entry;
+ int (*match_fn)(struct sockaddr_storage *checkip, struct ip_match_entry *match_entry);
+
+ if (checkip->ss_family == AF_INET){
+ match_entry = match_entry_head_v4.next;
+ match_fn = ip_matches_v4;
+ } else {
+ match_entry = match_entry_head_v6.next;
+ match_fn = ip_matches_v6;
+ }
+ while (match_entry) {
+ if (match_fn(checkip, match_entry)) {
+ if (match_entry->acceptreject == IPCHECK_ACCEPT)
+ return 1;
+ else
+ return 0;
+ }
+ match_entry = match_entry->next;
+ }
+ return 0; /* Default reject */
+}
+
+/*
+ * Routines to manuipulate the lists
+ */
+
+void ipcheck_clear(void)
+{
+ struct ip_match_entry *match_entry;
+ struct ip_match_entry *next_match_entry;
+
+ match_entry = match_entry_head_v4.next;
+ while (match_entry) {
+ next_match_entry = match_entry->next;
+ free(match_entry);
+ match_entry = next_match_entry;
+ }
+
+ match_entry = match_entry_head_v6.next;
+ while (match_entry) {
+ next_match_entry = match_entry->next;
+ free(match_entry);
+ match_entry = next_match_entry;
+ }
+}
+
+int ipcheck_addip(struct sockaddr_storage *ip1, struct sockaddr_storage *ip2,
+ ipcheck_type_t type, ipcheck_acceptreject_t acceptreject)
+{
+ struct ip_match_entry *match_entry;
+ struct ip_match_entry *new_match_entry;
+
+ if (type == IPCHECK_TYPE_RANGE &&
+ (ip1->ss_family != ip2->ss_family))
+ return -1;
+
+ if (ip1->ss_family == AF_INET){
+ match_entry = &match_entry_head_v4;
+ } else {
+ match_entry = &match_entry_head_v6;
+ }
+
+
+ new_match_entry = malloc(sizeof(struct ip_match_entry));
+ if (!new_match_entry)
+ return -1;
+
+ memcpy(&new_match_entry->addr1, ip1, sizeof(struct sockaddr_storage));
+ memcpy(&new_match_entry->addr2, ip2, sizeof(struct sockaddr_storage));
+ new_match_entry->type = type;
+ new_match_entry->acceptreject = acceptreject;
+ new_match_entry->next = NULL;
+
+ /* Find the end of the list */
+ /* is this OK, or should we use a doubly-linked list or bulk-load API call? */
+ while (match_entry->next) {
+ match_entry = match_entry->next;
+ }
+ match_entry->next = new_match_entry;
+
+ return 0;
+}
diff --git a/poc-code/access-list/ipcheck.h b/poc-code/access-list/ipcheck.h
new file mode 100644
index 00000000..c7b3fee6
--- /dev/null
+++ b/poc-code/access-list/ipcheck.h
@@ -0,0 +1,10 @@
+
+
+typedef enum {IPCHECK_TYPE_ADDRESS, IPCHECK_TYPE_MASK, IPCHECK_TYPE_RANGE} ipcheck_type_t;
+typedef enum {IPCHECK_ACCEPT, IPCHECK_REJECT} ipcheck_acceptreject_t;
+
+int ipcheck_validate(struct sockaddr_storage *checkip);
+
+void ipcheck_clear(void);
+int ipcheck_addip(struct sockaddr_storage *ip1, struct sockaddr_storage *ip2,
+ ipcheck_type_t type, ipcheck_acceptreject_t acceptreject);
diff --git a/poc-code/access-list/test_ipcheck.c b/poc-code/access-list/test_ipcheck.c
new file mode 100644
index 00000000..9c814748
--- /dev/null
+++ b/poc-code/access-list/test_ipcheck.c
@@ -0,0 +1,185 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <malloc.h>
+#include "ipcheck.h"
+
+/* This is a test program .. remember! */
+#define BUFLEN 1024
+
+static int get_ipaddress(char *buf, struct sockaddr_storage *addr)
+{
+ struct addrinfo *info;
+ struct addrinfo hints;
+ int res;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+
+ res = getaddrinfo(buf, NULL, &hints, &info);
+ if (!res) {
+ memcpy(addr, info->ai_addr, info->ai_addrlen);
+ free(info);
+ }
+ return res;
+}
+
+static int read_address(char *buf, struct sockaddr_storage *addr)
+{
+ return get_ipaddress(buf, addr);
+}
+
+static int read_mask(char *buf, struct sockaddr_storage *addr, struct sockaddr_storage *addr2)
+{
+ char tmpbuf[BUFLEN];
+ char *slash;
+ int ret;
+
+ slash = strchr(buf, '/');
+ if (!slash)
+ return 1;
+
+ strncpy(tmpbuf, buf, slash-buf);
+ tmpbuf[slash-buf] = '\0';
+
+ ret = get_ipaddress(tmpbuf, addr);
+ if (ret)
+ return ret;
+
+ ret = get_ipaddress(slash+1, addr2);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int read_range(char *buf, struct sockaddr_storage *addr1, struct sockaddr_storage *addr2)
+{
+ char tmpbuf[BUFLEN];
+ char *hyphen;
+ int ret;
+
+ hyphen = strchr(buf, '-');
+ if (!hyphen)
+ return 1;
+
+ strncpy(tmpbuf, buf, hyphen-buf);
+ tmpbuf[hyphen-buf] = '\0';
+
+ ret = get_ipaddress(tmpbuf, addr1);
+ if (ret)
+ return ret;
+
+ ret = get_ipaddress(hyphen+1, addr2);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+
+static int load_file()
+{
+ FILE *filterfile;
+ char filebuf[BUFLEN];
+ int line = 0;
+ int ret;
+ ipcheck_type_t type;
+ ipcheck_acceptreject_t acceptreject;
+ struct sockaddr_storage addr1;
+ struct sockaddr_storage addr2;
+
+ ipcheck_clear();
+
+ filterfile = fopen("test_ipcheck.txt", "r");
+ if (!filterfile) {
+ fprintf(stderr, "Cannot open test_ipcheck.txt\n");
+ return 1;
+ }
+
+ while (fgets(filebuf, sizeof(filebuf), filterfile)) {
+ filebuf[strlen(filebuf)-1] = '\0'; /* remove trailing LF */
+ line++;
+
+ /*
+ * First char is A (accept) or R (Reject)
+ */
+ switch(filebuf[0] & 0x5F) {
+ case 'A':
+ acceptreject = IPCHECK_ACCEPT;
+ break;
+ case 'R':
+ acceptreject = IPCHECK_REJECT;
+ break;
+ default:
+ fprintf(stderr, "Unknown record type on line %d: %s\n", line, filebuf);
+ goto next_record;
+ }
+
+ /*
+ * Second char is the filter type:
+ * A Address
+ * M Mask
+ * R Range
+ */
+ switch(filebuf[1] & 0x5F) {
+ case 'A':
+ type = IPCHECK_TYPE_ADDRESS;
+ ret = read_address(filebuf+2, &addr1);
+ break;
+ case 'M':
+ type = IPCHECK_TYPE_MASK;
+ ret = read_mask(filebuf+2, &addr1, &addr2);
+ break;
+ case 'R':
+ type = IPCHECK_TYPE_RANGE;
+ ret = read_range(filebuf+2, &addr1, &addr2);
+ break;
+ default:
+ fprintf(stderr, "Unknown filter type on line %d: %s\n", line, filebuf);
+ goto next_record;
+ break;
+ }
+ if (ret) {
+ fprintf(stderr, "Failed to parse address on line %d: %s\n", line, filebuf);
+ }
+ else {
+ ipcheck_addip(&addr1, &addr2, type, acceptreject);
+ }
+ next_record: {} /* empty statement to mollify the compiler */
+ }
+ fclose(filterfile);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_storage saddr;
+ int ret;
+ int i;
+
+ if (load_file())
+ return 1;
+
+ for (i=1; i<argc; i++) {
+ ret = get_ipaddress(argv[i], &saddr);
+ if (ret) {
+ fprintf(stderr, "Cannot parse address %s\n", argv[i]);
+ }
+ else {
+ if (ipcheck_validate(&saddr)) {
+ printf("%s is VALID\n", argv[i]);
+ }
+ else {
+ printf("%s is not allowed\n", argv[i]);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/poc-code/access-list/test_ipcheck.txt b/poc-code/access-list/test_ipcheck.txt
new file mode 100644
index 00000000..5776d54f
--- /dev/null
+++ b/poc-code/access-list/test_ipcheck.txt
@@ -0,0 +1,8 @@
+AA192.168.1.1
+AA192.168.1.2
+RA192.168.0.3
+AR192.168.0.0-192.168.0.250
+AM192.168.2.0/255.255.255.0
+AM1740::0/FFF0::0
+RA1000::666
+AR1000::1-2000::7FF
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 25, 4:53 AM (1 d, 19 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952210
Default Alt Text
(11 KB)
Attached To
Mode
rK kronosnet
Attached
Detach File
Event Timeline
Log In to Comment