From 727b8a503f88131d92025bc43e3803d4a7c2aa00 Mon Sep 17 00:00:00 2001 From: pk910 Date: Thu, 12 Jan 2012 08:09:23 +0100 Subject: [PATCH] added IPNode for storing real IP's of users --- Makefile.am | 1 + src/IPNode.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++ src/IPNode.h | 33 +++++++++++ src/UserNode.c | 12 +++- src/UserNode.h | 2 + src/WHOHandler.c | 23 ++++---- src/tools.c | 23 +++++++- src/tools.h | 2 + 8 files changed, 233 insertions(+), 13 deletions(-) create mode 100644 src/IPNode.c create mode 100644 src/IPNode.h diff --git a/Makefile.am b/Makefile.am index dee97f3..1f7d907 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,7 @@ neonserv_SOURCES = src/version.c \ src/ChanUser.c \ src/ModeNode.c \ src/BanNode.c \ + src/IPNode.c \ src/WHOHandler.c \ src/modcmd.c \ src/mysqlConn.c \ diff --git a/src/IPNode.c b/src/IPNode.c new file mode 100644 index 0000000..7e1c499 --- /dev/null +++ b/src/IPNode.c @@ -0,0 +1,150 @@ +/* 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 . + */ +#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); +} + diff --git a/src/IPNode.h b/src/IPNode.h new file mode 100644 index 0000000..0b2fd29 --- /dev/null +++ b/src/IPNode.h @@ -0,0 +1,33 @@ +/* IPNode.h - 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 . + */ +#ifndef _IPNode_h +#define _IPNode_h +#include "main.h" + +#define IPNODE_IS_IPV6 0x01 +#define IPNODE_IS_LOCAL 0x02 + +struct IPNode { + unsigned char flags; + unsigned char ipdata[16]; // 16 * 8bit = 128bit +}; + +struct IPNode *createIPNode(const char *ipstr); +int ipmatch(struct IPNode *ip1, struct IPNode *ip2, int bits); +void freeIPNode(struct IPNode *ip); + +#endif \ No newline at end of file diff --git a/src/UserNode.c b/src/UserNode.c index 3f20a13..21b618d 100644 --- a/src/UserNode.c +++ b/src/UserNode.c @@ -18,6 +18,7 @@ #include "ChanUser.h" #include "tools.h" #include "IRCEvents.h" +#include "IPNode.h" static struct UserNode **userList; @@ -199,6 +200,7 @@ struct UserNode* addUser(const char *nick) { user->created = time(0); user->ident[0] = 0; user->host[0] = 0; + user->ip = NULL; user->realname[0] = 0; user->flags = 0; user->channel = NULL; @@ -255,6 +257,7 @@ struct UserNode* createTempUser(const char *nick) { } user->ident[0] = 0; user->host[0] = 0; + user->ip = NULL; user->realname[0] = 0; user->flags = 0; user->channel = NULL; @@ -299,6 +302,7 @@ struct UserNode* createTempUserMask(const char *mask) { } user->ident[0] = 0; user->host[0] = 0; + user->ip = NULL; user->realname[0] = 0; user->flags = 0; user->channel = NULL; @@ -322,6 +326,7 @@ struct UserNode* createTempUserMask(const char *mask) { user->created = time(0); user->ident[0] = 0; user->host[0] = 0; + user->ip = NULL; user->realname[0] = 0; user->flags = USERFLAG_ISSERVER; user->channel = NULL; @@ -345,6 +350,7 @@ struct UserNode* createTempUserMask(const char *mask) { user->created = time(0); user->ident[0] = 0; user->host[0] = 0; + user->ip = NULL; user->realname[0] = 0; user->flags = 0; user->channel = NULL; @@ -417,9 +423,11 @@ void delUser(struct UserNode* user, int freeUser) { removeChanUserFromLists(chanUser, 1, 0, freeUser); } } - if(freeUser) + if(freeUser) { + if(user->ip) + freeIPNode(user->ip); free(user); - else + } else user->next = NULL; } diff --git a/src/UserNode.h b/src/UserNode.h index bb794b7..bf07e7e 100644 --- a/src/UserNode.h +++ b/src/UserNode.h @@ -37,6 +37,7 @@ struct ChanUser; struct language; +struct IPNode; struct UserNode { char nick[NICKLEN+1]; @@ -44,6 +45,7 @@ struct UserNode { char host[HOSTLEN+1]; char realname[REALLEN+1]; char auth[AUTHLEN+1]; + struct IPNode *ip; unsigned int flags; time_t created, last_who; struct ChanUser *channel; diff --git a/src/WHOHandler.c b/src/WHOHandler.c index eafa62f..61f2ed2 100644 --- a/src/WHOHandler.c +++ b/src/WHOHandler.c @@ -21,6 +21,7 @@ #include "ChanUser.h" #include "ModeNode.h" #include "ClientSocket.h" +#include "IPNode.h" #define WHOQUEUETYPE_ISONQUEUE 0x01 #define WHOQUEUETYPE_USERLIST 0x02 @@ -107,7 +108,7 @@ void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *dat entry->data[0] = data; for(i = 1; i < MAXCALLBACKS; i++) entry->data[i] = NULL; - putsock(bot, "WHO %s,%d %%tuhnaf,%d", chan->name, entry->type, entry->type); + putsock(bot, "WHO %s,%d %%tuihnaf,%d", chan->name, entry->type, entry->type); } else callback(bot, chan, data); } @@ -142,7 +143,7 @@ void _get_userlist_with_invisible(struct ChanNode *chan, userlist_callback_t cal entry->data[0] = data; for(i = 1; i < MAXCALLBACKS; i++) entry->data[i] = NULL; - putsock(bot, "WHO %s,%d d%%tuhnaf,%d", chan->name, entry->type, entry->type); + putsock(bot, "WHO %s,%d d%%tuihnaf,%d", chan->name, entry->type, entry->type); } else callback(bot, chan, data); } @@ -209,8 +210,8 @@ void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int //parse flags int userflags = 0; int chanuserflags = 0; - for(i = 0; i < strlen(argv[5]); i++) { - switch (argv[5][i]) { + for(i = 0; i < strlen(argv[6]); i++) { + switch (argv[6][i]) { case '@': chanuserflags |= CHANUSERFLAG_OPPED; break; @@ -231,17 +232,17 @@ void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int } } - struct UserNode *user = getUserByNick(argv[4]); + struct UserNode *user = getUserByNick(argv[5]); struct ChanUser *chanuser; if((chanuserflags & CHANUSERFLAG_INVISIBLE) && (!user || !isBot(user))) { - user = createTempUser(argv[4]); + user = createTempUser(argv[5]); user->flags |= USERFLAG_ISTMPUSER; chan->flags |= CHANFLAG_HAVE_INVISIBLES; chanuser = addInvisibleChanUser(chan, user); chanuser->flags = (chanuser->flags & ~CHANUSERFLAG_OPPED_OR_VOICED) | chanuserflags; } else { if(user == NULL) { - user = addUser(argv[4]); + user = addUser(argv[5]); } if(!(chanuser = getChanUser(user, chan))) { chanuser = addChanUser(chan, user); @@ -252,10 +253,12 @@ void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int user->last_who = time(0); if(!*user->ident) strcpy(user->ident, argv[2]); + if(!user->ip) + user->ip = createIPNode(argv[3]); if(!*user->host) - strcpy(user->host, argv[3]); - if(!(user->flags & USERFLAG_ISAUTHED) && strcmp(argv[6], "0")) { - strcpy(user->auth, argv[6]); + strcpy(user->host, argv[4]); + if(!(user->flags & USERFLAG_ISAUTHED) && strcmp(argv[7], "0")) { + strcpy(user->auth, argv[7]); user->flags |= USERFLAG_ISAUTHED; } } else if((type & WHOQUEUETYPE_USERAUTH) && !(entry->type & WHOQUEUETYPE_FOUND)) { diff --git a/src/tools.c b/src/tools.c index c802bbe..2cb1065 100644 --- a/src/tools.c +++ b/src/tools.c @@ -19,6 +19,7 @@ #include "ChanNode.h" #include "lang.h" #include "ClientSocket.h" +#include "IPNode.h" static const struct default_language_entry msgtab[] = { {"TIME_MASK_2_ITEMS", "%s and %s"}, /* {ARGS: "2 days", "1 hour"} */ @@ -487,7 +488,7 @@ char* make_banmask(char *input, char* buffer) { ident = input; *p = '\0'; host = p+1; - } else if((p = strstr(input, "."))) { + } else if((p = strstr(input, ".")) || (p = strstr(input, ":"))) { host = input; } else if(*input == '*' && input[1] != '\0' && !strstr(input+1, "*")) { //AUTH MASK @@ -525,6 +526,26 @@ int isFakeHost(char *host) { return (strlen(p2+1) > 4); } +int mask_match(char *mask, struct UserNode *user) { + char usermask[NICKLEN+USERLEN+HOSTLEN+3]; + char matchmask[strlen(mask)+3]; + strcpy(matchmask, mask); + char *host = strchr(mask, '@'); + if(host) { + struct IPNode *ip = createIPNode(host); + int bits = (ip->flags & IPNODE_IS_IPV6 ? 128 : 32); + if((host = strchr(host, '/'))) { + bits = atoi(host+1); + } + if(ip && user->ip&& !ipmatch(user->ip, ip, bits)) { + host[1] = '*'; + host[2] = '\0'; + } + } + sprintf(usermask, "%s!%s@%s", user->nick, user->ident, user->host); + return match(matchmask, usermask); +} + static unsigned long crc_table[256]; static void crc32_init() { diff --git a/src/tools.h b/src/tools.h index dffb4a2..29cd337 100644 --- a/src/tools.h +++ b/src/tools.h @@ -82,6 +82,8 @@ char* generate_banmask(struct UserNode *user, char *buffer); char* make_banmask(char *input, char* buffer); int isFakeHost(char *host); +int mask_match(char *mask, struct UserNode *user); + unsigned long crc32(const char *text); void init_tools(); -- 2.20.1