2
\$\begingroup\$

Identify whether an IP address is internal, global, link-local, or reserved.

Input should be an IPv4 address in decimal octets separated by periods.

Output should be 0 for link-local (RFC 3927), 1 for internal (RFC 1918), 2 for global IPs (Internet), and 3 for otherwise reserved addresses.

All these address types are described in RFC 5735:

  1. Global and Other Specialized Address Blocks

    0.0.0.0/8 - Addresses in this block refer to source hosts on "this" network. Address 0.0.0.0/32 may be used as a source address for this host on this network; other addresses within 0.0.0.0/8 may be used to refer to specified hosts on this network ([RFC1122], Section 3.2.1.3).

    10.0.0.0/8 - This block is set aside for use in private networks. Its intended use is documented in [RFC1918]. As described in that
    RFC, addresses within this block do not legitimately appear on the
    public Internet. These addresses can be used without any
    coordination with IANA or an Internet registry.

    127.0.0.0/8 - This block is assigned for use as the Internet host loopback address. A datagram sent by a higher-level protocol to an
    address anywhere within this block loops back inside the host. This
    is ordinarily implemented using only 127.0.0.1/32 for loopback. As
    described in [RFC1122], Section 3.2.1.3, addresses within the entire 127.0.0.0/8 block do not legitimately appear on any network anywhere.

    169.254.0.0/16 - This is the "link local" block. As described in [RFC3927], it is allocated for communication between hosts on a
    single link. Hosts obtain these addresses by auto-configuration,
    such as when a DHCP server cannot be found.

    172.16.0.0/12 - This block is set aside for use in private networks. Its intended use is documented in [RFC1918]. As described in that RFC, addresses within this block do not legitimately appear on the public Internet. These addresses can be used without any coordination with IANA or an Internet registry.

    192.0.0.0/24 - This block is reserved for IETF protocol assignments. At the time of writing this document, there are no current assignments. Allocation policy for future assignments is given in [RFC5736].

    192.0.2.0/24 - This block is assigned as "TEST-NET-1" for use in documentation and example code. It is often used in conjunction with domain names example.com or example.net in vendor and protocol
    documentation. As described in [RFC5737], addresses within this
    block do not legitimately appear on the public Internet and can be
    used without any coordination with IANA or an Internet registry. See [RFC1166].

    192.88.99.0/24 - This block is allocated for use as 6to4 relay anycast addresses, in [RFC3068]. In contrast with previously
    described blocks, packets destined to addresses from this block do
    appear in the public Internet. [RFC3068], Section 7, describes
    operational practices to prevent the malicious use of this block in
    routing protocols.

    192.168.0.0/16 - This block is set aside for use in private networks. Its intended use is documented in [RFC1918]. As described in that RFC, addresses within this block do not legitimately appear on the public Internet. These addresses can be used without any coordination with IANA or an Internet registry.

    198.18.0.0/15 - This block has been allocated for use in benchmark tests of network interconnect devices. [RFC2544] explains that this
    range was assigned to minimize the chance of conflict in case a
    testing device were to be accidentally connected to part of the
    Internet. Packets with source addresses from this range are not
    meant to be forwarded across the Internet.

    198.51.100.0/24 - This block is assigned as "TEST-NET-2" for use in documentation and example code. It is often used in conjunction with domain names example.com or example.net in vendor and protocol
    documentation. As described in [RFC5737], addresses within this
    block do not legitimately appear on the public Internet and can be
    used without any coordination with IANA or an Internet registry.

    203.0.113.0/24 - This block is assigned as "TEST-NET-3" for use in documentation and example code. It is often used in conjunction with domain names example.com or example.net in vendor and protocol
    documentation. As described in [RFC5737], addresses within this
    block do not legitimately appear on the public Internet and can be
    used without any coordination with IANA or an Internet registry.

    224.0.0.0/4 - This block, formerly known as the Class D address space, is allocated for use in IPv4 multicast address assignments.
    The IANA guidelines for assignments from this space are described in
    [RFC3171].

    240.0.0.0/4 - This block, formerly known as the Class E address space, is reserved for future use; see [RFC1112], Section 4.

    The one exception to this is the "limited broadcast" destination
    address 255.255.255.255. As described in [RFC0919] and [RFC0922],
    packets with this destination address are not forwarded at the IP
    layer.

4. Summary Table

Address Block       Present Use                Reference
0.0.0.0/8           "This" Network             RFC 1122, Section 3.2.1.3
10.0.0.0/8          Private-Use Networks       RFC 1918
127.0.0.0/8         Loopback                   RFC 1122, Section 3.2.1.3
169.254.0.0/16      Link Local                 RFC 3927
172.16.0.0/12       Private-Use Networks       RFC 1918
192.0.0.0/24        IETF Protocol Assignments  RFC 5736
192.0.2.0/24        TEST-NET-1                 RFC 5737
192.88.99.0/24      6to4 Relay Anycast         RFC 3068
192.168.0.0/16      Private-Use Networks       RFC 1918
198.18.0.0/15       Network Interconnect
                    Device Benchmark Testing   RFC 2544
198.51.100.0/24     TEST-NET-2                 RFC 5737
203.0.113.0/24      TEST-NET-3                 RFC 5737
224.0.0.0/4         Multicast                  RFC 3171
240.0.0.0/4         Reserved for Future Use    RFC 1112, Section 4
255.255.255.255/32  Limited Broadcast          RFC 919, Section 7
                                               RFC 922, Section 7

Rules

  • Standard loopholes apply.
  • This is , shortest answer wins.
\$\endgroup\$
  • 1
    \$\begingroup\$ For those of us who do not know this stuff, how do the single values here identify "blocks" and what values are "in" said blocks? Also which blocks are (2) and which are (3) (or are all non RFC3927/1918 (3) and everything else (2))? \$\endgroup\$ – Jonathan Allan Nov 12 '16 at 2:38
  • \$\begingroup\$ @JonathanAllan The number after the slash in the IP address is the bitmask. networkengineering.stackexchange.com/questions/3697/… \$\endgroup\$ – dkudriavtsev Nov 12 '16 at 2:41
  • 1
    \$\begingroup\$ That does not help me - I did not even think we would have that part in the input - "decimal octets separated by periods". \$\endgroup\$ – Jonathan Allan Nov 12 '16 at 2:44
  • 2
    \$\begingroup\$ Could you please reformat the summary table so that it exactly shows what should return 0, what should return 1, etc. \$\endgroup\$ – orlp Nov 12 '16 at 6:52
  • 2
    \$\begingroup\$ This question should have some example inputs and outputs. \$\endgroup\$ – Paŭlo Ebermann May 12 '17 at 17:07
3
\$\begingroup\$

JavaScript, 261 207 bytes

v=>["169.254","10.|172.1[6789].|172.2\\d.|172.3[01]|192.168","x","0.|127|192.0.[02].|192.88.99|198.1[89].|198.51.100|203.0.113|2[345]\\d|22[^0123]"].reduce((a,x,i)=>v.search(x.replace(/\./g,"\\."))==0?i:a,2)

Readable version

v=>[
    "169.254",
    "10.|172.1[6789].|172.2\\d.|172.3[01]|192.168",
    "x",
    "0.|127|192.0.[02].|192.88.99|198.1[89].|198.51.100|203.0.113|2[345]\\d|22[^0123]"]
    .reduce((a,x,i)=>v.search(x.replace(/\./g,"\\."))==0?i:a,2)

Create an array with matching patterns, loop through the patterns and compare to input. Return 0,1,2,3 as appropriate.

Edit: Fix bugs and streamline

\$\endgroup\$
  • \$\begingroup\$ I think you can save 18 bytes using (a,x,i)=>x.every(t=>v.search("^"+t.replace(".","\.")))?a:i. \$\endgroup\$ – Neil Nov 12 '16 at 11:29
  • \$\begingroup\$ V('172.16.0.1') => 2 (INVALID),V('172.17.1.1')=> 2 (INVALID), basically the whole "172.16" block does not work correctly. Have you tested this ? There is a syntax error - "\d" not escaped properly, resulting in a literal "d" match, and the patterns for this block are simply not correct too. \$\endgroup\$ – zeppelin Nov 12 '16 at 21:53
  • \$\begingroup\$ 172.16.0.1 returns 1 if you use the short version. I made an error when copying and pasting the "readable" version. As for the patterns being wrong, I made a mistake when calculating that subnet. \$\endgroup\$ – Grax32 Nov 14 '16 at 11:55
  • \$\begingroup\$ The mask for 172.16.0.0 is 12 bits, which means that the address range is: 172.16.0.0-172.31.255.255 (i.e. 172.16.X, 172.17 (!) e.t.c.)). Test: I("172.17.0.1") => 2 (should be 1 instead) \$\endgroup\$ – zeppelin Nov 14 '16 at 12:17
  • \$\begingroup\$ (you can compute the address ranges at iplocation.net/subnet-calculator, to avoid doing that by hand) \$\endgroup\$ – zeppelin Nov 14 '16 at 12:18
1
\$\begingroup\$

ES6 (Javascript), 204, 200, 182, 178 bytes

EDIT: Rewritten hex padding code, removed extra parenthesis, -4 bytes

EDIT: RegExp cleanup, streamline the result extraction, shorten the hex conversion code

EDIT: Refactored result extraction to bring it down to 200 bytes

Note, this should be pretty easy to shorten even further, by compressing the RegExp (as I never really bothered to do this)

Golfed

a=>/(^(?:00|7f|c0(?:5863|0{3}[02])|c6(?:1[23]|3364)|cb0071|e|f))|(^a9fe)|(^0a|^ac1|^c0a8)|./.exec(a.replace(/\d+./g,o=>(o|256).toString(16).slice(1))).reverse().findIndex(a=>a)^1

Explanation

IP addresses are shorter to write and easier to match, when converted to hexadecimal form, as CIDR masks tend to end on the 4 bit boundaries (with an exception of 198.18.0.0/15).

E.g.

0A000000-0AFFFFFF //10.0.0.0/8 
AC100000-AC1FFFFF //172.16.0.0/12
C0A80000-C0A8FFFF //192.168.0.0/16

can be matched as

/^0a|^ac1|^c0a8/

Test

I=a=>/(^(?:00|7f|c0(?:5863|0{3}[02])|c6(?:1[23]|3364)|cb0071|e|f))|(^a9fe)|(^0a|^ac1|^c0a8)|./.exec(a.replace(/\d+./g,o=>(o|256).toString(16).slice(1))).reverse().findIndex(a=>a)^1;

T=(i,o)=>{
  block=I(i);
  console.log(i,(block==o)?"OK":"NOT OK");
}

T("0.0.0.0",3)
T("10.0.0.0",1)
T("11.0.0.0",2)
T("127.0.0.0",3)
T("169.254.0.0",0)
T("169.253.0.0",2)
T("172.16.0.0",1)
T("172.31.0.0",1)
T("172.32.0.0",2)
T("192.0.0.0",3)
T("192.0.2.0",3)
T("192.88.99.0",3)
T("192.168.0.0",1)
T("192.167.0.0",2)
T("198.18.0.0",3)
T("198.51.100.0",3)
T("203.0.113.0",3)
T("224.0.0.0",3)
T("239.255.255.255",3)
T("240.0.0.0",3)
T("255.255.255.255",3)
T("241.0.0.1",3)
T("151.101.192.71",2)
\$\endgroup\$
0
\$\begingroup\$

Batch, 356 bytes

@echo off
set s=%1
if not %s==%s:.=% %0 %s:.= %
if %1.%2==169.254 exit/b0
if %1==10 exit/b1
if %1.%2==172.16 if %3 lss 32 exit/b1
if %1.%2==192.168 exit/b1
if %1==0 exit/b3
if %1==127 exit/b3
if %1 geq 224 exit/b3
for %%a in (18 19)do if %1.%2==192.%a exit/b3
for %%a in (192.0.0 192.0.2 198.51.100 203.0.113)do if %1.%2.%3==%%a exit/b3
exit/b2

Takes input as a command-line parameter and returns the result by setting the errorlevel.

\$\endgroup\$
  • \$\begingroup\$ The "224.0.0.0/4 Multicast" range has a 4 bit mask, which means that it covers the addresses from 224.0.0.0 – 239.255.255.255 (and you only match 224). The same for "240" block. \$\endgroup\$ – zeppelin Nov 12 '16 at 22:02
  • \$\begingroup\$ @zeppelin Ah, so in fact anything >= 224 counts? \$\endgroup\$ – Neil Nov 13 '16 at 1:05
  • \$\begingroup\$ Yep, correct, everything > 224 is either multicast, reserved or broadcast, all of which map to the same output value. \$\endgroup\$ – zeppelin Nov 13 '16 at 17:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.