diff --git a/spec/std/socket/address_spec.cr b/spec/std/socket/address_spec.cr index 55290b91f2c1..67c9cd33ec17 100644 --- a/spec/std/socket/address_spec.cr +++ b/spec/std/socket/address_spec.cr @@ -127,6 +127,18 @@ describe Socket::IPAddress do Socket::IPAddress.valid_port?(-1).should be_false Socket::IPAddress.valid_port?(65_536).should be_false end + + it "#private?" do + Socket::IPAddress.new("192.168.0.1", 0).private?.should be_true + Socket::IPAddress.new("192.100.0.1", 0).private?.should be_false + Socket::IPAddress.new("172.16.0.1", 0).private?.should be_true + Socket::IPAddress.new("172.10.0.1", 0).private?.should be_false + Socket::IPAddress.new("10.0.0.1", 0).private?.should be_true + Socket::IPAddress.new("1.1.1.1", 0).private?.should be_false + Socket::IPAddress.new("fd00::1", 0).private?.should be_true + Socket::IPAddress.new("fb00::1", 0).private?.should be_false + Socket::IPAddress.new("2001:4860:4860::8888", 0).private?.should be_false + end end describe Socket::UNIXAddress do diff --git a/src/socket/address.cr b/src/socket/address.cr index aa43f01b2470..fb490d9af816 100644 --- a/src/socket/address.cr +++ b/src/socket/address.cr @@ -208,7 +208,7 @@ class Socket def loopback? : Bool case addr = @addr in LibC::InAddr - addr.s_addr & 0x00000000ff_u32 == 0x0000007f_u32 + addr.s_addr & 0x000000ff_u32 == 0x0000007f_u32 in LibC::In6Addr ipv6_addr8(addr) == StaticArray[0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 1_u8] end @@ -224,6 +224,21 @@ class Socket end end + # Returns `true` if this IP is a private address. + # + # IPv4 addresses in `10.0.0.0/8`, `172.16.0.0/12` and `192.168.0.0/16` as defined in [RFC 1918](https://tools.ietf.org/html/rfc1918) + # and IPv6 Unique Local Addresses in `fc00::/7` as defined in [RFC 4193](https://tools.ietf.org/html/rfc4193) are considered private. + def private? : Bool + case addr = @addr + in LibC::InAddr + addr.s_addr & 0x000000ff_u32 == 0x00000000a_u32 || # 10.0.0.0/8 + addr.s_addr & 0x000000f0ff_u32 == 0x0000010ac_u32 || # 172.16.0.0/12 + addr.s_addr & 0x000000ffff_u32 == 0x0000a8c0_u32 # 192.168.0.0/16 + in LibC::In6Addr + ipv6_addr8(addr)[0] & 0xfe_u8 == 0xfc_u8 + end + end + private def ipv6_addr8(addr : LibC::In6Addr) {% if flag?(:darwin) || flag?(:bsd) %} addr.__u6_addr.__u6_addr8