root/sbin/ipf/libipf/parsewhoisline.c
/*
 * Copyright (C) 2012 by Darren Reed.
 *
 * See the IPFILTER.LICENCE file for details on licencing.
 *
 * $Id: parsewhoisline.c,v 1.2.2.5 2012/07/22 08:04:24 darren_r Exp $
 */
#include "ipf.h"

/*
Microsoft Corp MICROSOFT19 (NET-198-136-97-0-1) 198.137.97.0 - 198.137.97.255
Microsoft Corp SAVV-S233053-6 (NET-206-79-74-32-1) 206.79.74.32 - 206.79.74.47
 */
int
parsewhoisline(char *line, addrfamily_t *addrp, addrfamily_t *maskp)
{
        struct in_addr a1, a2;
        char *src = line;
        char *s = NULL;

        if (line == NULL)
                return (-1);

        while (*src != '\0') {
                s = strchr(src, '(');
                if (s == NULL)
                        break;

                if (strncmp(s, "(NET", 4)) {
                        src = s + 1;
                }
                break;
        }

        if (s == NULL)
                return (-1);

        memset(addrp, 0x00, sizeof(*maskp));
        memset(maskp, 0x00, sizeof(*maskp));

        if (*(s + 4) == '6') {
#ifdef USE_INET6
                i6addr_t a61, a62;

                s = strchr(s, ')');
                if (s == NULL || *++s != ' ')
                        return (-1);
                /*
                 * Parse the IPv6
                 */
                if (inet_pton(AF_INET6, s, &a61.in6) != 1)
                        return (-1);

                s = strchr(s, ' ');
                if (s == NULL || strncmp(s, " - ", 3))
                        return (-1);

                s += 3;
                if (inet_pton(AF_INET6, s, &a62) != 1)
                        return (-1);

                addrp->adf_addr = a61;
                addrp->adf_family = AF_INET6;
                addrp->adf_len = offsetof(addrfamily_t, adf_addr) +
                                 sizeof(struct in6_addr);

                maskp->adf_addr.i6[0] = ~(a62.i6[0] ^ a61.i6[0]);
                maskp->adf_addr.i6[1] = ~(a62.i6[1] ^ a61.i6[1]);
                maskp->adf_addr.i6[2] = ~(a62.i6[2] ^ a61.i6[2]);
                maskp->adf_addr.i6[3] = ~(a62.i6[3] ^ a61.i6[3]);

                /*
                 * If the mask that's been generated isn't a consecutive mask
                 * then we can't add it into a pool.
                 */
                if (count6bits(maskp->adf_addr.i6) == -1)
                        return (-1);

                maskp->adf_family = AF_INET6;
                maskp->adf_len = addrp->adf_len;

                if (IP6_MASKNEQ(&addrp->adf_addr.in6, &maskp->adf_addr.in6,
                                &addrp->adf_addr.in6)) {
                        return (-1);
                }
                return (0);
#else
                return (-1);
#endif
        }

        s = strchr(s, ')');
        if (s == NULL || *++s != ' ')
                return (-1);

        s++;

        if (inet_aton(s, &a1) != 1)
                return (-1);

        s = strchr(s, ' ');
        if (s == NULL || strncmp(s, " - ", 3))
                return (-1);

        s += 3;
        if (inet_aton(s, &a2) != 1)
                return (-1);

        addrp->adf_addr.in4 = a1;
        addrp->adf_family = AF_INET;
        addrp->adf_len = offsetof(addrfamily_t, adf_addr) +
                         sizeof(struct in_addr);
        maskp->adf_addr.in4.s_addr = ~(a2.s_addr ^ a1.s_addr);

        /*
         * If the mask that's been generated isn't a consecutive mask then
         * we can't add it into a pool.
         */
        if (count4bits(maskp->adf_addr.in4.s_addr) == -1)
                return (-1);

        maskp->adf_family = AF_INET;
        maskp->adf_len = addrp->adf_len;
        bzero((char *)maskp + maskp->adf_len, sizeof(*maskp) - maskp->adf_len);
        if ((addrp->adf_addr.in4.s_addr & maskp->adf_addr.in4.s_addr) !=
            addrp->adf_addr.in4.s_addr)
                return (-1);
        return (0);
}