From: Ralph Ronnquist Date: Tue, 18 Feb 2025 13:22:58 +0000 (+1100) Subject: cleanup and polish X-Git-Tag: 0.1 X-Git-Url: https://git.rrq.au/?a=commitdiff_plain;h=HEAD;p=rrq%2Fblockdomains.git cleanup and polish --- diff --git a/README.adoc b/README.adoc index 6fe912d..81cedcd 100644 --- a/README.adoc +++ b/README.adoc @@ -47,7 +47,7 @@ some other useful files == Setup and Confguration -The blockdomains utility uses blocklist files that nominates the +The blockdomains utility uses block list files that nominate the domains to block. Control scripting supports the notion of a configuration root directory `/etc/blockdomains/` with two sub direcotries `acl/` and `blocked/`. The idea is that `acl/` contains diff --git a/src/blockdomains.c b/src/blockdomains.c index 046e592..a8f144b 100644 --- a/src/blockdomains.c +++ b/src/blockdomains.c @@ -9,15 +9,20 @@ #include #include #include /* for NF_ACCEPT */ - #include -// Caching of verdicts +/** + * This file implements the overall program logic by setting up a + * netfilter queue callback for analysing packets and make an ACCEPT + * or REJECT verdict for them. + */ + +// API for caching of verdicts unsigned int lookup_cache(unsigned char *domain); void add_cache(unsigned char *domain,unsigned int ix); int hash_code(unsigned char *domain); -// BAD domains database +// API for BAD domains database unsigned int check_domain(unsigned char *domain); void load_domains(char *file); void start_domain_database_loading(void); @@ -31,33 +36,39 @@ static u_int32_t get_packet_id(struct nfq_data *tb) { return ( ph )? ntohl( ph->packet_id ) : 0; } +/** + * Packet header if ipv4 packet. + */ struct ipv4_pkt { struct ip first; // .ip_dst[4 bytes] struct tcphdr second; }; +/** + * Packet header if ipv6 packet. + */ struct ipv6_pkt { struct ip6_hdr first; // .ip6_dst[16 bytes] struct tcphdr second; }; -// Payload packet +/** + * Convenience type for network packets of undetermined family. + */ struct packet { union { struct ipv4_pkt pkt4; struct ipv6_pkt pkt6; } p; - //unsigned char pad[12]; // ?? }; +/** + * Locates the header of a packet byte blob. + */ static struct packet *get_headerP(unsigned char *data) { return (struct packet *) data; } -///////// Debugging -//const char *inet_ntop(int af, const void *restrict src, -// char dst[restrict .size], socklen_t size); - static const char *tell_ip(struct packet *ip) { static char THEIP[200]; switch ( ip->p.pkt4.first.ip_v ) { @@ -225,34 +236,20 @@ static int cb( int length = nfq_get_payload( nfa, &data); int verdict = NF_ACCEPT; struct packet *header = get_headerP( data ); -#if 0 - fprintf( stderr, "PKT %s %d\n", tell_ip( header ), length ); -#endif if ( length >= 100 ) { unsigned char *host = http_host( data, length ); -#if 1 - if ( host ) { - fprintf( stderr, "HTTP HOST %s %s\n", tell_ip( header ), host ); - } -#endif if ( host == 0 ) { host = ssl_host( data, length ); -#if 1 - if ( host ) { - fprintf( stderr, "SSL HOST %s %s\n", tell_ip( header ), host ); - } -#endif } if ( host ) { int i = lookup_cache( host ); if ( i < 0 ) { unsigned int ix = check_domain( host ); add_cache( host, ix ); -#if 1 - fprintf( stderr, "%s %d %s ** %d\n", - tell_ip( header ), hash_code( host ), host, ix ); -#endif if ( ix > 0 ) { + // Notify "new" domain blocking + fprintf( stderr, "%d: block %s at %s by %d\n", + hash_code( host ), host, tell_ip( header ), ix ); verdict = NF_DROP; } } else if ( i > 0 ) { @@ -264,14 +261,15 @@ static int cb( } /** - * Program main function. + * Program main function. Load block lists, register netfilter + * calllback and go for it. */ int main(int argc, char **argv) { // Load the database start_domain_database_loading(); int n = 1; for ( ; n < argc; n++ ) { - fprintf( stderr, "Loading block list %s\n", argv[ n ] ); + fprintf( stderr, "blockdomains loads block list %s\n", argv[ n ] ); load_domains( argv[ n ] ); } end_domain_database_loading(); @@ -283,36 +281,36 @@ int main(int argc, char **argv) { int rv; char buf[4096] __attribute__ ((aligned)); - fprintf( stderr, "opening library handle\n"); + fprintf( stderr, "blockdomains opens library handle\n"); h = nfq_open(); if ( !h ) { - fprintf(stderr, "error during nfq_open()\n"); + fprintf(stderr, "blockdomains error during nfq_open()\n"); exit(1); } - fprintf( stderr, "unbinding any existing nf_queue handler\n" ); + fprintf( stderr, "blockdomains unbinds any existing nf_queue handler\n" ); if ( nfq_unbind_pf(h, AF_INET) < 0 ) { fprintf(stderr, "error during nfq_unbind_pf()\n"); exit(1); } - fprintf( stderr, "binding nfnetlink_queue as nf_queue handler\n" ); + fprintf( stderr, "blockdomains binds as nf_queue handler\n" ); if ( nfq_bind_pf(h, AF_INET) < 0 ) { fprintf(stderr, "error during nfq_bind_pf()\n"); exit(1); } #define THEQUEUE 99 - fprintf( stderr, "binding this socket to queue '%d'\n", THEQUEUE ); + fprintf( stderr, "blockdomains registers to queue '%d'\n", THEQUEUE ); qh = nfq_create_queue( h, THEQUEUE, &cb, NULL ); if ( !qh ) { - fprintf(stderr, "error during nfq_create_queue()\n"); + fprintf(stderr, "blockdomains error during nfq_create_queue()\n"); exit(1); } - fprintf( stderr, "setting copy_packet mode\n" ); + fprintf( stderr, "blockdomains setting copy_packet mode\n" ); if ( nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff ) < 0) { - fprintf(stderr, "can't set packet_copy mode\n"); + fprintf(stderr, "blockdomains can't set packet_copy mode\n"); exit(1); } @@ -323,17 +321,17 @@ int main(int argc, char **argv) { nfq_handle_packet(h, buf, rv); } - fprintf( stderr, "unbinding from queue %d\n", THEQUEUE); + fprintf( stderr, "blockdomains unbinding from queue %d\n", THEQUEUE); nfq_destroy_queue(qh); #ifdef INSANE /* normally, applications SHOULD NOT issue this command, since it detaches other programs/sockets from AF_INET, too ! */ - fprintf( stderr, "unbinding from AF_INET\n"); + fprintf( stderr, "blockdomains unbinding from AF_INET\n"); nfq_unbind_pf(h, AF_INET); #endif - fprintf( stderr, "closing library handle\n"); + fprintf( stderr, "blockdomains closing library handle\n"); nfq_close( h ); exit( 0 ); diff --git a/src/cache.c b/src/cache.c index 2afb37a..c4df75d 100644 --- a/src/cache.c +++ b/src/cache.c @@ -2,16 +2,34 @@ #include #include +/** + * This file implements a "cache" of "known" domains together with + * their verdicts. + */ + +/** + * This is the CacheEntry type of a malloc-ed cstring domain and a + * verdict. + */ typedef struct _CacheEntry { unsigned char *domain; unsigned int ix; } CacheEntry; +/** + * This is the cache root structure as apointer to the CacheEntry + * array and its size. + */ struct { CacheEntry *table; int size; } cache; +/** + * This computes a hash code for a domain which is its cache index. + * This hashing simply adds the domain characters modulo cache table + * size. + */ int hash_code(unsigned char *domain) { int i = 0; for ( ; *domain; domain++ ) { @@ -20,6 +38,10 @@ int hash_code(unsigned char *domain) { return i % cache.size; } +/** + * Look up a domain in the cache and return its cached verdict, or -1 + * of not present. + */ int lookup_cache(unsigned char *domain) { if ( cache.table ) { int i = hash_code( domain ); @@ -31,6 +53,12 @@ int lookup_cache(unsigned char *domain) { return -1; } +/** + * Add a domain and verdict into the cache. The domain hash code is + * used as index into the table, to replace any prior CacheEntry + * setting. The domain is a NUL terminated string that is copied into + * the cache. + */ void add_cache(unsigned char *domain,unsigned int ix) { if ( cache.table == 0 ) { cache.size = 1024; diff --git a/src/database.c b/src/database.c index 02bb8dc..0edcf80 100644 --- a/src/database.c +++ b/src/database.c @@ -140,36 +140,9 @@ static int wordlen(unsigned char *p) { return q - p; } -#if 0 -static void add_domain(char *domain) { - if ( database.fill >= database.size ) { - grow(); - } - int length = wordlen( domain ); - int i = index_domain( domain, length, 0 ); - if ( i < 0 ) { - i = -i-1; - int tail = database.fill - i; - if ( tail ) { - memmove( &database.table[ i+1 ], - &database.table[i], - tail * sizeof( Entry ) ); - } - database.table[ i ].domain = domain; - database.table[ i ].length = length; - database.fill++; - } else { - char *p1 = strndup( domain, length ); - char *p2 = strndup( database.table[i].domain, - database.table[i].length ); - fprintf( stderr, "fill = %d %d %s == %s\n", - i, database.fill, p1, p2 ); - free( p1 ); - free( p2 ); - } -} -#endif - +/** + * Add an Entry for a given domain string and length. + */ static void fast_add_domain(unsigned char *domain,int length) { int fill = database.fill; if ( fill >= database.size ) { @@ -180,6 +153,11 @@ static void fast_add_domain(unsigned char *domain,int length) { database.fill++; } +/** + * Return a marker of the sort order of two given Entry records, with + * ab by + * (non-zero) positive integer. + */ static int table_order(Entry *a,Entry *b) { int k = ( a->length < b->length )? a->length : b->length; int c = tail_compare( a->domain + a->length, @@ -191,34 +169,28 @@ static int table_order(Entry *a,Entry *b) { } /** - * External call to check a given domain. + * External call to check whether a given domain is in the database, + * returning 0 if not and non-zero if the domain is present. */ unsigned int check_domain(unsigned char *domain) { int i = index_domain( domain, wordlen( domain ), 1 ); return ( i < 0 )? 0 : ( i + 1 ); } +/** + * This function doesn't do anything at all but is present for the + * sake of the ABI. + */ void start_domain_database_loading(void) { } -#if 0 -static void dump_table() { - fprintf( stderr, "Table fill=%d size=%d\n", database.fill, database.size ); - int i = 0; - for ( ; i < database.fill; i++ ) { - char *p = strndup( database.table[i].domain, - database.table[i].length ); - fprintf( stderr, "[%d] %d %p %s\n", - i, database.table[i].length, database.table[i].domain, p ); - free( p ); - } -} -#endif - +/** + * This function sorts the database to support the lookup by binary + * search. + */ void end_domain_database_loading(void) { qsort( database.table, database.fill, sizeof( Entry ), (__compar_fn_t) table_order ); - //dump_table(); } /** @@ -255,18 +227,14 @@ void load_domains(char *file) { } //fprintf( stderr, "processing %s %p %p\n", file, data, end ); unsigned char *p = data; -#if 0 - int count = 0; -#endif - while( p < end ) { -#if 0 - if ( ( ++count % 10000 ) == 0 ) { - fprintf( stderr, "%d rules\n", count ); + while( p < end ) { // Consume a line + if ( *p <= ' ' ) { + p++; + continue; } -#endif if ( *p == '.' ) { unsigned char *domain = ++p; - while ( *p > ' ' ) { + while ( p < end && *p > ' ' ) { p++; } fast_add_domain( domain, p - domain );