D- как проверить, что IP-адрес действителен - PullRequest
3 голосов
/ 23 февраля 2012

Я пишу библиотеку разбора HTTP (потому что я не смог найти хорошую в чистом D), и мне нужно было иметь возможность проверять IP-адреса (для поля URI), поэтому я написал пару функций дляпроверить IP-адреса:

Для IPv4:

bool isIPv4(string addr) {
    int parts;
    ulong idx;

    foreach (i, c; addr) {
        if (c == '.') {
            if (i == 0) {
                return false;
            }

            if (to!int(addr[idx..i]) > 255) {
                return false;
            }

            parts++;
            if (parts > 3) {
                return false;
            }

            idx = i + 1;
        } else if (!isDigit(c)) {
            return false;
        }
    }

    if (to!int(addr[idx..addr.length]) > 255) {
        return false;
    }

    if (parts != 3) {
        return false;
    }

    return true;
}

И для IPv6:

bool isIPv6(string addr) {
    bool isColon, hasSeparator, hasIPv4;
    int leftChunks, rightChunks, digits;

    foreach (i, c; addr) {
        if (isHexDigit(c)) {
            digits = isColon ? 1 : digits + 1;
            isColon = false;

            if (digits == 1) {
                if (hasSeparator) {
                    rightChunks++;
                } else {
                    leftChunks++;
                }
            } else if (digits > 4) {
                return false;
            }
        } else if (c == ':') {
            if (isColon) {
                // multiple :: separators not allowed
                // as is :::
                if (hasSeparator) {
                    return false;
                }
                hasSeparator = true;
            } else {
                isColon = true;
            }
        } else if (c == '.') {
            if (hasSeparator) {
                rightChunks--;
            } else {
                leftChunks--;
            }

            if (!isIPv4(addr[i - digits .. addr.length])) {
                return false;
            }

            hasIPv4 = true;
            break;
        }
    }

    if (hasIPv4) {
        if (hasSeparator) {
            if (rightChunks + leftChunks > 5) {
                return false;
            }
        } else if (leftChunks != 6) {
            return false;
        }
    } else if (digits > 0) {
        if (hasSeparator) {
            if (rightChunks + leftChunks > 7) {
                return false;
            }
        } else if (leftChunks != 8) {
            return false;
        }
    }

    return true;
}

Сначала я попытался создать регулярное выражение для IPv6, но это было больно,тем более что существует очень много особых случаев (::), и я думаю, что столкнулся с ошибкой компиляции регулярного выражения, потому что она была очень длинной.Очевидно, я хотел бы использовать некоторую стандартную функцию, чтобы сделать это для меня.

FWIW, у меня был реализован валидатор IPv4 с использованием std.arrays.split, затем я решил просто сделать это таким образом, потому что в противном случаепришлось бы обнаруживать или ловить исключения из std.conv.to! int.

Большое спасибо!

Примечание

Я бы в конечном итоге хотел быпостарайтесь получить часть кода, который я написал на Фобосе, поэтому я хотел бы, чтобы код был максимально надежным.

Ответы [ 4 ]

2 голосов
/ 23 февраля 2012

Как насчет parseAddress из std.socket ?

1 голос
/ 23 февраля 2012

@ tjameson: Давным-давно я взломал свой собственный модуль uri.Вот код: http://codepad.org/PBm5BEVP.Я всегда хотел вернуться к этому модулю, улучшить его и отправить запрос на извлечение на GitHub, но у меня никогда не было времени сделать это ... URI RFC также имеет регулярное выражение для парсинга адресов IPv6 внутри URI, что определенноЯ бы вставил в этот код.

0 голосов
/ 17 марта 2012

Попробуйте:

IPv4

/^(((2[0-4]|1\d|[1-9])?\d|25[0-5])(\.(?!$)|$)){4}$

IPv6

/^((?=(?=(.*?::))\2(?!.+::))(::)?([\dA-F]{1,4}:(:|(?!$))|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:(?!$)|$))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])(\.(?!$)|$)){4})$/i

(с использованием синтаксиса ECMAscript)

От: http://home.deds.nl/~aeron/regex/

0 голосов
/ 23 февраля 2012

Вы можете использовать функцию inet_pton (), предоставляемую операционной системой. Он проанализирует адрес и сообщит вам, если это не так. Смотри http://www.kernel.org/doc/man-pages/online/pages/man3/inet_pton.3.html

Он будет анализировать адреса IPv4 и IPv6, а inet_ntop () может использоваться для преобразования проанализированного адреса обратно в его каноническую нотацию.

...