diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c0f9e1465b..09cdc8afb6 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -281,14 +281,20 @@ proc parseIPv4Address(addressStr: string): IpAddress = byteCount = 0 currentByte: uint16 = 0 separatorValid = false + leadingZero = false result = IpAddress(family: IpAddressFamily.IPv4) for i in 0 .. high(addressStr): if addressStr[i] in strutils.Digits: # Character is a number + if leadingZero: + raise newException(ValueError, + "Invalid IP address. Octal numbers are not allowed") currentByte = currentByte * 10 + cast[uint16](ord(addressStr[i]) - ord('0')) - if currentByte > 255'u16: + if currentByte == 0'u16: + leadingZero = true + elif currentByte > 255'u16: raise newException(ValueError, "Invalid IP Address. Value is out of range") separatorValid = true @@ -300,6 +306,7 @@ proc parseIPv4Address(addressStr: string): IpAddress = currentByte = 0 byteCount.inc separatorValid = false + leadingZero = false else: raise newException(ValueError, "Invalid IP Address. Address contains an invalid character") @@ -388,10 +395,16 @@ proc parseIPv6Address(addressStr: string): IpAddress = result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF) groupCount.inc() else: # Must parse IPv4 address + var leadingZero = false for i, c in addressStr[v4StartPos..high(addressStr)]: if c in strutils.Digits: # Character is a number + if leadingZero: + raise newException(ValueError, + "Invalid IP address. Octal numbers not allowed") currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0')) - if currentShort > 255'u32: + if currentShort == 0'u32: + leadingZero = true + elif currentShort > 255'u32: raise newException(ValueError, "Invalid IP Address. Value is out of range") separatorValid = true @@ -402,6 +415,7 @@ proc parseIPv6Address(addressStr: string): IpAddress = currentShort = 0 byteCount.inc() separatorValid = false + leadingZero = false else: # Invalid character raise newException(ValueError, "Invalid IP Address. Address contains an invalid character") @@ -431,7 +445,12 @@ proc parseIPv6Address(addressStr: string): IpAddress = proc parseIpAddress*(addressStr: string): IpAddress = ## Parses an IP address - ## Raises ValueError on error + ## + ## Raises ValueError on error. + ## + ## For IPv4 addresses, only the strict form as + ## defined in RFC 6943 is considered valid, see + ## https://datatracker.ietf.org/doc/html/rfc6943#section-3.1.1. if addressStr.len == 0: raise newException(ValueError, "IP Address string is empty") if addressStr.contains(':'): diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index b19d31f6cd..671e0f7bc7 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -50,6 +50,41 @@ block: # parseIpAddress tests expect(ValueError): discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") + block: # ipv4-compatible ipv6 address (embedded ipv4 address) + check parseIpAddress("::ffff:10.0.0.23") == parseIpAddress("::ffff:0a00:0017") + + block: # octal number in ipv4 address + expect(ValueError): + discard parseIpAddress("010.8.8.8") + expect(ValueError): + discard parseIpAddress("8.010.8.8") + + block: # hexadecimal number in ipv4 address + expect(ValueError): + discard parseIpAddress("0xc0.168.0.1") + expect(ValueError): + discard parseIpAddress("192.0xa8.0.1") + + block: # less than 4 numbers in ipv4 address + expect(ValueError): + discard parseIpAddress("127.0.1") + + block: # octal number in embedded ipv4 address + expect(ValueError): + discard parseIpAddress("::ffff:010.8.8.8") + expect(ValueError): + discard parseIpAddress("::ffff:8.010.8.8") + + block: # hexadecimal number in embedded ipv4 address + expect(ValueError): + discard parseIpAddress("::ffff:0xc0.168.0.1") + expect(ValueError): + discard parseIpAddress("::ffff:192.0xa8.0.1") + + block: # less than 4 numbers in embedded ipv4 address + expect(ValueError): + discard parseIpAddress("::ffff:127.0.1") + block: # "IpAddress/Sockaddr conversion" proc test(ipaddrstr: string) = var ipaddr_1 = parseIpAddress(ipaddrstr) diff --git a/tests/stdlib/tparseipv6.nim b/tests/stdlib/tparseipv6.nim index 3e1c23e584..dd9abc511b 100644 --- a/tests/stdlib/tparseipv6.nim +++ b/tests/stdlib/tparseipv6.nim @@ -8,23 +8,23 @@ const positives = [ "::f:8:a8f:218.17.235.229", "::b:228.19.241.2", - "::8:c:a:f:8.35.8.096", - "::3:e:a:bc:04.19.2.9", + "::8:c:a:f:8.35.8.96", + "::3:e:a:bc:4.19.2.9", "::2:212.242.248.19", "::df:a5f:3.250.208.9", "::8:c:5:e63:250.208.249.0", "::b:f:181.12.9.98", - "::a:f8:77.08.243.232", - "::a:b:85:e4d9:252.9.229.056", + "::a:f8:77.8.243.232", + "::a:b:85:e4d9:252.9.229.56", "941:c:8a:c:e::917", "e8:7a:e:ad:88a:8:203.235.225.46", - "139c:9e::f8:254.08.21.249", + "139c:9e::f8:254.8.21.249", "b38:f0:e::f9:89.6.12.18", "ef::8", "5::ab", "a::8:255.247.96.253", "b:c0::c:254.248.95.254", - "::8c:2:99.251.024.3", + "::8c:2:99.251.24.3", "98::c:247.240.249.57", "9::9", "628::f1ed:f", @@ -106,68 +106,68 @@ const "::315", "::a:a", "::aed3:a", - "f0eb:0:e8:b:c:a:254.098.233.17", + "f0eb:0:e8:b:c:a:254.98.233.17", "bfa:7fc:c66d:15:e9a:ded:254.119.9.9", - "d:ffa8:9:a:879:3:202.39.08.245", + "d:ffa8:9:a:879:3:202.39.8.245", "8e:2:8:fa8a:f1d1:1aa8:252.254.245.81", - "5:d4:a:e9:8:8:06.38.98.253", - "9c5:4:a5c:f:a6:8c9d:05.250.8.2", + "5:d4:a:e9:8:8:6.38.98.253", + "9c5:4:a5c:f:a6:8c9d:5.250.8.2", "d19a:2:f808:be:f:c:98.86.197.249", - "8:26ac:8:8:cb:f:242.00.254.85", + "8:26ac:8:8:cb:f:242.0.254.85", "38:e:1:0b88:f:0:8.89.248.92", - "e7:ff96:a:f:f:b:253.91.052.195", + "e7:ff96:a:f:f:b:253.91.52.195", "d:8:2:5:894:5:254.0.240.199", "2:98:9:8aa:9c8f:fa:252.98.248.17", - "e9:d4f:890:ccbe:5:8:088.200.228.216", + "e9:d4f:890:ccbe:5:8:88.200.228.216", "3:3:9:5:6a:df5:255.251.8.12", - "0280:3:8:8:4:9:255.000.251.249", + "0280:3:8:8:4:9:255.0.251.249", "8:af7:db:aa:0:9:238.248.250.255", - "ff:ee:9a:9252:a:289:059.083.18.255", + "ff:ee:9a:9252:a:289:59.83.18.255", "9f6:5:fc9:b:a89:a:142.1.250.254", "e:981a:da:bf94:9:f8:254.242.18.95", "3c:1:4:f2:89:f:8.91.255.14", - "e::9a2:c:9.050.80.8", + "e::9a2:c:9.50.80.8", "9::4a:07:fb:211.241.254.228", "9be::2:e:215.189.48.188", - "f::f:d:069.148.99.168", + "f::f:d:69.148.99.168", "f::a:97.18.240.47", "c::a98e:1:251.253.252.254", "668::82:214.87.208.9", "9c0::cf0:ecb:253.208.238.255", - "a::0:f1:210.240.238.049", - "8::a:1:251.238.34.09", + "a::0:f1:210.240.238.49", + "8::a:1:251.238.34.9", "81:dfe::b8:8.255.249.248", - "d3::7:b:9:83.189.08.244", - "8::9:8:8:00.7.11.252", + "d3::7:b:9:83.189.8.244", + "8::9:8:8:0.7.11.252", "2:8::c:a8:250.221.9.249", "2::f:99.8.249.247", "c:22f5::5:2c:243.15.79.89", "e:8e::da:251.243.255.2", "f15f:9::a:255.70.247.218", - "f:b::9f38:31.220.94.022", - "9::9a48:03.98.249.119", + "f:b::9f38:31.220.94.22", + "9::9a48:3.98.249.119", "d:d:9b87::2d:a:249.253.38.8", "d86d:99b::a9b:5:242.236.8.244", "eb:3::f:9cf:1.253.1.228", "b::ba2:255.247.114.64", - "2f:ec:bcb::9:219.254.250.094", + "2f:ec:bcb::9:219.254.250.94", "da8a:f6::a:e0:19.251.241.251", - "5e:c1::a:021.250.8.254", + "5e:c1::a:21.250.8.254", "c:9::8c9b:248.219.212.252", "2:a::8d4a:216.255.198.223", - "1f::66:255.30.08.150", + "1f::66:255.30.8.150", "bc2b:8f::2ff9:6.245.99.230", "a:8::a8:9.251.246.255", - "f:7:7::98:06.14.1.208", + "f:7:7::98:6.14.1.208", "e:2::9:218.249.255.254", "79:f::6:250.255.98.246", - "47:9:fb9f::9:038.136.17.251", + "47:9:fb9f::9:38.136.17.251", "ed::a:247.9.23.239", "6f::f1:88.254.119.9", "a::d:218.199.236.0", - "fc88::9:203.196.04.95", - "::8.048.255.85", - "::253.07.255.36", + "fc88::9:203.196.4.95", + "::8.48.255.85", + "::253.7.255.36", "9:d::253.7.178.229", "::250.84.158.253", "::8.55.204.248", @@ -175,31 +175,39 @@ const "df9:88ca::248.255.108.17", "8e9b::250.206.0.82", "::209.8.254.209", - "::247.088.8.8", + "::247.88.8.8", "::cb:f:ba41:250.208.19.249", "::fe:0e8:243.240.229.5", "::c:223.251.5.226", - "::8:08.03.8.250", + "::8:8.3.8.250", "::f:8.88.11.255", - "::fda:48:aa:05.189.07.2", - "::8:c3f:f:240.06.212.255", + "::fda:48:aa:5.189.7.2", + "::8:c3f:f:240.6.212.255", "::f:0aa:244.123.99.16", - "::c9b5:c:034.8.090.196", + "::c9b5:c:34.8.90.196", "::98:c9:254.14.241.81" ] negatives = ["foo.bar", "::::::::::::", "yet another failure", - "de:6:c:ab5:6a::9:252.06.06.249", - "f9:5f7:fa38:9:b::b6:09.255.248.252", + "de:6:c:ab5:6a::9:252.6.6.249", + "f9:5f7:fa38:9:b::b6:9.255.248.252", "97:c:5b:81:8a::f5dd:144.252.250.9", - "9:8:cd:8:a9::f:247.255.09.255", + "9:8:cd:8:a9::f:247.255.9.255", "18:1:8c:2:3::9:8.254.252.139", - "e:c298:3:e:a::bb12:254.246.05.250", + "e:c298:3:e:a::bb12:254.246.5.250", "e:e:c:8e:fd::8:253.8.49.231", "9:97f:f:e929:8a::c9:0.8.252.10", - "0df:b24:7:89:c::2b:16.249.240.092", + "0df:b24:7:89:c::2b:16.249.240.92", "b:8f5f:485:c:9a::84c:178.7.249.34", + "::3:e:a:bc:091.19.2.9", + "::a:f8:77.08.243.232", + "::8c:2:99.251.029.3", + "::8:c:a:f:8.35.8.096", + "d:ffa8:9:a:879:3:0202.39.8.245", + "139c:9e::f8:254.07.21.249", + "f0eb:0:e8:b:c:a:254.233.043.17", + "::a:b:85:e4d9:252.9.229.056", ] proc ok(pos: openarray[string]) =