/*
Copyright (c) 2005-2006 NFG Net Facilities Group BV support@nfg.nl
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dbmail.h"
struct cidrfilter * cidr_new(const char *str)
{
struct cidrfilter *self;
char *addr, *port, *mask;
char *haddr, *hport;
unsigned i;
size_t l;
assert(str != NULL);
self = (struct cidrfilter *)malloc(sizeof(struct cidrfilter));
self->sock_str = strdup(str);
self->socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
self->mask = 32;
addr = g_strdup(str);
haddr = addr;
while (*addr && *addr != ':')
addr++;
if (*addr == ':')
addr++;
port = g_strdup(addr);
hport = port;
while (*port && *port != ':')
port++;
if (*port == ':')
port++;
/* chop port */
l = strlen(addr);
for (i=0; i<l; i++) {
if (addr[i] == ':') {
addr[i]='\0';
break;
}
}
mask = index(addr,'/');
if (mask && mask[1] != '\0') {
mask++;
self->mask = atoi(mask);
/* chop mask */
l = strlen(addr);
for(i=0; i<l; i++) {
if (addr[i] == '/') {
addr[i]='\0';
break;
}
}
}
self->socket->sin_family = AF_INET;
self->socket->sin_port = strtol(port,NULL,10);
if (! inet_aton(addr,&self->socket->sin_addr)) {
free(haddr);
free(hport);
cidr_free(self);
return NULL;
}
free(haddr);
free(hport);
return self;
}
int cidr_repr(struct cidrfilter *self)
{
return printf("struct cidrfilter {\n"
"\tsock_str: %s;\n"
"\tsocket->sin_addr: %s;\n"
"\tsocket->sin_port: %d;\n"
"\tmask: %d;\n"
"};\n",
self->sock_str,
inet_ntoa(self->socket->sin_addr),
self->socket->sin_port,
self->mask
);
}
int cidr_match(struct cidrfilter *base, struct cidrfilter *test)
{
char *fullmask = "255.255.255.255";
struct in_addr match_addr, base_addr, test_addr;
inet_aton(fullmask, &base_addr);
inet_aton(fullmask, &test_addr);
unsigned result = 0;
if (base->mask)
base_addr.s_addr = ~((unsigned long)base_addr.s_addr >> (32-base->mask));
if (test->mask)
test_addr.s_addr = ~((unsigned long)test_addr.s_addr >> (32-test->mask));
base_addr.s_addr = (base->socket->sin_addr.s_addr | base_addr.s_addr);
test_addr.s_addr = (test->socket->sin_addr.s_addr | test_addr.s_addr);
match_addr.s_addr = (base_addr.s_addr & test_addr.s_addr);
/* only match ports if specified */
if (test->socket->sin_port > 0 && (base->socket->sin_port != test->socket->sin_port))
return 0;
if (test_addr.s_addr == match_addr.s_addr)
result = base->mask ? base->mask : 32;
return result;
}
void cidr_free(struct cidrfilter *self)
{
if (! self)
return;
if (self->socket)
free(self->socket);
if (self->sock_str)
free(self->sock_str);
if (self)
free(self);
}
syntax highlighted by Code2HTML, v. 0.9.1