handle both ipv4 and ipv6
authorRalph Ronnquist <rrq@rrq.au>
Mon, 17 Feb 2025 06:23:14 +0000 (17:23 +1100)
committerRalph Ronnquist <rrq@rrq.au>
Mon, 17 Feb 2025 06:23:14 +0000 (17:23 +1100)
src/nfblocker.c

index b8b979cb0fb4e78c4b3997ffd8dab00a85702ad3..b889d36a10ac03cb1771bb0e1273906c122042ea 100644 (file)
@@ -1,7 +1,9 @@
 #include <linux/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <netinet/tcp.h>
+#include <arpa/inet.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -29,38 +31,66 @@ static u_int32_t get_packet_id(struct nfq_data *tb) {
     return ( ph )? ntohl( ph->packet_id ) : 0;
 }
 
-// Payload headers
-struct headers {
-    struct ip first;
+struct ipv4_pkt {
+    struct ip first;          // .ip_dst[4 bytes]
     struct tcphdr second;
-    //unsigned char pad[12]; // ??
 };
 
-///////// Debugging
+struct ipv6_pkt {
+    struct ip6_hdr first;     // .ip6_dst[16 bytes]
+    struct tcphdr second;
+};
 
-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;
+// Payload packet
+struct packet {
+    union {
+       unsigned int packet_type:4; // 4 or 6
+       struct ipv4_pkt packet4;
+       struct ipv6_pkt packet6;
+    } p;
+    //unsigned char pad[12]; // ??
+};
+
+static struct packet *get_headerP(unsigned char *data) {
+    return (struct packet *) data;
 }
 
-static u_int32_t get_dest_ip4(unsigned char *data) {
-    struct headers *p = (struct headers *) data;
-    return p->first.ip_dst.s_addr;
+///////// 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.packet_type ) {
+    case 4:
+       return inet_ntop( AF_INET, &ip->p.packet4.first.ip_dst, THEIP, 200 );
+    case 6:
+       return inet_ntop( AF_INET6, &ip->p.packet6.first.ip6_dst, THEIP, 200 );
+    }
+    return strcpy( THEIP, "???" );
 }
 
 /**
  * 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 );
+    struct packet *header = get_headerP( data );
+    u_int16_t port = 0;
+    u_int8_t syn = 0;
+    unsigned char *body = data ;//+ sizeof( struct packet );
+    switch ( header->p.packet_type ) {
+    case 4:
+       port = ntohs( ((struct ipv4_pkt *) data )->second.th_dport );
+       syn = sizeof( struct ipv4_pkt );
+       break;
+    case 6:
+       port = ntohs( ((struct ipv6_pkt *) data )->second.th_dport );
+       syn = sizeof( struct ipv6_pkt );
+       break;
+    }
 #define END 400
     unsigned char * end = body + ( ( length > END )? END : length );
-    fprintf( stderr, "%s %d %d %d ", tell_ip( ip4 ), syn, port, length );
+    fprintf( stderr, "%s %d %d %d ", tell_ip( header ), syn, port, length );
     while ( body < end ) {
        unsigned char c = *body++;
        if ( c < ' ' || c >= 127 || 1 ) {
@@ -81,7 +111,17 @@ static unsigned char buffer[1000];
  */
 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;
+    unsigned char *p;
+    switch ( ((struct packet *) data)->p.packet_type ) {
+    case 4:
+       p = data + sizeof( struct ipv4_pkt ) + 12; //??
+       break;
+    case 6:
+       p = data + sizeof( struct ipv6_pkt ) + 0; //??
+       break;
+    default:
+       return 0;
+    }
     if ( p[0] != 0x16 || p[1] != 0x03 || p[5] != 0x01 || p[6] != 0x00 ) {
        return 0;
     }
@@ -127,7 +167,17 @@ static unsigned char *ssl_host(unsigned char *data,int length) {
  * "Host:" attribute.
  */
 static unsigned char *http_host(unsigned char *data,int length) {
-    unsigned char *body = data + sizeof( struct headers );
+    unsigned char *body = data + sizeof( struct packet );
+    switch ( ((struct packet *) data)->p.packet_type ) {
+    case 4:
+       body = data + sizeof( struct ipv4_pkt );
+       break;
+    case 6:
+       body = data + sizeof( struct ipv6_pkt );
+       break;
+    default:
+       return 0;
+    }
     if ( ( strncmp( (char*) body, "GET ", 4 ) != 0 ) &&
         ( strncmp( (char*) body, "POST ", 5 ) != 0 ) ) {
        return 0;
@@ -174,19 +224,19 @@ static int cb(
     unsigned char *data;
     int length = nfq_get_payload( nfa, &data);
     int verdict = NF_ACCEPT;
-    u_int32_t ip4 = get_dest_ip4( data );
+    struct packet *header = get_headerP( data );
 #if 0
-    fprintf( stderr, "PKT %s %d\n", tell_ip( ip4 ), length );
+    fprintf( stderr, "PKT %s %d\n", tell_ip( header ), 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 );
+           fprintf( stderr, "HTTP HOST %s %s\n", tell_ip( header ), host );
 #endif
        if ( host == 0 ) {
            host = ssl_host( data, length );
 #if 1
-           fprintf( stderr, "SSL HOST %s %s\n", tell_ip( ip4 ), host );
+           fprintf( stderr, "SSL HOST %s %s\n", tell_ip( header ), host );
 #endif
        }
        if ( host ) {
@@ -196,7 +246,7 @@ static int cb(
                add_cache( host, ix );
 #if 1
                fprintf( stderr, "%s %d %s ** %d\n",
-                        tell_ip( ip4 ), hash_code( host ), host, ix );
+                        tell_ip( header ), hash_code( host ), host, ix );
 #endif
                if ( ix > 0 ) {
                    verdict = NF_DROP;