The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include <stdio.h>
#include <stdlib.h>

#include "ip-tools.h"

#ifdef HEADER

/* '0.0.0.0' is not a valid IP address, so this uses the value 0 to
   indicate an invalid IP address. */

#define INVALID_IP 0
#define NOTFOUND -1

typedef struct {
    unsigned start;
    unsigned end;
}
ip_block_t;

#endif /* HEADER */

/* Convert the character string in "ip" into an unsigned integer.

   This assumes that an unsigned integer contains at least 32 bits. */

unsigned int ip_tools_ip_to_int (const char * ip)
{
    /* The return value. */
    unsigned v = 0;
    /* The count of the number of bytes processed. */
    int i;
    /* A pointer to the next digit to process. */
    const char * start;

    start = ip;
    for (i = 0; i < 4; i++) {
        /* The digit being processed. */
        char c;
        /* The value of this byte. */
        int n = 0;
        while (1) {
            c = * start;
            start++;
            if (c >= '0' && c <= '9') {
                n *= 10;
                n += c - '0';
            }
            /* We insist on stopping at "." if we are still parsing
               the first, second, or third numbers. If we have reached
               the end of the numbers, we will allow any character. */
            else if ((i < 3 && c == '.') || i == 3) {
                break;
            }
            else {
                return INVALID_IP;
            }
        }
        if (n >= 256) {
            return INVALID_IP;
        }
        v *= 256;
        v += n;
    }
    return v;
}

/* Search for "ip" in the structure "ip_blocks". "n_ip_ranges" is the
   total number of members in "ip_blocks". */

int ip_tools_ip_range (ip_block_t * ip_blocks, int n_ip_ranges, unsigned ip)
{
    int i;
    int division;
    int count = 0;

    division = n_ip_ranges / 2;
    i = division;
    while (1) {
        count++;
        if (count > 100) {
            /* Trap for possible errors. 2^100 should be big
               enough. */
            fprintf (stderr, "There is bad logic in the search.\n");
            return NOTFOUND;
        }
        division /= 2;
        if (division == 0) {
            division = 1;
        }
        // printf ("i is %d/%d; Division is %d\n", i, n_ip_ranges, division);
        if (ip >= ip_blocks[i].start) {
            if (ip <= ip_blocks[i].end) {
                /* "ip" is between the start and end of block i. */
                return i;
            }
            else if (ip < ip_blocks[i + 1].start) {
                /* "ip" is between the end of block i and the start of
                    block i+1 */
                return NOTFOUND;
            }
            else {
                /* Go up a bit and continue searching. */
                i += division;
            }
        }
        else {
            /* Go down a bit and continue searching. */
            i -= division;
        }
        if (i > n_ip_ranges - 1 || i < 0) {
            /* "i" has gone outside the boundaries. */
            return NOTFOUND;
        }
    }
}