Skip to main content

Overflow While Parsing IPv4 Addresses

The DecimalMaxSO implementation on Stack Overflow was written in the context of parsing octets of IPv4 addresses. Curious to see if the libraries on Hackage deal with overflow, I checked out the most popular libraries that parse IPv4 addresses.

Some test code is available on GitHub.

iproute

The iproute library parses strings using the appar library. Octet values are accumulated using an Int type. The octet bounds are checked after the whole number has been parsed, however, so it is subject to Int overflow.

λ: import Data.IP (IPv4)
λ: print @IPv4 $ read "127.0.0.18446744073709551617"
127.0.0.1

While I do not think that this issue is significant, I created a GitHub issue to report it.

Note that the DecimalMaxStrict implementation does not have this issue because the maximum bound is checked as the number is parsed.

λ: import DecimalMaxStrict
λ: import qualified Data.Attoparsec.Text as AT
λ: AT.parseOnly (word8 True) "18446744073709551617"
Left "decimalMax: Failed reading: overflow"
it :: Either String Word8

ip

The ip library parses strings using a text Reader. Octet values are parsed by the decimal function using a Word type. The octet bounds are checked after the whole number has been parsed, so it is subject to Word overflow.

λ: import Net.IPv4 (decode)
λ: print $ decode "127.0.0.18446744073709551617"
Just (ipv4 127 0 0 1)

While I do not think that this issue is significant, I created a GitHub issue to report it.

network-ip

The network-ip library parses strings using the data-textual library. It parses octets using an Int type, and it uses the nnUpTo function to limit each octet to three digits, avoiding overflow.

hw-ip

The hw-ip library also parses strings using the appar library. It parses octets by matching digits similar to how people use regular expressions for validation, using overlapping groups for improved performance. (I wondered what kind of error messages this leads to, and I found that appar only parses to Maybe and therefore does not provide error messages.) This constrains the parsed value, avoiding overflow.

octet :: AP.Parser Word8
octet = AP.try ((digits 1 2 #<*>#  digit 5  ) #<*># digits 0 5)
  <|>   AP.try ((digits 1 2 #<*># digits 0 4) #<*># digits 0 9)
  <|>   AP.try (( digit 1   #<*># digits 0 9) #<*># digits 0 9)
  <|>   AP.try ( digits 1 9 #<*># digits 0 9)
  <|>            digits 0 9