Go/GoLang check IP address in range

匿名 (未验证) 提交于 2019-12-03 02:06:01

问题:

In Go/GoLang, what is the fastest way to check if an IP address is in a specific range?

For example, given range 216.14.49.184 to 216.14.49.191, how would I check if a given input IP address is in that range?

回答1:

IP addresses are represented as bigendian []byte slices in go (the IP type) so will compare correctly using bytes.Compare.

Eg (play)

package main  import (     "bytes"     "fmt"     "net" )  var (     ip1 = net.ParseIP("216.14.49.184")     ip2 = net.ParseIP("216.14.49.191") )  func check(ip string) bool {     trial := net.ParseIP(ip)     if trial.To4() == nil {         fmt.Printf("%v is not an IPv4 address\n", trial)         return false     }     if bytes.Compare(trial, ip1) >= 0 && bytes.Compare(trial, ip2) 

Which produces

1.2.3.4 is NOT between 216.14.49.184 and 216.14.49.191 216.14.49.185 is between 216.14.49.184 and 216.14.49.191 1::16 is not an IPv4 address 


回答2:

The generic version for ipv4/ipv6.

ip.go:

package ip  import (     "bytes"     "net"      "github.com/golang/glog" )  //test to determine if a given ip is between two others (inclusive) func IpBetween(from net.IP, to net.IP, test net.IP) bool {     if from == nil || to == nil || test == nil {         glog.Warning("An ip input is nil") // or return an error!?         return false     }      from16 := from.To16()     to16 := to.To16()     test16 := test.To16()     if from16 == nil || to16 == nil || test16 == nil {         glog.Warning("An ip did not convert to a 16 byte") // or return an error!?         return false     }      if bytes.Compare(test16, from16) >= 0 && bytes.Compare(test16, to16) 

and ip_test.go:

package ip  import (     "net"     "testing" )  func TestIPBetween(t *testing.T) {     HandleIpBetween(t, "0.0.0.0", "255.255.255.255", "128.128.128.128", true)     HandleIpBetween(t, "0.0.0.0", "128.128.128.128", "255.255.255.255", false)     HandleIpBetween(t, "74.50.153.0", "74.50.153.4", "74.50.153.0", true)     HandleIpBetween(t, "74.50.153.0", "74.50.153.4", "74.50.153.4", true)     HandleIpBetween(t, "74.50.153.0", "74.50.153.4", "74.50.153.5", false)     HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "74.50.153.4", "74.50.153.2", false)     HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", true)     HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", "2001:0db8:85a3:0000:0000:8a2e:0370:7350", true)     HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", true)     HandleIpBetween(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:8334", "2001:0db8:85a3:0000:0000:8a2e:0370:8335", false)     HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.127", false)     HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.128", true)     HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.129", true)     HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.250", true)     HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "::ffff:192.0.2.251", false)     HandleIpBetween(t, "::ffff:192.0.2.128", "::ffff:192.0.2.250", "192.0.2.130", true)     HandleIpBetween(t, "192.0.2.128", "192.0.2.250", "::ffff:192.0.2.130", true)     HandleIpBetween(t, "idonotparse", "192.0.2.250", "::ffff:192.0.2.130", false)  }  func HandleIpBetween(t *testing.T, from string, to string, test string, assert bool) {     res := IpBetween(net.ParseIP(from), net.ParseIP(to), net.ParseIP(test))     if res != assert {         t.Errorf("Assertion (have: %s should be: %s) failed on range %s-%s with test %s", res, assert, from, to, test)     } } 


回答3:

I ported over the code from a C# example found here: https://stackoverflow.com/a/2138724/1655418

And for some reason it ends up being 1ms faster than Nick's solution.

My question was for the "fastest" way, so I figured I'd post mine and see what the community thinks.

package iptesting  import (     "fmt"     "testing"     "net"     "time"     "bytes" )  func TestIPRangeTime(t *testing.T) {     lowerBytes := net.ParseIP("216.14.49.184").To4()     upperBytes := net.ParseIP("216.14.49.191").To4()     inputBytes := net.ParseIP("216.14.49.184").To4()      startTime := time.Now()     for i := 0; i = 0 && bytes.Compare(trial, upper)  upper[i] {             return false         }          if ip[i] == lower[i] {             if lowerBoundary {                 lowerBoundary = true             } else {                 lowerBoundary = false             }             //lowerBoundary &= true         } else {             lowerBoundary = false             //lowerBoundary &= false         }          if ip[i] == upper[i] {             //fmt.Printf("matched upper\n")             if upperBoundary {                 upperBoundary = true             } else {                 upperBoundary = false             }             //upperBoundary &= true         } else {             upperBoundary = false             //upperBoundary &= false         }     }     return true } 

My results:

=== RUN TestIPRangeTime ELAPSED time port:  1.0001ms ELAPSED time bytescompare:  2.0001ms --- PASS: TestIPRangeTime (0.00 seconds)  === RUN TestIPRangeTime ELAPSED time port:  1ms ELAPSED time bytescompare:  2.0002ms --- PASS: TestIPRangeTime (0.00 seconds)  === RUN TestIPRangeTime ELAPSED time port:  1.0001ms ELAPSED time bytescompare:  2.0001ms --- PASS: TestIPRangeTime (0.00 seconds)  === RUN TestIPRangeTime ELAPSED time port:  1.0001ms ELAPSED time bytescompare:  2.0001ms --- PASS: TestIPRangeTime (0.00 seconds) 


回答4:

How about some implementation like inet_pton? The result is easy to be stored.

func IP2Integer(ip *net.IP) (int64, error) {     ip4 := ip.To4()     if ip4 == nil {         return 0, fmt.Errorf("illegal: %v", ip)     }      bin := make([]string, len(ip4))     for i, v := range ip4 {         bin[i] = fmt.Sprintf("%08b", v)     }     return strconv.ParseInt(strings.Join(bin, ""), 2, 64) } 


回答5:

This is already in the stdlib in the "net" package as a function called net.Contains. You dont need to rewrite code that already exists!

See documentation here.

To use it you just have to parse the desired subnets

network := "192.168.5.0/24" clientips := []string{     "192.168.5.1",     "192.168.6.0", } _, subnet, _ := net.ParseCIDR(network) for _, clientip := range clientips {     ip := net.ParseIP(clientip)     if subnet.Contains(ip) {         fmt.Println("IP in subnet", clientip)     } } 

In case the above code doesn't make sense here is a google play link



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!