+/* IPNode.c - NeonServ v5.3
+ * Copyright (C) 2011-2012 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "IPNode.h"
+
+#define hex2dec(x) (isxdigit(x) ? (isdigit(x) ? x - '0' : (isupper(x) ? x - 'A' : x - 'a') + 10) : 0)
+
+static struct IPNode *parseIP(struct IPNode *ip, const char *org_ipstr);
+
+struct IPNode *createIPNode(const char *ipstr) {
+ struct IPNode *ip = malloc(sizeof(*ip));
+ if(!ip) return NULL;
+ ip->flags = 0;
+ if(!parseIP(ip, ipstr)) {
+ free(ip);
+ ip = NULL;
+ }
+ return ip;
+}
+
+static struct IPNode *parseIP(struct IPNode *ip, const char *org_ipstr) {
+ char ipstr[strlen(org_ipstr)+1];
+ strcpy(ipstr, org_ipstr);
+ if(strchr(ipstr, ':')) {
+ ip->flags |= IPNODE_IS_IPV6;
+ char *p1 = ipstr;
+ char *p2;
+ int blocks = 1;
+ while(*p1) {
+ if(p1[0] == ':' && p1[1] == ':') {
+ //double ::
+ p1++;
+ }
+ if(*p1 == ':')
+ blocks++;
+ if(*p1 == '/') {
+ *p1 = '\0';
+ break;
+ }
+ p1++;
+ }
+ if(blocks > 8) return 0;
+ char hexa[32];
+ int i;
+ for(i = 0; i < 32; i++)
+ hexa[i] = '0';
+ i = 0;
+ int p = 0;
+ int len;
+ while(*p1) {
+ if(p1[0] == ':' && p1[1] == ':') {
+ i = 8 - blocks;
+ p1 += 2;
+ p = 0;
+ p2 = p1;
+ len = 0;
+ while(*p2 && *p2 != ':') {
+ len++;
+ p2++;
+ }
+ continue;
+ }
+ else if(*p1 == ':') {
+ p1++;
+ i++;
+ p = 0;
+ len = 0;
+ while(*p2 && *p2 != ':') {
+ len++;
+ p2++;
+ }
+ continue;
+ }
+ if(p >= 4 || i >= 8) return NULL;
+ hexa[i*4 + ((4-len) + (p++))] = *p1;
+ p1++;
+ }
+ for(i = 0, p = 0; i < 32; i+=2, p++) {
+ ip->ipdata[p] = hex2dec(hexa[i]) << 4;
+ ip->ipdata[p] |= hex2dec(hexa[i+1]);
+ }
+ } else if(strchr(ipstr, '.')) {
+ char *ippart = ipstr;
+ char *next = strchr(ipstr, '/');
+ int i = 0;
+ if(next) {
+ *next = '\0';
+ next = NULL;
+ }
+ do {
+ next = strchr(ippart, '.');
+ if(next) *next = '\0';
+ if(i >= 4) return NULL;
+ ip->ipdata[12+(i++)] = (unsigned char) atoi(ippart);
+ if(next) {
+ ippart = next+1;
+ continue;
+ }
+ break;
+ } while(1);
+ if(i != 3) return NULL;
+ } else
+ return NULL;
+ return ip;
+}
+
+int ipmatch(struct IPNode *ip1, struct IPNode *ip2, int bits) {
+ if(!bits) return 0;
+ bits = (ip2->flags & IPNODE_IS_IPV6 ? bits : bits + (12*8));
+ if(bits > 128) return 1;
+ int sbit = (bits % 8);
+ int check = (bits / 8) + (sbit ? 1 : 0);
+ int i;
+ for(i = 0; i < check; i++) {
+ if(i == check-1 && sbit) {
+ int bitmask = 0;
+ int j = 0;
+ for(;j < sbit; j++) {
+ bitmask <<= 1;
+ bitmask |= 1;
+ }
+ for(;j < 8; j++) {
+ bitmask <<= 1;
+ bitmask |= 0;
+ }
+ if((ip1->ipdata[i] & bitmask) != (ip2->ipdata[i] & bitmask))
+ return 1;
+ } else if(ip1->ipdata[i] != ip2->ipdata[i])
+ return 1;
+ }
+ return 0;
+}
+
+void freeIPNode(struct IPNode *ip) {
+ free(ip);
+}
+