Detecting a valid IPv4 in Go like a boss

A short analysis of different alternatives to check IPv4 validity comparing complexity vs performance of their implementations.

Sergio Anguita
Sep 10 · 4 min read

In this post, we will analyze how Golang can be used to squeeze computer performance at maximum, with a tiny example of how to parse and validate content. In this case, we will be using IPv4 detection methods in order to make different approaches, and to benchmark & compare how Golang behaves in each of them. We will be testing:

  • net package.
  • regular expressions.
  • custom implementation.

All tests are executed with latest available version of Go at the time of writing this article which is go version go1.12.9 linux/amd64.


Method 1: net package

This method will use golang netpackage to check if given string contains a valid IPv4 or not.

func IsIpv4Net(host string) bool {
return net.ParseIP(host) != nil
}

Method 2: regex implementation

This method will use golang regexpackage to check if given string contains a valid IPv4 or not. The selected regular expression for this purpose is:

^(([0–9]|[1–9][0–9]|1[0–9]{2}|2[0–4][0–9]|25[0–5])\.){3}([0–9]|[1–9][0–9]|1[0–9]{2}|2[0–4][0–9]|25[0–5])$

And this is how we use it:

var (
ipRegex, _ = regexp.Compile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`)
)
func IsIpv4Regex(ipAddress string) bool {
ipAddress = strings.Trim(ipAddress, " ")
return ipRegex.MatchString(ipAddress)
}

Method 3: custom implementation

Our custom approach will be based on net.Parse method as is implemented in standard Go package.

func IsIpv4(s string) bool {
var p [IPv4len]byte
for i := 0; i < IPv4len; i++ {
if len(s) == 0 {
// Missing octets.
return false
}
if i > 0 {
if s[0] != '.' {
return false
}
s = s[1:]
}
var n int
var i int
var ok bool
for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
n = n*10 + int(s[i]-'0')
if n >= big {
n = big; ok = false
}
}
if i == 0 {
n = 0; i = 0; ok = false
}
ok = true
if !ok || n > 0xFF {
return false
}
s = s[i:]
p[i] = byte(n)
}
if len(s) != 0 {
return false
}
return true
}

Benchmarking our implementations

Let’s prepare a simple benchmark tests in where we receive IP value as string and we need to determine if it is a valid IPv4 or not just returning a boolean value with the result.

All test will have following configuration:

  • Measure allocations per operation
  • Measure ns per operation
  • Measure bytes per operation

All benchmarking test will be executed of course, with testing machine in idle state with no other workloads being executed at same time to avoid bias results.

Method 1 Benchmarking: net package

b.Run("is-valid-ipv4-net-pkg", func(b *testing.B) {
b.ReportAllocs()
b.SetBytes(1)
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = IsIpv4Net("10.41.132.6")
}
})
Results of method 1 benchmarking

Method 2 Benchmarking: regex package

b.Run("is-valid-ipv4-method-3", func(b *testing.B) {
b.ReportAllocs()
b.SetBytes(1)
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = IsIpv4Regex("10.41.132.6")
}
})

Method 3 Benchmarking: custom method

b.Run("is-valid-ipv4-custom-method", func(b *testing.B) {
b.ReportAllocs()
b.SetBytes(1)
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = IsIpv4("10.41.132.6")
}
})

Final Results

Once tested and benchmarking all different methods, and having solid results, let’s compare the performance gain between our different options. But first, lets take a look at final results!!

IPv4 validation algorithms. Benchmarking final results.
Plotted final results of our different implementations (bigger is better)

Conclusions

Obviously this optimizations was quite a tiny one, and it was used in order to show you the relationship between readable code and optimized code. Just take into account the huge impact that can have writing good code vs writing code when we scale our software.

For a http server, this means that for each validation it will require to make one allocations while the optimized version is zero-alloc! And compared to regex version, the optimized code is x20 times faster.

Thanks for checking this out and I hope you found the info useful! This is a basic introduction to how to optimize stuff for performance.

If you want to see more content on — hit the 👏 button as many times as you can and share with your colleges, co-workers, FFF, etc so I know you want more content like this!

Sergio Anguita

Written by

Cybersecurity // Blockchain Research

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade