2014-12-27 3 views
4

Мне нужно сохранить IP-адреса/сетевые маски в структуре in_addr/in6_addr. Для IPv4 я использую следующий код, чтобы проверить, если маска подсети смежный:Эффективный способ проверки, если побитовая сетевая маска IPv6 смежна

((((~netmask + 1) & (~netmask)) != 0) && (netmask != 0)) 

мне было интересно, если есть умный способ сделать то же самое для IPv6.

+0

Как вы храните маску? – chepner

+0

'~ netmask + 1' совпадает с' -netmask' в дополнении 2, так почему бы вам не использовать его? Это короче –

+0

@chepner маску, хранящуюся в структуре in6_addr. – evelina

ответ

1

Некоторые компиляторы имеют 128-битные целые числа. Я использовал __uint128_t в коде, который был скомпилирован с использованием gcc на архитектуре AMD64.

Если вы используете компилятор с 128-битными целыми числами, вы можете просто повторно использовать существующий код, поскольку он не делает никаких предположений о размере слова.

Если вам нужно выполнить расчет с меньшим размером слова, он, естественно, усложняется, но не очень. Первый запуск указателя Уст масок, чтобы найти первое слово с нулевым битом (например):

for (i = 0; i < 4 && netmask[i] != 0xffffffff; ++i) 

Далее вы можете применить свой оригинальный тест на netmask[i], наконец, вам нужно проверить, что все оставшиеся слова равны нулю.

Другой подход, чтобы применить оригинальный тест к каждому отдельному слову и, кроме того теста, что каждая пара слов имеет первую быть все те или второй все нули:

int contiguous(uint32_t **netmask) 
{ 
    int i; 
    for (i = 0; i < 4; ++i) { 
     if ((~netmask[i] + 1) & (~netmask[i])) return 0; 
    } 
    for (i = 0; i < 3; ++i) { 
     if ((netmask[i] != 0xffffffff) && (netmask[i+1] != 0)) return 0; 
    } 
    return 1; 
} 

Вы также можете взять более общий подход и не принимать маску в качестве входных данных, а вместо этого использовать длину префикса, указанную как целое число в диапазоне от 0 до 128 в качестве входного. Затем вы можете сами создать битмаску и знать, что она смежна.

+0

Я думаю, что последнее для утверждения неверно. – evelina

1

я наткнулся на следующее решение:

Разделить IPV6 байт в четырех кусках 32 бит и создать три части следующим образом:

uint64_t netmask1, netmask2, netmask3; 
netmask1 = (netmask.s6_addr32[0] << 32) + in6_netmask.s6_addr32[1]; 
netmask2 = (netmask.s6_addr32[1] << 32) + in6_netmask.s6_addr32[2]; 
netmask3 = (netmask.s6_addr32[2] << 32) + in6_netmask.s6_addr32[3]; 

Если одна из этих частей не является непрерывным, то сетевая маска не является непрерывной.

if ((((~address1 + 1) & (~address1)) != 0) || 
    (((~address2 + 1) & (~address2)) != 0) || 
    ((~address3 + 1) & (~address3)) != 0))) { 
    // Netmask is not valid! 
}