Search RPD Archives
Limit search to: Subject & Body Subject Author
Sort by:

[rpd] Reserved Space/Available Space and potential hijacking

Andrew Alston aa at alstonnetworks.net
Wed Oct 15 12:20:51 UTC 2025


Haha - Understood Ben - and as (not so subtly requested) - find below the
commented code.

//

//  main.c

//  AfrinicAudit

//

//  Created by Andrew Alston on 15/10/2025.

//  Code is considered open use with no restrictions.

//


#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <arpa/inet.h>


// Location of BGP Dump file

*char* BGP_DUMP[256] = "/Users/aalston/audit/bgp.dump.txt";

// Location of Afrinic Extended Stats File

*char* AFRINIC_EXT[256] =
"/Users/aalston/audit/delegated-afrinic-extended-latest";



// Structure to contain route data

*struct* routes {

    *unsigned* *int* network;

    *unsigned* *int* broadcast;

    *unsigned* *int* mask;

    *unsigned* *short* cidr;

};


// Audit structure into which we parse all our data before comparison

*struct* audit {

    *struct* routes *dfz;

    *int* dfz_count;

    *struct* routes *reserved;

    *int* total_resv;

    *int* rc;

    *struct* routes *available;

    *int* total_avail;

    *int* ac;

};


// parse_afrinic_extended parses the extended statistics file into the
audit structure

// afext parameter is the file location of the afrinic extended stats file

// output is a pointer to an audit restructure

*int* parse_afrinic_extended(*char* *afext, *struct* audit *output) {

    FILE *dump = fopen(afext, "r");

    *if*(!dump)

        *return* -1;

    *char* buffer[1024] = {0};

    *char* *delim;

    output->rc = 0;

    // Run through the entire extended file isolating lines where the space
is marked as reserved

    *while*(fgets(buffer, 1024, dump)) {

        *if*(strstr(buffer, "ZZ") && strstr(buffer, "reserved") &&
strstr(buffer,
"ipv4")) {

            output->rc++;

        }

    }

    // Allocate sufficient route structures for storing the reserved blocks

    output->reserved = calloc(output->rc, *sizeof*(*struct* routes));

    *if*(!output->reserved)

        *return* -1;

    output->rc = 0;

    *struct* routes *resv = output->reserved;

    // Rewind the file pointer to the start of the file so we can re-run
through the file parsing it this time

    rewind(dump);

    *while*(fgets(buffer, 1024, dump)) {

        // Check if this is a line matching reserved space

        *if*(strstr(buffer, "ZZ") && strstr(buffer, "reserved") &&
strstr(buffer,
"ipv4")) {

            // Tokenize the line such that delim becomes a pointer to the
start of the network address

            delim = strtok(buffer, "|");

            *for*(*int* i = 0; i < 3; i++)

                delim = strtok(*NULL*, "|");

            // Convert the network address to a big endian formatted integer

            inet_pton(AF_INET, delim, &resv[output->rc].network);

            // Swap the byte ordering of the saved network address to
little endian to make computations easier

            resv[output->rc].network = __builtin_bswap32(resv[output->rc].
network);

            // Jump to the next token so that delim points to the start of
the number of addresses in the block

            delim = strtok(*NULL*, "|");

            // Convert number of addresses to an integer

            *unsigned* *int* addr_count = atoi(delim);

            output->total_resv += addr_count;

            // Broadcast is calculated by taking the number of addresses
less 1 and adding it to the little endian

            // network address

            resv[output->rc].broadcast = resv[output->rc].network
+(addr_count-1);

            // Swap the network and broadcast back to big endian format

            resv[output->rc].network = __builtin_bswap32(resv[output->rc].
network);

            resv[output->rc].broadcast = __builtin_bswap32(resv[output->rc].
broadcast);

            // Calculate the subnet mask by taking a 1s compliment of the
address count less 1 and flipping endianness

            resv[output->rc].mask = ~__builtin_bswap32((*unsigned* *int*
)addr_count-1);

            // Increment the reserved route count.

            output->rc++;

        }

    }

    // Rewind the file pointer again

    rewind(dump);

    // Count the number of lines matching available space

    *while*(fgets(buffer, 1024, dump)) {

        *if*(strstr(buffer, "ZZ") && strstr(buffer, "available") &&
strstr(buffer,
"ipv4")) {

            output->ac++;

        }

    }

    output->available = calloc(output->ac, *sizeof*(*struct* routes));

    *if*(!output->available)

        *return* -1;

    *struct* routes *avail = output->available;

    // Rewind the file pointer again so we can run through the file again

    rewind(dump);

    *while*(fgets(buffer, 1024, dump)) {

        // Match lines for available space

        // Rest of the code in this function uses identical code to what we
used above for reserved files,

        // So comments in the above apply here as well

        *if*(strstr(buffer, "ZZ") && strstr(buffer, "available") &&
strstr(buffer,
"ipv4")) {

            delim = strtok(buffer, "|");

            *for*(*int* i = 0; i < 3; i++)

                delim = strtok(*NULL*, "|");

            inet_pton(AF_INET, delim, &avail[output->ac].network);

            avail[output->ac].network = __builtin_bswap32(avail[output->ac].
network);

            delim = strtok(*NULL*, "|");

            *unsigned* *int* addr_count = atoi(delim);

            output->total_avail += addr_count;

            avail[output->ac].broadcast = avail[output->ac].network
+(addr_count-1);

            avail[output->ac].mask = ~__builtin_bswap32((*unsigned* *int*
)addr_count-1);

            output->ac++;

        }

    }

    fclose(dump);

    *return* 0;

}


// parse_dfz parses the bgp dump file

*int* parse_dfz(*char* *dfz_dump, *struct* audit *output) {

    FILE *dump = fopen(dfz_dump, "r");

    *char* buffer[1024] = {0};

    *int* rc = 0, mult = 0, cidr = 0;

    *char* *delim;

    *if*(!dump) {

        *return* -1;

    }

    // Run through the dump file to get a count of matching routes.

    // The match here is made by checking for lines that start with a
number between 1 and 9, contain a / and also contain a .

    // This was the easiest way to match lines in the BGP dump from a
juniper

    *while*(fgets(buffer, 1024, dump)) {

        *if*(buffer[0] >= '1' && buffer[0] <= '9' && strtok(buffer, "/") &&
strchr(buffer, '.')) {

            rc++;

        }

    }

    output->dfz = calloc(rc, *sizeof*(*struct* routes));

    output->dfz_count = rc;

    *if*(!output->dfz) {

        *return* -1;

    }

    // Rewind the file pointer to run through again

    rewind(dump);

    rc = 0;

    *while*(fgets(buffer, 1024, dump)) {

        // Match lines that start with a number between 1 and 9

        *if*(buffer[0] >= '1' && buffer[0] <= '9') {

            cidr = 0;

            // Tokenize to get the CIDR deliminator

            delim = strtok(buffer, "/");

            delim = strtok(*NULL*, "/");

            // If there is no CIDR deliminator, skip this line after
resetting the buffer

            *if*(!delim) {

                memset(buffer, 0, 1024);

                *continue*;

            }

            // This code is essentially a manual ascii to integer to
calculate the CIDR from the text

            mult = 1;

            *for*(*int* i = 0; i < 3; i++) {

                *if*(delim[i] >= '0' && delim[i] <= '9') {

                    cidr = cidr * mult+(9-('9'-delim[i]));

                    mult*=10;

                }

            }

            // Check if the line contains a . - if it doesnt the line is
skipped, this avoids IPv6 lines

            // in the BGP dump

            delim = strchr(buffer, '.');

            *if*(!delim) {

                memset(buffer, 0, 1024);

                *continue*;

            }

            // Save the CIDR

            output->dfz[rc].cidr = cidr;

            // Save the network in big endian format

            inet_pton(AF_INET, buffer, &output->dfz[rc].network);

            output->dfz[rc].cidr = cidr;

            // Swap the network to little endian format

            output->dfz[rc].network = __builtin_bswap32((*unsigned* *int*
)output->dfz[rc].network);

            // Calculate the subnet mask using a 1s compliment of zero
shifted by 32 minus the CIDR bits

            output->dfz[rc].mask = (~(*unsigned* *int*)0) << (32-cidr);

            // Calculate the broadcast by adding a 1s compliment of zero
shifted right by the CIDR

            output->dfz[rc].broadcast = output->dfz[rc].network + ((~(
*unsigned* *int*)0) >> cidr);

            // Convert the network and broadcast back to big endian format

            output->dfz[rc].network = __builtin_bswap32((*unsigned* *int*
)output->dfz[rc].network);

            output->dfz[rc].broadcast = __builtin_bswap32((*unsigned* *int*
)output->dfz[rc].broadcast);

            rc++;

            memset(buffer, 0, 1024);

        }

    }

    fclose(dump);

    *return* 0;

}


// audit_reserved uses a pre-populated audit structure to audit the afrinic
reserved and available address

// space against the routes in the DFZ dump file

*int* audit_reserved(*struct* audit *data) {

    *int* hijack_count = 0;

    *int* prefix_count = 0;

    // Cycle through all the routes in the DFZ

    *for*(*int* i = 0; i < data->dfz_count; i++) {

        // Get little endian routes for the DFZ network and broadcast

        *unsigned* *int* dfz_net = __builtin_bswap32((*unsigned* *int*
)data->dfz[i].network);

        *unsigned* *int* dfz_bcast = __builtin_bswap32((*unsigned* *int*
)data->dfz[i].broadcast);

        // Cycle through the reserved routes in an inner loop

        *for*(*int* r = 0; r < data->rc; r++) {

            // Get the little endian versions of the reserved network and
broadcasts

            *unsigned* *int* resv_net = __builtin_bswap32((*unsigned* *int*
)data->reserved[r].network);

            *unsigned* *int* resv_bcast = __builtin_bswap32((*unsigned*
*int*)data->reserved[r].broadcast);

            // If the DFZ network in little endian format is greater than
or equal to the reserved network

            // and less than or equal to the reserved broadcast - the route
falls in the reserved range

            *if*(dfz_net >= resv_net && dfz_net <= resv_bcast) {

                // Add to the hijack count using an address count
calculated by subtracting the

                // dfz network address from the dfz broadcast address

                hijack_count += ((dfz_bcast-dfz_net)+1);

                prefix_count++;

                *char* dfz_route[INET_ADDRSTRLEN] = {0};

                *char* resv_network[INET_ADDRSTRLEN] = {0};

                *char* resv_broadcast[INET_ADDRSTRLEN] = {0};

                // Convert the numeric networks and broadcast addresses to
strings for printing

                inet_ntop(AF_INET, &data->dfz[i].network, dfz_route,
INET_ADDRSTRLEN);

                inet_ntop(AF_INET, &data->reserved[r].network,
resv_network, INET_ADDRSTRLEN);

                inet_ntop(AF_INET, &data->reserved[r].broadcast,
resv_broadcast, INET_ADDRSTRLEN);

                // Print potential hijacked routes in the reserved range

                printf("%s/%d fell between reserved range %s -> %s [Adding
%d addresses to potential hijack]\n",

                       dfz_route, data->dfz[i].cidr, resv_network,
resv_broadcast, (dfz_bcast-dfz_net)+1);

            }

        }

        // Comments for the inner loop for reserved range apply equally to
the below inner loop which

        // processes against available routes in the afrinic extended file

        *for*(*int* a = 0; a < data->ac; a++) {

            *unsigned* *int* avail_net = __builtin_bswap32((*unsigned* *int*
)data->available[a].network);

            *unsigned* *int* avail_bcast = __builtin_bswap32((*unsigned*
*int*)data->available[a].broadcast);

            *if*(dfz_net >= data->available[a].network && dfz_net <= data->
available[a].broadcast) {

                hijack_count += ((data->available[a].broadcast-data->
available[a].network)+1);

                prefix_count++;

                *char* dfz_route[INET_ADDRSTRLEN] = {0};

                *char* avail_network[INET_ADDRSTRLEN] = {0};

                *char* avail_broadcast[INET_ADDRSTRLEN] = {0};

                inet_ntop(AF_INET, &data->dfz[i].network, dfz_route,
INET_ADDRSTRLEN);

                inet_ntop(AF_INET, &avail_net, avail_network,
INET_ADDRSTRLEN);

                inet_ntop(AF_INET, &avail_bcast, avail_broadcast,
INET_ADDRSTRLEN);

                printf("%s/%d fell between available range %s -> %s\n",
dfz_route, data->dfz[i].cidr, avail_network, avail_broadcast);

            }

        }

    }

    printf("Found %d potentially hijacked addresses from %d prefixes\n",
hijack_count, prefix_count);

    *return* 0;

}


*int* main(*int* argc, *const* *char* * argv[]) {

    *struct* audit data = {0};

    // Call the DFZ file parser, expecting a zero return if all is well

    *if*(parse_dfz(BGP_DUMP, &data))

        *return* EXIT_FAILURE;

    // Call the afrinic extended parser, expecting a zero return if all is
well

    *if*(parse_afrinic_extended(AFRINIC_EXT, &data))

        *return* EXIT_FAILURE;

    // Print the total available and reserved addresses found by the
afrinic extended parser

    printf("Found %d total available addresses and %d total reserved
addresses\n", data.total_avail, data.total_resv);

    // Run the audit

    audit_reserved(&data);

    *return* EXIT_SUCCESS;

}

On Wed, Oct 15, 2025 at 2:55 PM <ben.roberts at afrinic.net> wrote:

> This is great Andrew.  I feel like we should have more of this sort of
> thing and perhaps an IP address research hackathon  will be a great idea.
>
>
>
> Your c is pretty good, I will give you a tip though.
>
>
>
> 2 useful features of c are to use // or /* */ to insert comments in the
> code
>
> e.g.
>
> // This is a comment
>
> Or
>
> /* This is a comment*/
>
>
>
> The comments aren’t compiled in the code so you can write anything you
> like.  Using comments like this is really helpful when sharing code with
> others, to help them understand it…
>
>
>
>
>
> 😊😊😊
>
>
>
> *From:* Andrew Alston <aa at alstonnetworks.net>
> *Sent:* 15 October 2025 14:41
> *To:* RPD <rpd at afrinic.net>
> *Subject:* [rpd] Reserved Space/Available Space and potential hijacking
>
>
>
> Hi Guys,
>
>
>
> So - Firstly a few notes on using the code I'm going to paste below.
>
>
>
> I created the BGP dump file on a juniper router by running a "show route
> protocol bgp | save bgp.dump.txt" and then copying that dump file to my
> local system from the Juniper router.  Note - this produces a roughly
> 400meg file on a full table router and it takes quite a while to run the
> command.
>
> Then - I used the delegated-afrinic-extended-latest file downloaded from
> the stats ftp server.
>
>
>
> In the code below - if you wish to run similar - change the char
> BGP_DUMP[256] and char AFRINIC_EXT[256] global variables to match the
> pathing to the relevant files.
>
>
>
> Note that there is some weirdness in this code to deal with endianness -
> and I will openly admit its not the cleanest (or probably most efficient)
> code - but it does work and I've verified the results.
>
>
>
> I've pasted the code below the results section.
>
>
>
> So - first the results:
>
>
>
> Found 824064 total available addresses and 4482304 total reserved addresses
> 41.57.124.0/22 fell between reserved range 41.57.124.0 -> 41.57.127.255
> [Adding 1024 addresses to potential hijack]
> 41.57.124.0/23 fell between reserved range 41.57.124.0 -> 41.57.127.255
> [Adding 512 addresses to potential hijack]
> 41.57.124.0/24 fell between reserved range 41.57.124.0 -> 41.57.127.255
> [Adding 256 addresses to potential hijack]
> 41.57.125.0/24 fell between reserved range 41.57.124.0 -> 41.57.127.255
> [Adding 256 addresses to potential hijack]
> 41.57.126.0/24 fell between reserved range 41.57.124.0 -> 41.57.127.255
> [Adding 256 addresses to potential hijack]
> 41.57.127.0/24 fell between reserved range 41.57.124.0 -> 41.57.127.255
> [Adding 256 addresses to potential hijack]
> 41.77.64.0/21 fell between reserved range 41.77.64.0 -> 41.77.71.255
> [Adding 2048 addresses to potential hijack]
> 41.138.192.0/24 fell between reserved range 41.138.192.0 ->
> 41.138.223.255 [Adding 256 addresses to potential hijack]
> 41.204.224.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.225.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.226.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.227.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.228.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.229.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.230.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.231.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.232.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.233.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.234.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.235.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.236.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.237.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.238.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.239.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.240.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.241.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.242.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.243.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.244.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.245.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.246.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.247.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.248.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.249.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.250.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.251.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.254.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.204.255.0/24 fell between reserved range 41.204.224.0 ->
> 41.204.255.255 [Adding 256 addresses to potential hijack]
> 41.205.224.0/19 fell between reserved range 41.205.224.0 ->
> 41.205.255.255 [Adding 8192 addresses to potential hijack]
> 41.205.225.0/24 fell between reserved range 41.205.224.0 ->
> 41.205.255.255 [Adding 256 addresses to potential hijack]
> 41.205.232.0/24 fell between reserved range 41.205.224.0 ->
> 41.205.255.255 [Adding 256 addresses to potential hijack]
> 41.205.234.0/24 fell between reserved range 41.205.224.0 ->
> 41.205.255.255 [Adding 256 addresses to potential hijack]
> 41.205.235.0/24 fell between reserved range 41.205.224.0 ->
> 41.205.255.255 [Adding 256 addresses to potential hijack]
> 41.205.237.0/24 fell between reserved range 41.205.224.0 ->
> 41.205.255.255 [Adding 256 addresses to potential hijack]
> 41.205.238.0/24 fell between reserved range 41.205.224.0 ->
> 41.205.255.255 [Adding 256 addresses to potential hijack]
> 41.205.239.0/24 fell between reserved range 41.205.224.0 ->
> 41.205.255.255 [Adding 256 addresses to potential hijack]
> 41.220.48.0/20 fell between reserved range 41.220.48.0 -> 41.220.63.255
> [Adding 4096 addresses to potential hijack]
> 80.88.6.0/24 fell between reserved range 80.88.6.0 -> 80.88.6.255 [Adding
> 256 addresses to potential hijack]
> 102.128.74.0/24 fell between reserved range 102.128.72.0 ->
> 102.128.75.255 [Adding 256 addresses to potential hijack]
> 102.135.164.0/24 fell between reserved range 102.135.164.0 ->
> 102.135.167.255 [Adding 256 addresses to potential hijack]
> 102.135.165.0/24 fell between reserved range 102.135.164.0 ->
> 102.135.167.255 [Adding 256 addresses to potential hijack]
> 102.135.166.0/24 fell between reserved range 102.135.164.0 ->
> 102.135.167.255 [Adding 256 addresses to potential hijack]
> 102.219.128.0/24 fell between reserved range 102.219.128.0 ->
> 102.219.131.255 [Adding 256 addresses to potential hijack]
> 102.219.129.0/24 fell between reserved range 102.219.128.0 ->
> 102.219.131.255 [Adding 256 addresses to potential hijack]
> 102.219.130.0/24 fell between reserved range 102.219.128.0 ->
> 102.219.131.255 [Adding 256 addresses to potential hijack]
> 102.221.148.0/22 fell between reserved range 102.221.144.0 ->
> 102.221.151.255 [Adding 1024 addresses to potential hijack]
> 156.0.254.0/24 fell between reserved range 156.0.254.0 -> 156.0.254.255
> [Adding 256 addresses to potential hijack]
> 160.119.208.0/24 fell between reserved range 160.119.208.0 ->
> 160.119.211.255 [Adding 256 addresses to potential hijack]
> 160.119.209.0/24 fell between reserved range 160.119.208.0 ->
> 160.119.211.255 [Adding 256 addresses to potential hijack]
> 164.160.192.0/21 fell between reserved range 164.160.192.0 ->
> 164.160.223.255 [Adding 2048 addresses to potential hijack]
> 169.255.164.0/22 fell between reserved range 169.255.164.0 ->
> 169.255.167.255 [Adding 1024 addresses to potential hijack]
> 193.188.7.0/24 fell between reserved range 193.188.7.0 -> 193.188.7.255
> [Adding 256 addresses to potential hijack]
> 196.13.203.0/24 fell between reserved range 196.13.203.0 ->
> 196.13.203.255 [Adding 256 addresses to potential hijack]
> 196.20.60.0/24 fell between reserved range 196.20.32.0 -> 196.20.63.255
> [Adding 256 addresses to potential hijack]
> 196.20.61.0/24 fell between reserved range 196.20.32.0 -> 196.20.63.255
> [Adding 256 addresses to potential hijack]
> 196.20.62.0/24 fell between reserved range 196.20.32.0 -> 196.20.63.255
> [Adding 256 addresses to potential hijack]
> 196.41.74.0/24 fell between reserved range 196.41.74.0 -> 196.41.74.255
> [Adding 256 addresses to potential hijack]
> 196.43.252.0/24 fell between reserved range 196.43.252.0 ->
> 196.43.252.255 [Adding 256 addresses to potential hijack]
> 196.46.18.0/24 fell between reserved range 196.46.18.0 -> 196.46.19.255
> [Adding 256 addresses to potential hijack]
> 196.46.19.0/24 fell between reserved range 196.46.18.0 -> 196.46.19.255
> [Adding 256 addresses to potential hijack]
> 196.46.152.0/24 fell between reserved range 196.46.152.0 ->
> 196.46.159.255 [Adding 256 addresses to potential hijack]
> 196.46.153.0/24 fell between reserved range 196.46.152.0 ->
> 196.46.159.255 [Adding 256 addresses to potential hijack]
> 196.46.154.0/23 fell between reserved range 196.46.152.0 ->
> 196.46.159.255 [Adding 512 addresses to potential hijack]
> 196.50.21.0/24 fell between reserved range 196.50.21.0 -> 196.50.21.255
> [Adding 256 addresses to potential hijack]
> 196.53.113.0/24 fell between reserved range 196.52.0.0 -> 196.55.255.255
> [Adding 256 addresses to potential hijack]
> 196.54.72.0/23 fell between reserved range 196.52.0.0 -> 196.55.255.255
> [Adding 512 addresses to potential hijack]
> 196.55.102.0/23 fell between reserved range 196.52.0.0 -> 196.55.255.255
> [Adding 512 addresses to potential hijack]
> 196.63.243.0/24 fell between reserved range 196.62.0.0 -> 196.63.255.255
> [Adding 256 addresses to potential hijack]
> 196.195.4.0/24 fell between reserved range 196.194.0.0 -> 196.195.255.255
> [Adding 256 addresses to potential hijack]
> 196.195.15.0/24 fell between reserved range 196.194.0.0 ->
> 196.195.255.255 [Adding 256 addresses to potential hijack]
> 196.195.253.0/24 fell between reserved range 196.194.0.0 ->
> 196.195.255.255 [Adding 256 addresses to potential hijack]
> 197.157.200.0/22 fell between reserved range 197.157.200.0 ->
> 197.157.203.255 [Adding 1024 addresses to potential hijack]
> 197.231.248.0/22 fell between reserved range 197.231.248.0 ->
> 197.231.251.255 [Adding 1024 addresses to potential hijack]
> 197.231.248.0/24 fell between reserved range 197.231.248.0 ->
> 197.231.251.255 [Adding 256 addresses to potential hijack]
> 197.231.249.0/24 fell between reserved range 197.231.248.0 ->
> 197.231.251.255 [Adding 256 addresses to potential hijack]
> 197.231.250.0/24 fell between reserved range 197.231.248.0 ->
> 197.231.251.255 [Adding 256 addresses to potential hijack]
> 197.231.251.0/24 fell between reserved range 197.231.248.0 ->
> 197.231.251.255 [Adding 256 addresses to potential hijack]
> 197.234.208.0/24 fell between reserved range 197.234.208.0 ->
> 197.234.215.255 [Adding 256 addresses to potential hijack]
> 212.12.224.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.225.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.226.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.227.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.229.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.231.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.232.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.233.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.234.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.235.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.236.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.237.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.238.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.239.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.240.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.241.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.242.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.243.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.244.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.245.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.246.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.247.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.248.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.249.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.250.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.251.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.252.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.254.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> 212.12.255.0/24 fell between reserved range 212.12.224.0 ->
> 212.12.255.255 [Adding 256 addresses to potential hijack]
> Found 50176 potentially hijacked addresses
>
>
>
> --- Below here is the code (I didn't know if I could send attachments to
> the RPD list so I just pasted the code straight) ---
>
>
>
> //
> //  main.c
> //  AfrinicAudit
> //
> //  Created by Andrew Alston on 15/10/2025.
> //  Code is considered open use with no restrictions.
> //
>
> #include <stdlib.h>
> #include <stdio.h>
> #include <string.h>
> #include <arpa/inet.h>
>
> char BGP_DUMP[256] = "/Users/aalston/audit/bgp.dump.txt";
> char AFRINIC_EXT[256] =
> "/Users/aalston/audit/delegated-afrinic-extended-latest";
>
> struct routes {
>     unsigned int network;
>     unsigned int broadcast;
>     unsigned int mask;
>     unsigned short cidr;
> };
>
> struct audit {
>     struct routes *dfz;
>     int dfz_count;
>     struct routes *reserved;
>     int total_resv;
>     int rc;
>     struct routes *available;
>     int total_avail;
>     int ac;
> };
>
> int parse_afrinic_extended(char *afext, struct audit *output) {
>     FILE *dump = fopen(afext, "r");
>     if(!dump)
>         return -1;
>     char buffer[1024] = {0};
>     char *delim;
>     output->rc = 0;
>     while(fgets(buffer, 1024, dump)) {
>         if(strstr(buffer, "ZZ") && strstr(buffer, "reserved") &&
> strstr(buffer, "ipv4")) {
>             output->rc++;
>         }
>     }
>     output->reserved = calloc(output->rc, sizeof(struct routes));
>     if(!output->reserved)
>         return -1;
>     output->rc = 0;
>     struct routes *resv = output->reserved;
>     rewind(dump);
>     while(fgets(buffer, 1024, dump)) {
>         if(strstr(buffer, "ZZ") && strstr(buffer, "reserved") &&
> strstr(buffer, "ipv4")) {
>             delim = strtok(buffer, "|");
>             for(int i = 0; i < 3; i++)
>                 delim = strtok(NULL, "|");
>             inet_pton(AF_INET, delim, &resv[output->rc].network);
>             resv[output->rc].network =
> __builtin_bswap32(resv[output->rc].network);
>             delim = strtok(NULL, "|");
>             unsigned int addr_count = atoi(delim);
>             output->total_resv += addr_count;
>             resv[output->rc].broadcast =
> resv[output->rc].network+(addr_count-1);
>             resv[output->rc].network =
> __builtin_bswap32(resv[output->rc].network);
>             resv[output->rc].broadcast =
> __builtin_bswap32(resv[output->rc].broadcast);
>             resv[output->rc].mask = ~__builtin_bswap32((unsigned
> int)addr_count-1);
>             output->rc++;
>         }
>     }
>     rewind(dump);
>     while(fgets(buffer, 1024, dump)) {
>         if(strstr(buffer, "ZZ") && strstr(buffer, "available") &&
> strstr(buffer, "ipv4")) {
>             output->ac++;
>         }
>     }
>     output->available = calloc(output->ac, sizeof(struct routes));
>     if(!output->available)
>         return -1;
>     struct routes *avail = output->available;
>     rewind(dump);
>     while(fgets(buffer, 1024, dump)) {
>         if(strstr(buffer, "ZZ") && strstr(buffer, "available") &&
> strstr(buffer, "ipv4")) {
>             delim = strtok(buffer, "|");
>             for(int i = 0; i < 3; i++)
>                 delim = strtok(NULL, "|");
>             inet_pton(AF_INET, delim, &avail[output->ac].network);
>             avail[output->ac].network =
> __builtin_bswap32(avail[output->ac].network);
>             delim = strtok(NULL, "|");
>             unsigned int addr_count = atoi(delim);
>             output->total_avail += addr_count;
>             avail[output->ac].broadcast =
> avail[output->ac].network+(addr_count-1);
>             avail[output->ac].mask = ~__builtin_bswap32((unsigned
> int)addr_count-1);
>             output->ac++;
>         }
>     }
>     fclose(dump);
>     return 0;
> }
>
> int parse_dfz(char *dfz_dump, struct audit *output) {
>     FILE *dump = fopen(dfz_dump, "r");
>     char buffer[1024] = {0};
>     int rc = 0, mult = 0, cidr = 0;
>     char *delim;
>     if(!dump) {
>         return -1;
>     }
>     while(fgets(buffer, 1024, dump)) {
>         if(buffer[0] >= '1' && buffer[0] <= '9' && strtok(buffer, "/") &&
> strchr(buffer, '.')) {
>             rc++;
>         }
>     }
>     output->dfz = calloc(rc, sizeof(struct routes));
>     output->dfz_count = rc;
>     if(!output->dfz) {
>         return -1;
>     }
>     rewind(dump);
>     rc = 0;
>     while(fgets(buffer, 1024, dump)) {
>         if(buffer[0] >= '1' && buffer[0] <= '9') {
>             cidr = 0;
>             delim = strtok(buffer, "/");
>             delim = strtok(NULL, "/");
>             if(!delim) {
>                 memset(buffer, 0, 1024);
>                 continue;
>             }
>             mult = 1;
>             for(int i = 0; i < 3; i++) {
>                 if(delim[i] >= '0' && delim[i] <= '9') {
>                     cidr = cidr * mult+(9-('9'-delim[i]));
>                     mult*=10;
>                 }
>             }
>             delim = strchr(buffer, '.');
>             if(!delim) {
>                 memset(buffer, 0, 1024);
>                 continue;
>             }
>             output->dfz[rc].cidr = cidr;
>             inet_pton(AF_INET, buffer, &output->dfz[rc].network);
>             output->dfz[rc].cidr = cidr;
>             output->dfz[rc].network = __builtin_bswap32((unsigned
> int)output->dfz[rc].network);
>             output->dfz[rc].mask = (~(unsigned int)0) << (32-cidr);
>             output->dfz[rc].broadcast = output->dfz[rc].network +
> ((~(unsigned int)0) >> cidr);
>             output->dfz[rc].network = __builtin_bswap32((unsigned
> int)output->dfz[rc].network);
>             output->dfz[rc].broadcast = __builtin_bswap32((unsigned
> int)output->dfz[rc].broadcast);
>             rc++;
>             memset(buffer, 0, 1024);
>         }
>     }
>     fclose(dump);
>     return 0;
> }
>
> int audit_reserved(struct audit *data) {
>     int hijack_count = 0;
>     for(int i = 0; i < data->dfz_count; i++) {
>         unsigned int dfz_net = __builtin_bswap32((unsigned
> int)data->dfz[i].network);
>         unsigned int dfz_bcast = __builtin_bswap32((unsigned
> int)data->dfz[i].broadcast);
>         for(int r = 0; r < data->rc; r++) {
>             unsigned int resv_net = __builtin_bswap32((unsigned
> int)data->reserved[r].network);
>             unsigned int resv_bcast = __builtin_bswap32((unsigned
> int)data->reserved[r].broadcast);
>             if(dfz_net >= resv_net && dfz_net <= resv_bcast) {
>                 hijack_count += ((dfz_bcast-dfz_net)+1);
>                 char dfz_route[INET_ADDRSTRLEN] = {0};
>                 char resv_network[INET_ADDRSTRLEN] = {0};
>                 char resv_broadcast[INET_ADDRSTRLEN] = {0};
>                 inet_ntop(AF_INET, &data->dfz[i].network, dfz_route,
> INET_ADDRSTRLEN);
>                 inet_ntop(AF_INET, &data->reserved[r].network,
> resv_network, INET_ADDRSTRLEN);
>                 inet_ntop(AF_INET, &data->reserved[r].broadcast,
> resv_broadcast, INET_ADDRSTRLEN);
>                 printf("%s/%d fell between reserved range %s -> %s [Adding
> %d addresses to potential hijack]\n",
>                        dfz_route, data->dfz[i].cidr, resv_network,
> resv_broadcast, (dfz_bcast-dfz_net)+1);
>             }
>         }
>         for(int a = 0; a < data->ac; a++) {
>             unsigned int avail_net = __builtin_bswap32((unsigned
> int)data->available[a].network);
>             unsigned int avail_bcast = __builtin_bswap32((unsigned
> int)data->available[a].broadcast);
>             if(dfz_net >= data->available[a].network && dfz_net <=
> data->available[a].broadcast) {
>                 hijack_count +=
> ((data->available[a].broadcast-data->available[a].network)+1);
>                 char dfz_route[INET_ADDRSTRLEN] = {0};
>                 char avail_network[INET_ADDRSTRLEN] = {0};
>                 char avail_broadcast[INET_ADDRSTRLEN] = {0};
>                 inet_ntop(AF_INET, &data->dfz[i].network, dfz_route,
> INET_ADDRSTRLEN);
>                 inet_ntop(AF_INET, &avail_net, avail_network,
> INET_ADDRSTRLEN);
>                 inet_ntop(AF_INET, &avail_bcast, avail_broadcast,
> INET_ADDRSTRLEN);
>                 printf("%s/%d fell between available range %s -> %s\n",
> dfz_route, data->dfz[i].cidr, avail_network, avail_broadcast);
>             }
>         }
>     }
>     printf("Found %d potentially hijacked addresses\n", hijack_count);
>     return 0;
> }
>
> int main(int argc, const char * argv[]) {
>     struct audit data = {0};
>     if(parse_dfz(BGP_DUMP, &data))
>         return EXIT_FAILURE;
>     if(parse_afrinic_extended(AFRINIC_EXT, &data))
>         return EXIT_FAILURE;
>     printf("Found %d total available addresses and %d total reserved
> addresses\n", data.total_avail, data.total_resv);
>     audit_reserved(&data);
>     return EXIT_SUCCESS;
> }
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.afrinic.net/pipermail/rpd/attachments/20251015/dd336f26/attachment-0001.html>


More information about the RPD mailing list