Skip to content

Commit

Permalink
Add Socket::IPAddress#private? (#9517)
Browse files Browse the repository at this point in the history
Co-authored-by: Brian J. Cardiff <bcardiff@gmail.com>
  • Loading branch information
jgillich and bcardiff authored Jan 15, 2021
1 parent 9d7e162 commit b5e6df6
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
12 changes: 12 additions & 0 deletions spec/std/socket/address_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ describe Socket::IPAddress do
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

it "#==" do
Socket::IPAddress.new("127.0.0.1", 8080).should eq Socket::IPAddress.new("127.0.0.1", 8080)
Socket::IPAddress.new("127.0.0.1", 8080).hash.should eq Socket::IPAddress.new("127.0.0.1", 8080).hash
Expand Down
17 changes: 16 additions & 1 deletion src/socket/address.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit b5e6df6

Please sign in to comment.