/*
This file is part of GNUnet.
(C) 2001, 2002, 2003, 2004 Christian Grothoff (and other contributing authors)
GNUnet 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, or (at your
option) any later version.
GNUnet 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 GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file util/ipcheck.c
* @brief test if an IP matches a given subnet
* @author Christian Grothoff
*/
#include "gnunet_util.h"
#include "platform.h"
/**
* Parse a network specification. The argument specifies
* a list of networks. The format is
* [network/netmask;]* (no whitespace, must be terminated
* with a semicolon). The network must be given in dotted-decimal
* notation. The netmask can be given in CIDR notation (/16) or
* in dotted-decimal (/255.255.0.0).
*
* @param routeList a string specifying the forbidden networks
* @return the converted list, NULL if the synatx is flawed
*/
CIDRNetwork * parseRoutes(const char * routeList) {
unsigned int count;
unsigned int i;
unsigned int j;
unsigned int len;
int cnt;
unsigned int pos;
unsigned int temps[8];
int slash;
CIDRNetwork * result;
if (routeList == NULL)
return NULL;
len = strlen(routeList);
if (len == 0)
return NULL;
count = 0;
for (i=0;i 0xFF) {
LOG(LOG_ERROR,
_("Invalid format for IP: '%s'\n"),
&routeList[pos]);
FREE(result);
return NULL;
}
result[i].network.addr
= htonl((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + temps[3]);
result[i].netmask.addr
= htonl((temps[4] << 24) + (temps[5] << 16) + (temps[6] << 8) + temps[7]);
while (routeList[pos] != ';')
pos++;
pos++;
i++;
continue;
}
/* try second notation */
cnt = sscanf(&routeList[pos],
"%u.%u.%u.%u/%u;",
&temps[0],
&temps[1],
&temps[2],
&temps[3],
&slash);
if (cnt == 5) {
for (j=0;j<4;j++)
if (temps[j] > 0xFF) {
LOG(LOG_ERROR,
"wrong format for IP: %s\n",
&routeList[pos]);
FREE(result);
return NULL;
}
result[i].network.addr
= htonl((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + temps[3]);
if ( (slash <= 32) && (slash > 0) ) {
result[i].netmask.addr = 0;
while (slash > 0) {
result[i].netmask.addr
= (result[i].netmask.addr >> 1) + 0x80000000;
slash--;
}
result[i].netmask.addr
= htonl(result[i].netmask.addr);
while (routeList[pos] != ';')
pos++;
pos++;
i++;
continue;
} else {
LOG(LOG_ERROR,
_("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."),
slash);
FREE(result);
return NULL; /* error */
}
}
LOG(LOG_ERROR,
"invalid network notation: >>%s<<",
&routeList[pos]);
FREE(result);
return NULL; /* error */
}
if (pos < strlen(routeList)) {
LOG(LOG_ERROR,
_("Invalid network notation (additional characters: '%s')."),
&routeList[pos]);
FREE(result);
return NULL; /* oops */
}
return result; /* ok */
}
/**
* Check if the given IP address is in the list of IP addresses.
*
* @param list a list of networks
* @param ip the IP to check (in network byte order)
* @return NO if the IP is not in the list, YES if it it is
*/
int checkIPListed(const CIDRNetwork * list,
IPaddr ip) {
int i;
IPaddr add;
add = ip;
i=0;
if (list == NULL)
return NO;
while ( (list[i].network.addr != 0) ||
(list[i].netmask.addr != 0) ) {
if ( (add.addr & list[i].netmask.addr) ==
(list[i].network.addr & list[i].netmask.addr) )
return YES;
i++;
}
return NO;
}
#if USE_IPV6
/**
* Parse a network specification. The argument specifies
* a list of networks. The format is
* [network/netmask;]* (no whitespace, must be terminated
* with a semicolon). The network must be given in colon-hex
* notation. The netmask must be given in CIDR notation (/16) or
* can be omitted to specify a single host.
*
* @param routeList a string specifying the forbidden networks
* @return the converted list, NULL if the synatx is flawed
*/
CIDR6Network * parseRoutes6(char * routeList) {
unsigned int count;
unsigned int i;
unsigned int len;
unsigned int pos;
int start;
int slash;
int ret;
CIDR6Network * result;
if (routeList == NULL)
return NULL;
len = strlen(routeList);
if (len == 0)
return NULL;
routeList = STRDUP(routeList);
count = 0;
for (i=0;i= start) &&
(routeList[slash] != '/') )
slash--;
if (slash < start) {
memset(&result[i].netmask,
0xFF,
sizeof(IP6addr));
slash = pos;
} else {
routeList[pos] = '\0';
ret = inet_pton(AF_INET6,
&routeList[slash+1],
&result[i].netmask);
if (ret <= 0) {
LOG(LOG_ERROR,
_("Wrong format '%s' for netmask: %s\n"),
&routeList[slash+1],
STRERROR(errno));
FREE(result);
FREE(routeList);
return NULL;
}
}
routeList[slash] = '\0';
ret = inet_pton(AF_INET6,
&routeList[start],
&result[i].network);
if (ret <= 0) {
LOG(LOG_ERROR,
_("Wrong format '%s' for network: %s\n"),
&routeList[slash+1],
STRERROR(errno));
FREE(result);
FREE(routeList);
return NULL;
}
pos++;
}
FREE(routeList);
return result;
}
/**
* Check if the given IP address is in the list of IP addresses.
*
* @param list a list of networks
* @param ip the IP to check (in network byte order)
* @return NO if the IP is not in the list, YES if it it is
*/
int checkIP6Listed(CIDR6Network * list,
IP6addr * ip) {
unsigned int i;
unsigned int j;
struct in6_addr zero;
i=0;
if (list == NULL)
return NO;
memset(&zero, 0, sizeof(struct in6_addr));
while ( (memcmp(&zero, &list[i].network, sizeof(struct in6_addr)) != 0) ||
(memcmp(&zero, &list[i].netmask, sizeof(struct in6_addr)) != 0) ) {
for (j=0;j