From 5df54493e9eeb0f934f7f606cb1997cb546ca739 Mon Sep 17 00:00:00 2001 From: Ralph Ronnquist Date: Tue, 7 Sep 2021 23:24:09 +1000 Subject: [PATCH 1/1] added --- Makefile | 28 +++ README.html | 84 +++++++++ README.md | 72 ++++++++ bin/nfblocker | Bin 0 -> 23820 bytes bin/nfblocker.sh | 38 ++++ blocked/squid-ads.acl | 1 + blocked/squid-dating.acl | 1 + blocked/squid-gambling.acl | 1 + blocked/squid-malicious.acl | 1 + blocked/squid-porn.acl | 1 + blocked/squid-video.acl | 1 + blocked/youtube-google-videos.acl | 1 + src/cache.c | 45 +++++ src/database.c | 280 +++++++++++++++++++++++++++++ src/nfblocker.c | 286 ++++++++++++++++++++++++++++++ src/ssl.txt | 42 +++++ 16 files changed, 882 insertions(+) create mode 100644 Makefile create mode 100644 README.html create mode 100644 README.md create mode 100755 bin/nfblocker create mode 100755 bin/nfblocker.sh create mode 120000 blocked/squid-ads.acl create mode 120000 blocked/squid-dating.acl create mode 120000 blocked/squid-gambling.acl create mode 120000 blocked/squid-malicious.acl create mode 120000 blocked/squid-porn.acl create mode 120000 blocked/squid-video.acl create mode 120000 blocked/youtube-google-videos.acl create mode 100644 src/cache.c create mode 100644 src/database.c create mode 100644 src/nfblocker.c create mode 100644 src/ssl.txt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..534f9f1 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +# Distribution Makefile for nfbuilder +# + +ifeq ($(shell dpkg -l libnetfilter-queue-dev),) +$(info "nfblocker requires the libnetfilter-queue-dev package") +$(info "please install it before making") +$(error "TERMINATED") +endif + +INSTALLDIR=/usr/local/sbin +USERCOMMAND = nfblocker.sh + +.PHONY: install clean + +default: install + +bin/nfblocker: $(wildcard src/*.c) + gcc -g -Wall -o $@ $^ -lnetfilter_queue + +# Installing the control script in $(INSTALLDIR) + +$(INSTALLDIR)/$(USERCOMMAND): bin/nfblocker.sh $(INSTALLDIR) + ln -sTf $$(readlink -f $<) $@ + +install: bin/nfblocker $(INSTALLDIR)/$(USERCOMMAND) + +clean: + rm -f bin/nfblocker diff --git a/README.html b/README.html new file mode 100644 index 0000000..fb7af87 --- /dev/null +++ b/README.html @@ -0,0 +1,84 @@ +

Blacklist based domain name filtering

+ +

The nfblocker utility is a blacklist based network traffic filter +for iptables via libnetfilter-queue. It applies to HTTP and SSL +traffic for recognizing and dropping packets that are directed to +blacklisted domain names.

+ +

Dendencies

+ +

Operationally nfblocker depends on the libnetfilter-queue-dev and +iptables packages, and for building, you'll also need a C build +environment including make.

+ +

The blacklist format is that of squidblacklist.org, which you'll need +to acquire separately.

+ +

Build and Install

+ +

nfblocker is distributed in a tar file, which should be unpacked at +its future residence; e.g., as /usr/local/src/nfblocker-1.0.0. Then +cd into that directory and type:

+ +
+

# make

+
+ +

This will build the binary filter, and install the control script as +/usr/local/sbin/nfblocker.sh. Edit the Makefile to install +elsewhere.

+ +

Setup and Confguration

+ +

The residence has a directory acl that is intended to hold all +available access control lists, and a directory blocked that should +be set up with links to the access control list files to use. For +example:

+ +
+

# ( cd blocked && ln -s ../acl/youtube-google-videos.acl )

+
+ +

That command will set up youtube-google-videos.acl to be an included +blacklist. Do the opposite to remove; for example:

+ +
+

# rm blocked/youtube-google-videos.acl

+
+ +

Running

+ +

The nfblocker is started with the following command:

+ +
+

# nfblocker.sh start

+
+ +

With the start argument, the script adds appropriate iptables +rules to use direct certain traffic to net-filter queue 99, and it +starts a background process fot that filtering.

+ +
+

# nfblocker.sh reload

+
+ +

With the reload argument, the control script stops and restarts the +filter without changing iptables rules.

+ +
+

# nfblocker.sh stop

+
+ +

With the stop argument, the control script removes the iptables +rules and terminates the filtering process.

+ +

Technical Detail

+ +

The filtering uses the given lists of domain names for rejecting +packets. It recognizes HTTP message headers and SSL certificate +requests, from where it picks out the targeted domain name. If that +name is blacklised or in a blacklisted domain, then the packet is +rejected.

+ +

The filtering also uses a fixed size decision cache, so that +subsequent decisions for the same target can be made quickly.

diff --git a/README.md b/README.md new file mode 100644 index 0000000..f950a79 --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +# Blacklist based domain name filtering + +The `nfblocker` utility is a blacklist based network traffic filter +for `iptables` via `libnetfilter-queue`. It applies to HTTP and SSL +traffic for recognizing and dropping packets that are directed to +blacklisted domain names. + +## Dendencies + +Operationally `nfblocker` depends on the `libnetfilter-queue-dev` and +`iptables` packages, and for building, you'll also need a C build +environment including `make`. + +The blacklist format is that of squidblacklist.org, which you'll need +to acquire separately. + +## Build and Install + +`nfblocker` is distributed in a tar file, which should be unpacked at +its future residence; e.g., as /usr/local/src/nfblocker-1.0.0. Then +`cd` into that directory and type: + +> `# make` + +This will build the binary filter, and install the control script as +`/usr/local/sbin/nfblocker.sh`. Edit the Makefile to install +elsewhere. + +## Setup and Confguration + +The residence has a directory `acl` that is intended to hold all +available access control lists, and a directory `blocked` that should +be set up with links to the access control list files to use. For +example: + +> `# ( cd blocked && ln -s ../acl/youtube-google-videos.acl )` + +That command will set up `youtube-google-videos.acl` to be an included +blacklist. Do the opposite to remove; for example: + +> `# rm blocked/youtube-google-videos.acl` + +## Running + +The `nfblocker` is started with the following command: + +> `# nfblocker.sh start` + +With the `start` argument, the script adds appropriate `iptables` +rules to use direct certain traffic to net-filter queue 99, and it +starts a background process fot that filtering. + +> `# nfblocker.sh reload` + +With the `reload` argument, the control script stops and restarts the +filter without changing `iptables` rules. + +> `# nfblocker.sh stop` + +With the `stop` argument, the control script removes the `iptables` +rules and terminates the filtering process. + +## Technical Detail + +The filtering uses the given lists of domain names for rejecting +packets. It recognizes HTTP message headers and SSL certificate +requests, from where it picks out the targeted domain name. If that +name is blacklised or in a blacklisted domain, then the packet is +rejected. + +The filtering also uses a fixed size decision cache, so that +subsequent decisions for the same target can be made quickly. diff --git a/bin/nfblocker b/bin/nfblocker new file mode 100755 index 0000000000000000000000000000000000000000..a9a9c8a8ed5a6c72a8523f728f5b0b7307fefc9a GIT binary patch literal 23820 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 literal 0 HcmV?d00001 diff --git a/bin/nfblocker.sh b/bin/nfblocker.sh new file mode 100755 index 0000000..661d8d0 --- /dev/null +++ b/bin/nfblocker.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# +# This is a control script for nfblocker. +# + +if [ -z "$1" ] ; then + echo "start or stop?" + exit 1 +fi + +cd $(dirname $(readlink $0)) + +function start_nfblocker() { + LOG=/var/log/nfblocker.$(date +%Y%m%d) + BLOCKED=( ../acl/*.acl ) + echo "BLOCKING ${BLOCKED[@]}" >> $LOG + ./nfblocker ../blocked/*.acl >> $LOG 2>&1 & +} + +TABLE=OUTPUT +case $1 in + start) + iptables -I $TABLE -p tcp -j NFQUEUE --queue-num 99 + pkill -x nfblocker + start_nfblocker + ;; + reload) + pkill -x nfblocker + start_nfblocker + ;; + stop) + iptables -D $TABLE -p tcp -j NFQUEUE --queue-num 99 + pkill -x nfblocker + ;; + *) + echo "Use start, stop or reload" >&2 + ;; +esac diff --git a/blocked/squid-ads.acl b/blocked/squid-ads.acl new file mode 120000 index 0000000..905bd71 --- /dev/null +++ b/blocked/squid-ads.acl @@ -0,0 +1 @@ +../acl/squid-ads.acl \ No newline at end of file diff --git a/blocked/squid-dating.acl b/blocked/squid-dating.acl new file mode 120000 index 0000000..6a7fd51 --- /dev/null +++ b/blocked/squid-dating.acl @@ -0,0 +1 @@ +../acl/squid-dating.acl \ No newline at end of file diff --git a/blocked/squid-gambling.acl b/blocked/squid-gambling.acl new file mode 120000 index 0000000..fd170a7 --- /dev/null +++ b/blocked/squid-gambling.acl @@ -0,0 +1 @@ +../acl/squid-gambling.acl \ No newline at end of file diff --git a/blocked/squid-malicious.acl b/blocked/squid-malicious.acl new file mode 120000 index 0000000..b0b7f81 --- /dev/null +++ b/blocked/squid-malicious.acl @@ -0,0 +1 @@ +../acl/squid-malicious.acl \ No newline at end of file diff --git a/blocked/squid-porn.acl b/blocked/squid-porn.acl new file mode 120000 index 0000000..0710db6 --- /dev/null +++ b/blocked/squid-porn.acl @@ -0,0 +1 @@ +../acl/squid-porn.acl \ No newline at end of file diff --git a/blocked/squid-video.acl b/blocked/squid-video.acl new file mode 120000 index 0000000..d0b480f --- /dev/null +++ b/blocked/squid-video.acl @@ -0,0 +1 @@ +../acl/squid-video.acl \ No newline at end of file diff --git a/blocked/youtube-google-videos.acl b/blocked/youtube-google-videos.acl new file mode 120000 index 0000000..06f57c8 --- /dev/null +++ b/blocked/youtube-google-videos.acl @@ -0,0 +1 @@ +../acl/youtube-google-videos.acl \ No newline at end of file diff --git a/src/cache.c b/src/cache.c new file mode 100644 index 0000000..2afb37a --- /dev/null +++ b/src/cache.c @@ -0,0 +1,45 @@ +#include +#include +#include + +typedef struct _CacheEntry { + unsigned char *domain; + unsigned int ix; +} CacheEntry; + +struct { + CacheEntry *table; + int size; +} cache; + +int hash_code(unsigned char *domain) { + int i = 0; + for ( ; *domain; domain++ ) { + i += *domain; + } + return i % cache.size; +} + +int lookup_cache(unsigned char *domain) { + if ( cache.table ) { + int i = hash_code( domain ); + if ( cache.table[i].domain && + strcmp( (char*) domain, (char*) cache.table[i].domain ) == 0 ) { + return cache.table[i].ix; + } + } + return -1; +} + +void add_cache(unsigned char *domain,unsigned int ix) { + if ( cache.table == 0 ) { + cache.size = 1024; + cache.table = (CacheEntry*) calloc( cache.size, sizeof( CacheEntry ) ); + } + int i = hash_code( domain ); + if ( cache.table[i].domain ) { + free( cache.table[i].domain ); + } + cache.table[i].domain = (unsigned char*) strdup( (char*) domain ); + cache.table[i].ix = ix; +} diff --git a/src/database.c b/src/database.c new file mode 100644 index 0000000..02bb8dc --- /dev/null +++ b/src/database.c @@ -0,0 +1,280 @@ +#include +#include +#include +#include +#include +#include +#include + +/** + * This file implements a "database" of "bad" domains, loaded from + * ".acl" files of a fairly strict format; each domain to block is + * written on a line starting with a period, immediately followed by + * the domain to block, then an optional comment. + * + * The database is populated by using the call sequence: + * 1. start_domain_database_loading(); + * 2. load_domains( filename ); // repeated + * N. end_domain_database_loading(); + * + * The final call triggers a reordering of domains so as to support + * binary search in reverse text order, for matching domain suffixes. + * See the function `tail_compare` for details. + */ + +/** + * This is the Entry type for the "database", which basically is an + * array of these. The domain pointer will point at a domain name in + * the loaded ".acl" file, and length is the domain name length. + */ +typedef struct _Entry { + int length; + unsigned char *domain; +} Entry; + +/** + * This is the domain name database root structure. It holds a pointer + * to the array of Entry records, the fill of that array, and the + * allocated size for that array (no lesser than the fill, of course). + */ +static struct { + Entry *table; + int fill; + int size; +} database = { 0, 0, 0 }; + +/** + * This function compares strings backwars; the last k bytes of string + * (a,na) versus string (b,nb). It also holds '.' as the least of + * characters, so as to ensure that refined/extended domain names are + * comparatively greater that their base domain names. + */ +static int tail_compare(unsigned char *a,unsigned char *b,int k) { + while ( k-- > 0 ) { + int c = *(--a) - *(--b); + if ( c != 0) { + if ( *a == '.' ) { + return -1; + } + if ( *b == '.' ) { + return 1; + } + return c; + } + } + return 0; +} + +/** + * Extend the domain name table to allow additions. + */ +#define STARTSIZE 100000 +static void grow() { + if ( database.table ) { + Entry *old = database.table; + int s = database.size; + database.size += 100000; + database.table = (Entry*) calloc( database.size, sizeof( Entry ) ); + memcpy( database.table, old, s * sizeof( Entry ) ); + free( old ); + } else { + database.table = (Entry*) calloc( STARTSIZE, sizeof( Entry ) ); + database.size = STARTSIZE; + } +} + +/** + * Determine the index for given domain. This matches computes a tail + * match between the given domain and the databse domains, returning + * the index for the matching database entry, or (-index-1) to + * indicate insertion point. In lookup mode, a database entry being a + * tail domain part of the given domain is also considered a match. + */ +static int index_domain(unsigned char *domain,int n,int lookup) { + int lo = 0; + int hi = database.fill; + while ( lo < hi ) { + int m = ( lo + hi ) / 2; + Entry *p = &database.table[ m ]; + int k = p->length; + if ( n < k ) { + k = n; + } + int q = tail_compare( p->domain + p->length, domain + n, k ); +#if 0 + fprintf( stderr, "%s %d %d %d\n", domain, k, m, q ); +#endif + if ( q == 0 ) { + if ( p->length < n ) { + // table entry shorter => new entry after, or match on lookup + if ( lookup && *(domain+n-k-1) == '.' ) { + return m; + } + lo = m + 1; + } else if ( p->length > n ) { + // table entry longer => new entry before + hi = m; + } else { + // equal + return m; + } + } else if ( q < 0 ) { + // new entry after + lo = m + 1; + } else { + // new entry before + hi = m; + } + } + return -lo - 1; +} + +/** + * Determine the length of a "word" + */ +static int wordlen(unsigned char *p) { + unsigned char *q = p; + while ( *q > ' ' ) { + q++; + } + 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 + +static void fast_add_domain(unsigned char *domain,int length) { + int fill = database.fill; + if ( fill >= database.size ) { + grow(); + } + database.table[ fill ].length = length; + database.table[ fill ].domain = domain; + database.fill++; +} + +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, + b->domain + b->length, k ); + if ( c != 0 ) { + return c; + } + return a->length - b->length; +} + +/** + * External call to check a given domain. + */ +unsigned int check_domain(unsigned char *domain) { + int i = index_domain( domain, wordlen( domain ), 1 ); + return ( i < 0 )? 0 : ( i + 1 ); +} + +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 + +void end_domain_database_loading(void) { + qsort( database.table, database.fill, sizeof( Entry ), + (__compar_fn_t) table_order ); + //dump_table(); +} + +/** + * Load BAD domain names from file. The file is line based where data + * lines consist of domain name starting with period and ending with + * space or newline, and other lines ignored. + */ +void load_domains(char *file) { + struct stat info; + unsigned char *data; + //fprintf( stderr, "state(\"%s\",&info)\n", file ); + if ( stat( file, &info ) ) { + perror( file ); + exit( 1 ); + } + int n = info.st_size; + data = (unsigned char *) malloc( n ); + //fprintf( stderr, "open(\"%s\",)\n", file ); + int fd = open( file, O_RDONLY ); + if ( fd < 0 ) { + perror( file ); + exit( 1 ); + } + //fprintf( stderr, "Loading %s\n", file ); + unsigned char *end = data; + while ( n > 0 ) { + int k = read( fd, end, n ); + if ( k == 0 ) { + fprintf( stderr, "Premature EOF for %s\n", file ); + exit( 1 ); + } + end += k; + n -= k; + } + //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 ); + } +#endif + if ( *p == '.' ) { + unsigned char *domain = ++p; + while ( *p > ' ' ) { + p++; + } + fast_add_domain( domain, p - domain ); + } + while ( p < end && *p != '\n' ) { + p++; + } + p++; + } + close( fd ); +} diff --git a/src/nfblocker.c b/src/nfblocker.c new file mode 100644 index 0000000..b8b979c --- /dev/null +++ b/src/nfblocker.c @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for NF_ACCEPT */ + +#include + +// 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 +unsigned int check_domain(unsigned char *domain); +void load_domains(char *file); +void start_domain_database_loading(void); +void end_domain_database_loading(void); + +/** + * Return packet id, or 0 on error. + */ +static u_int32_t get_packet_id(struct nfq_data *tb) { + struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr( tb ); + return ( ph )? ntohl( ph->packet_id ) : 0; +} + +// Payload headers +struct headers { + struct ip first; + struct tcphdr second; + //unsigned char pad[12]; // ?? +}; + +///////// Debugging + +static unsigned char *tell_ip(u_int32_t ip) { + static unsigned char THEIP[20]; + unsigned char *b = (unsigned char *)&ip; + sprintf( (char*) THEIP, "%d.%d.%d.%d%c", b[0], b[1], b[2], b[3], 0 ); + return THEIP; +} + +static u_int32_t get_dest_ip4(unsigned char *data) { + struct headers *p = (struct headers *) data; + return p->first.ip_dst.s_addr; +} + +/** + * Review payload packet payload + */ +static void view_payload(unsigned char *data,int length) { + u_int32_t ip4 = get_dest_ip4( data ); + u_int16_t port = ntohs( ((struct headers *) data )->second.th_dport ); + u_int8_t syn = sizeof( struct headers ); + unsigned char *body = data ;//+ sizeof( struct headers ); +#define END 400 + unsigned char * end = body + ( ( length > END )? END : length ); + fprintf( stderr, "%s %d %d %d ", tell_ip( ip4 ), syn, port, length ); + while ( body < end ) { + unsigned char c = *body++; + if ( c < ' ' || c >= 127 || 1 ) { + fprintf( stderr, "%02x ", c ); + } else { + fprintf( stderr, "%c", c ); + } + } + fprintf( stderr, "\n" ); +} + +////////////////// +static unsigned char buffer[1000]; + +/** + * SSL traffic includes a data packet with a clear text host name. + * This is knwon as the SNI extension. + */ +static unsigned char *ssl_host(unsigned char *data,int length) { + // Check that it's a "Client Hello" message + unsigned char *p = data + sizeof( struct headers ) + 12; + if ( p[0] != 0x16 || p[1] != 0x03 || p[5] != 0x01 || p[6] != 0x00 ) { + return 0; + } + //fprintf( stderr, "Client Hello\n" ); + // Note minor version p[2] is not checked + // record_length = 256 * p[3] + p[4] + // handshake_message_length = 256 * p[7] + p[8] + if ( p[9] != 0x03 || p[10] != 0x03 ) { // TLS 1.2 (?ralph?) + return 0; + } + //fprintf( stderr, "TLS 1.2\n" ); + unsigned int i = 46 + ( 256 * p[44] ) + p[45]; + i += p[i] + 1; + unsigned int extensions_length = ( 256 * p[i] ) + p[i+1]; + i += 2; + int k = 0; + //fprintf( stderr, "TLS 1.2 %d %d\n", i, extensions_length ); + while ( k < extensions_length ) { + unsigned int type = ( 256 * p[i+k] ) + p[i+k+1]; + k += 2; + unsigned int length = ( 256 * p[i+k] ) + p[i+k+1]; + k += 2; + //fprintf( stderr, "Extension %d %d\n", k-4, type ); + if ( type == 0 ) { // Server Name + if ( p[i+k+2] ) { + break; // Name badness + } + unsigned int name_length = ( 256 * p[i+k+3] ) + p[i+k+4]; + unsigned char *path = &p[i+k+5]; + memcpy( buffer, path, name_length ); + buffer[ name_length ] = '\0'; + return buffer; + } + k += length; + } + // This point is only reached on "missing or bad SNI". + view_payload( data, length ); + return 0; +} + +/** + * HTTP traffic includes a data packet with the host name as a + * "Host:" attribute. + */ +static unsigned char *http_host(unsigned char *data,int length) { + unsigned char *body = data + sizeof( struct headers ); + if ( ( strncmp( (char*) body, "GET ", 4 ) != 0 ) && + ( strncmp( (char*) body, "POST ", 5 ) != 0 ) ) { + return 0; + } + unsigned char *end = data + length - 6; + int check = 0; + for ( ; body < end; body++ ) { + if ( check ) { + if ( strncmp( (char*) body, "Host:", 5 ) == 0 ) { + body += 5; + for( ; body < end; body++ ) if ( *body != ' ' ) break; + unsigned char *start = body; + int n = 0; + for( ; body < end; n++, body++ ) if ( *body <= ' ' ) break; + if ( n < 5 ) { + return 0; + } + memcpy( buffer, start, n ); + buffer[ n ] = '\0'; + return buffer; + } + if ( strncmp( (char*) body, "\r\n", 2 ) == 0 ) { + return 0; + } + for( ; body < end; body++ ) if ( *body == '\n' ) break; + if ( body >= end ) { + return 0; + } + } + check = ( *body == '\n' ); + } + return 0; +} + +/** + * Callback function to handle a packet. + */ +static int cb( + struct nfq_q_handle *qh, + struct nfgenmsg *nfmsg, + struct nfq_data *nfa, void *code ) +{ + u_int32_t id = get_packet_id( nfa ); + unsigned char *data; + int length = nfq_get_payload( nfa, &data); + int verdict = NF_ACCEPT; + u_int32_t ip4 = get_dest_ip4( data ); +#if 0 + fprintf( stderr, "PKT %s %d\n", tell_ip( ip4 ), length ); +#endif + if ( length >= 100 ) { + unsigned char *host = http_host( data, length ); +#if 1 + fprintf( stderr, "HTTP HOST %s %s\n", tell_ip( ip4 ), host ); +#endif + if ( host == 0 ) { + host = ssl_host( data, length ); +#if 1 + fprintf( stderr, "SSL HOST %s %s\n", tell_ip( ip4 ), 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( ip4 ), hash_code( host ), host, ix ); +#endif + if ( ix > 0 ) { + verdict = NF_DROP; + } + } else if ( i > 0 ) { + verdict = NF_DROP; + } + } + } + return nfq_set_verdict(qh, id, verdict, 0, NULL); +} + +/** + * Program main function. + */ +int main(int argc, char **argv) { + // Load the database + start_domain_database_loading(); + int n = 1; + for ( ; n < argc; n++ ) { + fprintf( stderr, "Loading blacklist %s\n", argv[ n ] ); + load_domains( argv[ n ] ); + } + end_domain_database_loading(); + + struct nfq_handle *h; + struct nfq_q_handle *qh; + //struct nfnl_handle *nh; + int fd; + int rv; + char buf[4096] __attribute__ ((aligned)); + + fprintf( stderr, "opening library handle\n"); + h = nfq_open(); + if ( !h ) { + fprintf(stderr, "error during nfq_open()\n"); + exit(1); + } + + fprintf( stderr, "unbinding 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" ); + 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 ); + qh = nfq_create_queue( h, THEQUEUE, &cb, NULL ); + if ( !qh ) { + fprintf(stderr, "error during nfq_create_queue()\n"); + exit(1); + } + + fprintf( stderr, "setting copy_packet mode\n" ); + if ( nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff ) < 0) { + fprintf(stderr, "can't set packet_copy mode\n"); + exit(1); + } + + fd = nfq_fd( h ); + + while ( ( rv = recv(fd, buf, sizeof(buf), 0) ) && rv >= 0 ) { + //printf( "pkt received\n" ); + nfq_handle_packet(h, buf, rv); + } + + fprintf( stderr, "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"); + nfq_unbind_pf(h, AF_INET); +#endif + + fprintf( stderr, "closing library handle\n"); + nfq_close( h ); + + exit( 0 ); +} diff --git a/src/ssl.txt b/src/ssl.txt new file mode 100644 index 0000000..9dbe988 --- /dev/null +++ b/src/ssl.txt @@ -0,0 +1,42 @@ +const unsigned char good_data_2[] = { + // TLS record + 0x16, // [0] Content Type: Handshake + 0x03, 0x01, // [1,2] Version: TLS 1.0 + 0x00, 0x6c, // [3,4] Length (use for bounds checking) + // Handshake + 0x01, // [5] Handshake Type: Client Hello + 0x00, 0x00, 0x68, // [6,7,8] Length (use for bounds checking) + 0x03, 0x03, // [9,10] Version: TLS 1.2 + // [11,,42] Random (32 bytes fixed length) + 0xb6, 0xb2, 0x6a, 0xfb, 0x55, 0x5e, 0x03, 0xd5, + 0x65, 0xa3, 0x6a, 0xf0, 0x5e, 0xa5, 0x43, 0x02, + 0x93, 0xb9, 0x59, 0xa7, 0x54, 0xc3, 0xdd, 0x78, + 0x57, 0x58, 0x34, 0xc5, 0x82, 0xfd, 0x53, 0xd1, + 0x00, // [43] Session ID Length (skip past this much) + 0x00, 0x04, // [44,45] Cipher Suites Length (skip past this much) + 0x00, 0x01, // NULL-MD5 + 0x00, 0xff, // RENEGOTIATION INFO SCSV + 0x01, // Compression Methods Length (skip past this much) + 0x00, // NULL + 0x00, 0x3b, // Extensions Length (use for bounds checking) + // Extension + 0x00, 0x00, // Extension Type: Server Name (check extension type) + 0x00, 0x0e, // Length (use for bounds checking) + 0x00, 0x0c, // Server Name Indication Length + 0x00, // Server Name Type: host_name (check server name type) + 0x00, 0x09, // Length (length of your data) + // "localhost" (data your after) + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, + // Extension + 0x00, 0x0d, // Extension Type: Signature Algorithms (check extension type) + 0x00, 0x20, // Length (skip past since this is the wrong extension) + // Data + 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, + 0x05, 0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, + 0x04, 0x02, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, + 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, + // Extension + 0x00, 0x0f, // Extension Type: Heart Beat (check extension type) + 0x00, 0x01, // Length (skip past since this is the wrong extension) + 0x01 // Mode: Peer allows to send requests +}; -- 2.39.2