From b3129591db95677d9beefb18b0aa2d939a19428e Mon Sep 17 00:00:00 2001 From: Mingye Wang Date: Sat, 13 Oct 2018 17:20:40 -0400 Subject: [PATCH] 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. --- libtransmission/blocklist-test.c | 12 ++++++++---- libtransmission/blocklist.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/libtransmission/blocklist-test.c b/libtransmission/blocklist-test.c index 4d01c0b65..6e6b29eef 100644 --- a/libtransmission/blocklist-test.c +++ b/libtransmission/blocklist-test.c @@ -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); diff --git a/libtransmission/blocklist.c b/libtransmission/blocklist.c index 434c999db..33064aade 100644 --- a/libtransmission/blocklist.c +++ b/libtransmission/blocklist.c @@ -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)