Support CIDR-notated blocklists

This commit adds a new blocklist line format, namely individual IPv4
CIDR ranges separated by newlines. Text put after each entry is ignored
by sscanf, so feel free to put any kind of comments there.

Fix #230.
This commit is contained in:
Mingye Wang 2018-10-13 17:20:40 -04:00
parent 24473c9487
commit b3129591db
2 changed files with 38 additions and 5 deletions

View File

@ -19,12 +19,14 @@
#include "libtransmission-test.h"
static char const* contents1 =
"10.5.6.7/8\n"
"Austin Law Firm:216.16.1.144-216.16.1.151\n"
"Sargent Controls and Aerospace:216.19.18.0-216.19.18.255\n"
"Corel Corporation:216.21.157.192-216.21.157.223\n"
"Fox Speed Channel:216.79.131.192-216.79.131.223\n";
static char const* contents2 =
"10.5.6.7/8\n"
"Austin Law Firm:216.16.1.144-216.16.1.151\n"
"Sargent Controls and Aerospace:216.19.18.0-216.19.18.255\n"
"Corel Corporation:216.21.157.192-216.21.157.223\n"
@ -78,6 +80,8 @@ static int test_parsing(void)
check(tr_blocklistIsEnabled(session));
/* test blocked addresses */
check(!address_is_blocked(session, "0.0.0.1"));
check(address_is_blocked(session, "10.1.2.3"));
check(!address_is_blocked(session, "216.16.1.143"));
check(address_is_blocked(session, "216.16.1.144"));
check(address_is_blocked(session, "216.16.1.145"));
@ -116,22 +120,22 @@ static int test_updating(void)
/* test that updated source files will get loaded */
create_text_file(path, contents1);
tr_sessionReloadBlocklists(session);
check_int(tr_blocklistGetRuleCount(session), ==, 4);
check_int(tr_blocklistGetRuleCount(session), ==, 5);
/* test that updated source files will get loaded */
create_text_file(path, contents2);
tr_sessionReloadBlocklists(session);
check_int(tr_blocklistGetRuleCount(session), ==, 5);
check_int(tr_blocklistGetRuleCount(session), ==, 6);
/* test that updated source files will get loaded */
create_text_file(path, contents1);
tr_sessionReloadBlocklists(session);
check_int(tr_blocklistGetRuleCount(session), ==, 4);
check_int(tr_blocklistGetRuleCount(session), ==, 5);
/* ensure that new files, if bad, get skipped */
create_text_file(path, "# nothing useful\n");
tr_sessionReloadBlocklists(session);
check_int(tr_blocklistGetRuleCount(session), ==, 4);
check_int(tr_blocklistGetRuleCount(session), ==, 5);
/* cleanup */
libttest_session_close(session);

View File

@ -301,9 +301,38 @@ static bool parseLine2(char const* line, struct tr_ipv4_range* range)
return true;
}
/*
* CIDR notation: "0.0.0.0/8", IPv4 only
* https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation
*/
static bool parseLine3(char const* line, struct tr_ipv4_range* range) {
unsigned ip[4];
unsigned pflen;
uint32_t ip_u;
uint32_t mask = 0xffffffff;
if (sscanf(line, "%u.%u.%u.%u/%u", &ip[0], &ip[1], &ip[2], &ip[3], &pflen) != 5) {
return false;
}
if (pflen > 32 || ip[0] > 0xff || ip[1] > 0xff || ip[2] > 0xff || ip[3] > 0xff) {
return false;
}
/* do it in the network order */
mask <<= pflen;
ip_u = ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3];
/* fill the non-prefix bits the way we need it */
range->begin = ntohl(ip_u & mask);
range->end = ntohl(ip_u | (~mask));
return true;
}
static bool parseLine(char const* line, struct tr_ipv4_range* range)
{
return parseLine1(line, range) || parseLine2(line, range);
return parseLine1(line, range) || parseLine2(line, range) || parseLine3(line, range);
}
static int compareAddressRangesByFirstAddress(void const* va, void const* vb)