]> granicus.if.org Git - transmission/commitdiff
Support CIDR-notated blocklists
authorMingye Wang <arthur200126@gmail.com>
Sat, 13 Oct 2018 21:20:40 +0000 (17:20 -0400)
committerMingye Wang <arthur200126@gmail.com>
Sat, 13 Oct 2018 21:23:45 +0000 (17:23 -0400)
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
libtransmission/blocklist.c

index 4d01c0b654cf9278a0a923902a348da90615e815..6e6b29eef9383b722735a10b4a202a2700acb271 100644 (file)
 #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);
index 434c999db83a70191d12e1ecc90cff5a5d94e308..33064aaded4effe9e952ca461b7fb5868ca1a214 100644 (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)