2015-06-25 5 views
0

У меня есть небольшой фрагмент кода, который преобразует 32-разрядное целое без знака (то есть: uint32_t) в набор из четырех 8-битных полей, обрабатывает его как IP-адрес, а затем сообщает клиенту, если он попадает в заданный диапазон IP-адресов.Стандартный/безопасный способ проверить, находится ли IP-адрес в диапазоне/подсети

Я already found несколько different examples кода в C, который показывает мне, как получить IP-адрес клиента из struct sockaddr_in, который его содержит, по with a C# answer. Тем не менее, я хотел бы, чтобы сломать адрес немного дальше, держите его в чистом C, и хотел бы знать несколько простых вещей:

  1. это внутреннее представление согласуется от системы к системе, или я когда-нибудь понадобится делать проверки/коррекции Endian-ness на поле s_addr?
  2. Существуют ли стандартные макросы по линиям CLASS_C_NETMASK, CLASS_B_NETMASK и т. Д., Что было бы более подходящим, чем использование созданных вручную масок (то есть: 0xFF000000, 0x00FF0000 и т. Д.).
  3. Существуют ли существующие функции в библиотеке сокетов, которые будут проверять, находится ли IP-адрес в диапазоне IP-адресов или соответствует маске подсети?

Спасибо.

+3

's_addr' всегда находится в« сетевом порядке байтов », который является big-endian. – zneak

+2

Вы не ошибетесь, глядя на [** Руководство Beej по программированию сети **] (http://beej.us/guide/bgnet/). Добавьте это в список ссылок/примеров для проверки. (его другие гиды хороши также) –

+0

@ DavidC.Rankin Спасибо.Хорошая рекомендация к книге очень ценится, так как вопросы, касающиеся «хороших книг по теме xzy», почти мгновенно закрываются на SO. :) – DevNull

ответ

7

Является ли внутреннее представление согласованным от системы к системе, или мне когда-либо нужно делать проверки/исправления Endial-ness в поле s_addr?

s_addr всегда в сети (большой эндиан) на всех платформах.

Существуют стандартные макросы вдоль линий CLASS_C_NETMASK, CLASS_B_NETMASK и т.д., которые были бы более подходящими, чем при использовании вручную сгенерированные маски (то есть: 0xFF000000, 0x00FF0000 и т.д.).

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

uint32_t ip = ...; // value to check 
uint32_t netip = ...; // network ip to compare with 
uint32_t netmask = ...; // network ip subnet mask 
uint32_t netstart = (netip & netmask); // first ip in subnet 
uint32_t netend = (netstart | ~netmask); // last ip in subnet 
if ((ip >= netstart) && (ip <= netend)) 
    // is in subnet range... 
else 
    // not in subnet range... 

Или проще, маска как сетевой IP и целевой IP с маской подсети и посмотреть, если полученные значения совпадают (т.е. они же подсети):

uint32_t ip = ...; // value to check 
uint32_t netip = ...; // network ip to compare with 
uint32_t netmask = ...; // network ip subnet mask 
if ((netip & netmask) == (ip & netmask)) 
    // is on same subnet... 
else 
    // not on same subnet... 

существуют ли какие-либо существующие функции в библиотеке сокетов, которые будут делать проверку, если IP-адрес находится в диапазоне IP-адресов или совпадает с маской подсети?

No. Но тривиально реализовать вручную, для этого требуется всего несколько строк кода, как показано выше.

+1

очень полезное решение, спасибо! Я мог бы предложить вычесть 1 из netend, чтобы получить последний адрес в подсети. –

+2

Последний адрес в подсети - это широковещательный IP-адрес подсети. Маскирование сетевого IP с маской подсети создает широковещательный IP-адрес, который по-прежнему является технически частью подсети. Если вы не хотите разрешать широковещательный IP-адрес в сравнении, вы можете вычесть 1 из 'netend', или вы можете изменить' <= netend' на '

+0

не удается, когда netmask 32, любая идея почему? – foobar