Standard/safe way to check if IP address is in range/subnet
Asked Answered
E

1

8

I have a small piece of code that converts a 32-bit unsigned integer (ie: uint32_t) into a set of four 8-bit fields, treats it like an IP address, and then reports to the client if it falls within a predetermined range of IP addresses.

I've already found a few different examples of code in C that shows me how to get the IP address of a client from the struct sockaddr_in that contains it, along with a C# answer. However, I would like to break down the address a bit further, keep it in pure C, and wanted to know a few quick things:

  1. Is the internal representation consistent from system to system, or do I ever need to do Endian-ness checks/correction on the s_addr field?
  2. Are there standard macros along the lines of CLASS_C_NETMASK, CLASS_B_NETMASK, etc, that would be more appropriate than using manually generated masks (ie: 0xFF000000, 0x00FF0000, etc).
  3. Are there any existing functions in the sockets library that will do checks if an IP address is in a range of IP addresses or matches a subnet mask?

Thanks.

Ecclesiastes answered 25/6, 2015 at 2:27 Comment(2)
s_addr is always in "network byte order", which is big-endian.Baumann
You can't go wrong looking at Beej's Guide to Network Programming. Add that to your list of references/examples to check. (his other guides are good as well)Democratize
B
19

Is the internal representation consistent from system to system, or do I ever need to do Endian-ness checks/correction on the s_addr field?

s_addr is always in network (big endian) byte order on all platforms.

Are there standard macros along the lines of CLASS_C_NETMASK, CLASS_B_NETMASK, etc, that would be more appropriate than using manually generated masks (ie: 0xFF000000, 0x00FF0000, etc).

No, nor would it make sense to use such macros, as subnet masks are not fixed from one network to another. You need to provide your code with an actual network IP and its subnet mask (prompt the user, query the OS, etc). You can then calculate the subnet's starting and ending IPs to compare against your target 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...

Or simpler, mask both network IP and target IP with the subnet mask and see if the resulting values are the same (ie, they are the same subnet):

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...

Are there any existing functions in the sockets library that will do checks if an IP address is in a range of IP addresses or matches a subnet mask?

No. But it is trivial to implement manually, it only takes a few lines of code, as shown above.

Bumptious answered 25/6, 2015 at 4:17 Comment(4)
very helpful solution, thanks! I might suggest subtracting 1 from netend to get the last address on the subnet.Prevailing
The last address on the subnet is the subnet's broadcast IP. Masking the network IP with the subnet mask produces the broadcast IP, which is still technically part of the subnet. If you don't want to allow the broadcast IP in the comparison, you could subtract 1 from netend, or you could change <= netend to < netend, or you could mask the target IP with the inverse of the subnet mask and see if the result is the same value as the mask (if so, the target is a broadcast IP).Bumptious
it fails when netmask is 32, any idea why?Forgiven
32 is hex 0x20, binary 00100000. The high bits of that subnet mask are not contiguous 1-bits. That is not technically illegal in IPv4 (it is on IPv6), but it is discouraged and rarely used in practice. The high bits of a subnet mask should always be contiguous 1-bits.Bumptious

© 2022 - 2024 — McMap. All rights reserved.