Определите, находится ли IPv6-адрес в пределах диапазона, используя Objective- C - PullRequest
1 голос
/ 02 февраля 2020

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

Я получил несколько советов, которые пытались сделать это сопоставление диапазонов не является хорошим подходом, или не практичным / бесполезным для IPv6, и что вместо этого я должен рассмотреть сопоставление префиксов. Прежде чем идти по этому пути, я хотел бы посмотреть, какие эффективные решения могут существовать для определения, является ли адрес IPv6 заданным диапазоном.

Я не эксперт по сетевым технологиям, поэтому прошу прощения за некоторые мои незнания в этом Вопрос.

Я нашел это сообщение о переполнении стека с непринятым ответом, указывающим, что лучший способ сделать это - преобразовать все шестнадцатеричные значения адреса IPv6 в двоичный файл и затем выполнить сравнение. Две проблемы с этим постом: 1. Я не уверен, как адаптировать скрипт PHP в Objective- C, и 2. Этот ответ имеет некоторые положительные отзывы, но не является принятым ответом, поэтому я не уверен это стоит продолжить.

Я также нашел этот другой пост Переполнения стека, который, кажется, хорошо работает для преобразования шестнадцатеричных значений в двоичные, но, опять же, я не уверен, как сделать сравнение между результирующие двоичные значения для определения диапазона. Обратите внимание, что я использую пример кода из вопроса, а не ответа. Адаптация этого кода для моих целей дает мне вывод, подобный следующему, используя пример IPv6-адреса fe80::34cb:9850:4868:9d2c:

fe80 = 1111111010000000
0000 = 0
0000 = 0
0000 = 0
34cb = 11010011001011
9850 = 1001100001010000
4868 = 100100001101000
9d2c = 1001110100101100

Конечный результат, которого я пытаюсь достичь, - это способность реагировать, когда Ma c ' s IP-адрес находится в пределах определенного диапазона. У меня есть решение для адресов IPv4, но я хочу добавить поддержку IPv6 в мое бесплатное приложение macOS, Amphetamine. Спасибо заранее за любую помощь. Это то, что я использую для проверки диапазона IPv4 ... не уверен, что он может быть адаптирован для использования с IPv6:

- (bool) ipAddress: (NSString *)ipAddress isBetweenIpAddress: (NSString *)rangeStart andIpAddress: (NSString *)rangeEnd
{
    uint32_t ip = [self convertIpAddress: ipAddress];
    uint32_t start = [self convertIpAddress: rangeStart];
    uint32_t end = [self convertIpAddress: rangeEnd];
    return ip >= start && ip <= end;
}

- (uint32_t) convertIpAddress: (NSString *) ipAddress
{
    struct sockaddr_in sin;
    inet_aton([ipAddress UTF8String], &sin.sin_addr);
    return ntohl(sin.sin_addr.s_addr);
}

1 Ответ

1 голос
/ 02 февраля 2020

Эта проблема требует двух шагов: (1) анализировать адрес и диапазон начала / конца строки; (2) сравнить значения. API, доступные для обеих частей, основаны на C и поэтому не особенно удобны для пользователя.

  • inet_pton можно использовать для анализа строки и ее помещения в in6_addr struct.
  • in6_addr содержит .s6_addr, который представляет собой массив из 16 байтов в порядке с прямым порядком байтов,
  • …, который можно сравнить с другой адрес с memcmp.

Собираем его вместе:

NSString *rangeStart = @"2001:db8::";
NSString *rangeEnd = @"2001:db8::ffff:ffff:ffff:ffff";

NSString *address = @"2001:db8::abc";

// Parse strings into in6_addrs
struct in6_addr rangeStartAddr;
struct in6_addr rangeEndAddr;
struct in6_addr addr;
if (inet_pton(AF_INET6, rangeStart.UTF8String, &rangeStartAddr) != 1) {
    abort();
}
if (inet_pton(AF_INET6, rangeEnd.UTF8String, &rangeEndAddr) != 1) {
    abort();
}
if (inet_pton(AF_INET6, address.UTF8String, &addr) != 1) {
    abort();
}

// Use memcmp to compare binary values
if (memcmp(rangeStartAddr.s6_addr, addr.s6_addr, 16) <= 0
    && memcmp(addr.s6_addr, rangeEndAddr.s6_addr, 16) <= 0) {
    NSLog(@"In range");
} else {
    NSLog(@"Not in range");
}

Было бы также возможно, но беспорядочно, преобразовать каждый адрес в один __uint128_t номер. Однако, если все, что вам нужно сделать, это сравнить, memcmp кажется достаточным.


То же самое можно сделать в Swift, используя UnsafeRawBufferPointer.lexicographicallyPrecedes вместо memcmp:

import Darwin

extension in6_addr {
    init?(_ str: String) {
        self.init()
        if inet_pton(AF_INET6, str, &self) != 1 {
            return nil
        }
    }
}

extension in6_addr: Comparable {
    public static func ==(lhs: in6_addr, rhs: in6_addr) -> Bool {
        return withUnsafeBytes(of: lhs) { lhsBytes in
            withUnsafeBytes(of: rhs) { rhsBytes in
                lhsBytes.prefix(16).elementsEqual(rhsBytes.prefix(16))
            }
        }
    }
    public static func <(lhs: in6_addr, rhs: in6_addr) -> Bool {
        return withUnsafeBytes(of: lhs) { lhsBytes in
            withUnsafeBytes(of: rhs) { rhsBytes in
                lhsBytes.prefix(16).lexicographicallyPrecedes(rhsBytes.prefix(16))
            }
        }
    }
}

var rangeStartAddr = in6_addr("2001:db8::")!
var rangeEndAddr = in6_addr("2001:db8::ffff:ffff:ffff:ffff")!
var addr = in6_addr("2001:db8::abc")!

(rangeStartAddr...rangeEndAddr).contains(addr)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...