Go/GoLang check IP address in range

huangapple go评论91阅读模式
英文:

Go/GoLang check IP address in range

问题

在Go/GoLang中,检查IP地址是否在特定范围内的最快方法是什么?

例如,给定范围为216.14.49.184216.14.49.191,我该如何检查给定的输入IP地址是否在该范围内?

英文:

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

得分: 46

IP地址在Go语言中以大端字节切片([]byte)的形式表示(使用IP类型),因此可以使用bytes.Compare进行正确比较。

例如(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 不是一个IPv4地址\n", trial)
		return false
	}
	if bytes.Compare(trial, ip1) >= 0 && bytes.Compare(trial, ip2) <= 0 {
		fmt.Printf("%v 在 %v 和 %v 之间\n", trial, ip1, ip2)
		return true
	}
	fmt.Printf("%v 不在 %v 和 %v 之间\n", trial, ip1, ip2)
	return false
}

func main() {
	check("1.2.3.4")
	check("216.14.49.185")
	check("1::16")
}

输出结果为:

1.2.3.4 不在 216.14.49.184 和 216.14.49.191 之间
216.14.49.185 在 216.14.49.184 和 216.14.49.191 之间
1::16 不是一个IPv4地址
英文:

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 (
	&quot;bytes&quot;
	&quot;fmt&quot;
	&quot;net&quot;
)

var (
	ip1 = net.ParseIP(&quot;216.14.49.184&quot;)
	ip2 = net.ParseIP(&quot;216.14.49.191&quot;)
)

func check(ip string) bool {
	trial := net.ParseIP(ip)
	if trial.To4() == nil {
		fmt.Printf(&quot;%v is not an IPv4 address\n&quot;, trial)
		return false
	}
	if bytes.Compare(trial, ip1) &gt;= 0 &amp;&amp; bytes.Compare(trial, ip2) &lt;= 0 {
		fmt.Printf(&quot;%v is between %v and %v\n&quot;, trial, ip1, ip2)
		return true
	}
	fmt.Printf(&quot;%v is NOT between %v and %v\n&quot;, trial, ip1, ip2)
	return false
}

func main() {
	check(&quot;1.2.3.4&quot;)
	check(&quot;216.14.49.185&quot;)
	check(&quot;1::16&quot;)
}

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

得分: 38

这已经在标准库的"net"包中作为一个名为net.Contains的函数存在。你不需要重写已经存在的代码!

请参阅此处的文档

要使用它,你只需要解析所需的子网:

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)
    }
}

如果上面的代码不清楚,请查看golang play链接

英文:

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 := &quot;192.168.5.0/24&quot;
clientips := []string{
	&quot;192.168.5.1&quot;,
	&quot;192.168.6.0&quot;,
}
_, subnet, _ := net.ParseCIDR(network)
for _, clientip := range clientips {
	ip := net.ParseIP(clientip)
	if subnet.Contains(ip) {
		fmt.Println(&quot;IP in subnet&quot;, clientip)
	}
}

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

答案3

得分: 7

ipv4/ipv6的通用版本。

ip.go:

package ip

import (
    "bytes"
    "net"

    "github.com/golang/glog"
)

// 判断给定的IP是否在两个IP之间(包括边界)
func IpBetween(from net.IP, to net.IP, test net.IP) bool {
    if from == nil || to == nil || test == nil {
        glog.Warning("输入的IP为空") // 或者返回错误!?
        return false
    }

    from16 := from.To16()
    to16 := to.To16()
    test16 := test.To16()
    if from16 == nil || to16 == nil || test16 == nil {
        glog.Warning("IP未转换为16字节") // 或者返回错误!?
        return false
    }

    if bytes.Compare(test16, from16) >= 0 && bytes.Compare(test16, to16) <= 0 {
        return true
    }
    return false
}

和 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("断言失败(实际结果:%s,期望结果:%s),范围:%s-%s,测试值:%s", res, assert, from, to, test)
    }
}
英文:

The generic version for ipv4/ipv6.

ip.go:

package ip

import (
	&quot;bytes&quot;
	&quot;net&quot;

	&quot;github.com/golang/glog&quot;
)

//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(&quot;An ip input is nil&quot;) // or return an error!?
		return false
	}

	from16 := from.To16()
	to16 := to.To16()
	test16 := test.To16()
	if from16 == nil || to16 == nil || test16 == nil {
		glog.Warning(&quot;An ip did not convert to a 16 byte&quot;) // or return an error!?
		return false
	}

	if bytes.Compare(test16, from16) &gt;= 0 &amp;&amp; bytes.Compare(test16, to16) &lt;= 0 {
		return true
	}
	return false
}

and ip_test.go:

package ip

import (
	&quot;net&quot;
	&quot;testing&quot;
)

func TestIPBetween(t *testing.T) {
	HandleIpBetween(t, &quot;0.0.0.0&quot;, &quot;255.255.255.255&quot;, &quot;128.128.128.128&quot;, true)
	HandleIpBetween(t, &quot;0.0.0.0&quot;, &quot;128.128.128.128&quot;, &quot;255.255.255.255&quot;, false)
	HandleIpBetween(t, &quot;74.50.153.0&quot;, &quot;74.50.153.4&quot;, &quot;74.50.153.0&quot;, true)
	HandleIpBetween(t, &quot;74.50.153.0&quot;, &quot;74.50.153.4&quot;, &quot;74.50.153.4&quot;, true)
	HandleIpBetween(t, &quot;74.50.153.0&quot;, &quot;74.50.153.4&quot;, &quot;74.50.153.5&quot;, false)
	HandleIpBetween(t, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:7334&quot;, &quot;74.50.153.4&quot;, &quot;74.50.153.2&quot;, false)
	HandleIpBetween(t, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:7334&quot;, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:8334&quot;, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:7334&quot;, true)
	HandleIpBetween(t, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:7334&quot;, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:8334&quot;, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:7350&quot;, true)
	HandleIpBetween(t, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:7334&quot;, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:8334&quot;, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:8334&quot;, true)
	HandleIpBetween(t, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:7334&quot;, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:8334&quot;, &quot;2001:0db8:85a3:0000:0000:8a2e:0370:8335&quot;, false)
	HandleIpBetween(t, &quot;::ffff:192.0.2.128&quot;, &quot;::ffff:192.0.2.250&quot;, &quot;::ffff:192.0.2.127&quot;, false)
	HandleIpBetween(t, &quot;::ffff:192.0.2.128&quot;, &quot;::ffff:192.0.2.250&quot;, &quot;::ffff:192.0.2.128&quot;, true)
	HandleIpBetween(t, &quot;::ffff:192.0.2.128&quot;, &quot;::ffff:192.0.2.250&quot;, &quot;::ffff:192.0.2.129&quot;, true)
	HandleIpBetween(t, &quot;::ffff:192.0.2.128&quot;, &quot;::ffff:192.0.2.250&quot;, &quot;::ffff:192.0.2.250&quot;, true)
	HandleIpBetween(t, &quot;::ffff:192.0.2.128&quot;, &quot;::ffff:192.0.2.250&quot;, &quot;::ffff:192.0.2.251&quot;, false)
	HandleIpBetween(t, &quot;::ffff:192.0.2.128&quot;, &quot;::ffff:192.0.2.250&quot;, &quot;192.0.2.130&quot;, true)
	HandleIpBetween(t, &quot;192.0.2.128&quot;, &quot;192.0.2.250&quot;, &quot;::ffff:192.0.2.130&quot;, true)
	HandleIpBetween(t, &quot;idonotparse&quot;, &quot;192.0.2.250&quot;, &quot;::ffff:192.0.2.130&quot;, 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(&quot;Assertion (have: %s should be: %s) failed on range %s-%s with test %s&quot;, res, assert, from, to, test)
	}
}

答案4

得分: 3

我从这里的一个C#示例中移植了代码:https://stackoverflow.com/a/2138724/1655418

由于某种原因,它比Nick的解决方案快1毫秒。

我的问题是关于“最快”的方法,所以我想发表我的代码,看看社区的想法。

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 < 27000; i++ {
        IsInRange(inputBytes, lowerBytes, upperBytes)
    }
    endTime := time.Now()

    fmt.Println("ELAPSED time port: ", endTime.Sub(startTime))

    lower := net.ParseIP("216.14.49.184")
    upper := net.ParseIP("216.14.49.191")
    trial := net.ParseIP("216.14.49.184")

    startTime = time.Now()
    for i := 0; i < 27000; i++ {
        IsInRange2(trial, lower, upper)
    }
    endTime = time.Now()

    fmt.Println("ELAPSED time bytescompare: ", endTime.Sub(startTime))
}

func IsInRange2(trial net.IP, lower net.IP, upper net.IP) bool {
    if bytes.Compare(trial, lower) >= 0 && bytes.Compare(trial, upper) <= 0 {
        return true
    }
    return false
}

func IsInRange(ip []byte, lower []byte, upper []byte) bool {
    lowerBoundary := true
    upperBoundary := true
    for i := 0; i < len(lower) && (lowerBoundary || upperBoundary); i++ {
        if lowerBoundary && ip[i] < lower[i] || upperBoundary && ip[i] > upper[i] {
            return false
        }

        if ip[i] == lower[i] {
            if lowerBoundary {
                lowerBoundary = true
            } else {
                lowerBoundary = false
            }
        } else {
            lowerBoundary = false
        }

        if ip[i] == upper[i] {
            if upperBoundary {
                upperBoundary = true
            } else {
                upperBoundary = false
            }
        } else {
            upperBoundary = false
        }
    }
    return true
}

我的结果:

=== 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)
英文:

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 (
&quot;fmt&quot;
&quot;testing&quot;
&quot;net&quot;
&quot;time&quot;
&quot;bytes&quot;
)
func TestIPRangeTime(t *testing.T) {
lowerBytes := net.ParseIP(&quot;216.14.49.184&quot;).To4()
upperBytes := net.ParseIP(&quot;216.14.49.191&quot;).To4()
inputBytes := net.ParseIP(&quot;216.14.49.184&quot;).To4()
startTime := time.Now()
for i := 0; i &lt; 27000; i++ {
IsInRange(inputBytes, lowerBytes, upperBytes)
}
endTime := time.Now()
fmt.Println(&quot;ELAPSED time port: &quot;, endTime.Sub(startTime))
lower := net.ParseIP(&quot;216.14.49.184&quot;)
upper := net.ParseIP(&quot;216.14.49.191&quot;)
trial := net.ParseIP(&quot;216.14.49.184&quot;)
startTime = time.Now()
for i := 0; i &lt; 27000; i++ {
IsInRange2(trial, lower, upper)
}
endTime = time.Now()
fmt.Println(&quot;ELAPSED time bytescompare: &quot;, endTime.Sub(startTime))
}
func IsInRange2(trial net.IP, lower net.IP, upper net.IP) bool {
if bytes.Compare(trial, lower) &gt;= 0 &amp;&amp; bytes.Compare(trial, upper) &lt;= 0 {
return true
}
return false
}
func IsInRange(ip []byte, lower []byte, upper []byte) bool {
//fmt.Printf(&quot;given ip len: %d\n&quot;, len(ip))
lowerBoundary := true
upperBoundary := true
for i := 0; i &lt; len(lower) &amp;&amp; (lowerBoundary || upperBoundary); i++ {
if lowerBoundary &amp;&amp; ip[i] &lt; lower[i] || upperBoundary &amp;&amp; ip[i] &gt; upper[i] {
return false
}
if ip[i] == lower[i] {
if lowerBoundary {
lowerBoundary = true
} else {
lowerBoundary = false
}
//lowerBoundary &amp;= true
} else {
lowerBoundary = false
//lowerBoundary &amp;= false
}
if ip[i] == upper[i] {
//fmt.Printf(&quot;matched upper\n&quot;)
if upperBoundary {
upperBoundary = true
} else {
upperBoundary = false
}
//upperBoundary &amp;= true
} else {
upperBoundary = false
//upperBoundary &amp;= 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)

答案5

得分: 2

func IP2Integer(ip *net.IP) (int64, error) {
ip4 := ip.To4()
if ip4 == nil {
return 0, fmt.Errorf("非法的IP地址: %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)

}

英文:

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(&quot;illegal: %v&quot;, ip)
}
bin := make([]string, len(ip4))
for i, v := range ip4 {
bin[i] = fmt.Sprintf(&quot;%08b&quot;, v)
}
return strconv.ParseInt(strings.Join(bin, &quot;&quot;), 2, 64)
}

答案6

得分: 2

Go 1.18

您可以使用新的net/netip包。该包定义了netip.Addr类型:

net.IP类型相比,该包的Addr类型占用更少的内存,是不可变的,并且支持比较(支持==和作为map键)。

您可以使用Compare方法比较IP地址:

Compare方法返回比较两个IP地址的整数结果。结果将是:

  • 如果ip == ip2,则返回0
  • 如果ip < ip2,则返回-1
  • 如果ip > ip2,则返回+1

“小于”的定义与Less方法相同。

假设您正在处理IPv4地址,一个简单的范围比较可能如下所示:

package main

import (
	"fmt"
	"net/netip"
)

func main() {
	ip1, _ := netip.ParseAddr("216.14.49.184")
	ip2, _ := netip.ParseAddr("216.14.49.191")

	myIP, _ := netip.ParseAddr("192.168.8.1")
	fmt.Println(inRange(ip1, ip2, myIP)) // false

	myIP, _ = netip.ParseAddr("216.14.49.185")
	fmt.Println(inRange(ip1, ip2, myIP)) // true
}

func inRange(ipLow, ipHigh, ip netip.Addr) bool {
	return ipLow.Compare(ip) <= 0 && ipHigh.Compare(ip) > 0
}

注意:在实际的代码中,不要忽略解析IP字符串时的错误。

英文:

Go 1.18

You can use the new package net/netip. The package defines the type netip.Addr:

> Compared to the net.IP type, this package's Addr type takes less memory, is immutable, and is comparable (supports == and being a map key).

You can compare IPs with the method Compare:

> Compare returns an integer comparing two IPs. The result will be:
> - 0 if ip == ip2
> - -1 if ip < ip2
> - +1 if ip > ip2.
>
> The definition of "less than" is the same as the Less method.

Assuming that you're dealing with IPv4 addresses, a simple in-range comparison might look like the following:

package main
import (
&quot;fmt&quot;
&quot;net/netip&quot;
)
func main() {
ip1, _ := netip.ParseAddr(&quot;216.14.49.184&quot;)
ip2, _ := netip.ParseAddr(&quot;216.14.49.191&quot;)
myIP, _ := netip.ParseAddr(&quot;192.168.8.1&quot;)
fmt.Println(inRange(ip1, ip2, myIP)) // false
myIP, _ = netip.ParseAddr(&quot;216.14.49.185&quot;)
fmt.Println(inRange(ip1, ip2, myIP)) // true
}
func inRange(ipLow, ipHigh, ip netip.Addr) bool {
return ipLow.Compare(ip) &lt;= 0 &amp;&amp; ipHigh.Compare(ip) &gt; 0
}

Note: In real-world code don't actually ignore errors from parsing the IP strings.

答案7

得分: 1

ipmatcher.go

type IPMatcher struct {
    IP     net.IP
    SubNet *net.IPNet
}
type IPMatchers []*IPMatcher

func NewIPMatcher(ipStr string) (*IPMatcher, error) {
    ip, subNet, err := net.ParseCIDR(ipStr)
    if err != nil {
        ip = net.ParseIP(ipStr)
        if ip == nil {
            return nil, errors.New("无效的IP地址:" + ipStr)
        }
    }
    return &IPMatcher{ip, subNet}, nil
}

func (m IPMatcher) Match(ipStr string) bool {
    ip := net.ParseIP(ipStr)
    if ip == nil {
        return false
    }
    return m.IP.Equal(ip) || (m.SubNet != nil && m.SubNet.Contains(ip))
}

func NewIPMatchers(ips []string) (list IPMatchers, err error) {
    for _, ipStr := range ips {
        var m *IPMatcher
        m, err = NewIPMatcher(ipStr)
        if err != nil {
            return
        }
        list = append(list, m)
    }
    return
}

func IPContains(ipMatchers []*IPMatcher, ip string) bool {
    for _, m := range ipMatchers {
        if m.Match(ip) {
            return true
        }
    }
    return false
}

func (ms IPMatchers) Match(ip string) bool {
    return IPContains(ms, ip)
}

ipmatcher_test.go

import "testing"

func TestIPMatcher(t *testing.T) {
    a, errA := NewIPMatcher("127.0.0.1")
    if errA != nil {
        t.Error(errA)
    }
    if a.IP.String() != "127.0.0.1" || a.SubNet != nil {
        t.Error("IP解析错误")
    }

    b, errB := NewIPMatcher("192.168.1.1/24")
    if errB != nil {
        t.Error(errB)
    }
    if b.IP.String() != "192.168.1.1" || b.SubNet == nil {
        t.Errorf("IP匹配错误:%s, %v", b.IP.String(), b.SubNet)
    }
    if !b.Match("192.168.1.1") || !b.Match("192.168.1.2") {
        t.Error("IP匹配错误")
    }
}

func TestIPMatchers(t *testing.T) {
    var WhiteListIPs = []string{"127.0.0.1", "192.168.1.0/24", "10.1.0.0/16"}
    M, err := NewIPMatchers(WhiteListIPs)
    if err != nil {
        t.Error(err)
    }
    if !M.Match("127.0.0.1") || !M.Match("192.168.1.1") || !M.Match("192.168.1.199") ||
        !M.Match("10.1.0.1") || !M.Match("10.1.3.1") {
        t.Error("IP匹配错误")
    }
    if M.Match("127.0.0.2") || M.Match("192.168.2.1") || M.Match("10.2.0.1") {
        t.Error("IP匹配错误2")
    }
}

你可以在gist链接中查看代码。

英文:

see in gist

ipmatcher.go

type IPMatcher struct {
IP net.IP
SubNet *net.IPNet
}
type IPMatchers []*IPMatcher
func NewIPMatcher(ipStr string) (*IPMatcher, error) {
ip, subNet, err := net.ParseCIDR(ipStr)
if err != nil {
ip = net.ParseIP(ipStr)
if ip == nil {
return nil, errors.New(&quot;invalid IP: &quot;+ipStr)
}
}
return &amp;IPMatcher{ip, subNet}, nil
}
func (m IPMatcher) Match(ipStr string) bool {
ip := net.ParseIP(ipStr)
if ip == nil {
return false
}
return m.IP.Equal(ip) || m.SubNet != nil &amp;&amp; m.SubNet.Contains(ip)
}
func NewIPMatchers(ips []string) (list IPMatchers, err error) {
for _, ipStr := range ips {
var m *IPMatcher
m, err = NewIPMatcher(ipStr)
if err != nil {
return
}
list = append(list, m)
}
return
}
func IPContains(ipMatchers []*IPMatcher, ip string) bool {
for _, m := range ipMatchers {
if m.Match(ip) {
return true
}
}
return false
}
func (ms IPMatchers) Match(ip string) bool {
return IPContains(ms, ip)
}

ipmatcher_test.go

import &quot;testing&quot;
func TestIPMatcher(t *testing.T)  {
a, errA := NewIPMatcher(&quot;127.0.0.1&quot;)
if errA != nil {
t.Error(errA)
}
if a.IP.String() != &quot;127.0.0.1&quot; || a.SubNet != nil {
t.Error(&quot;ip parse error&quot;)
}
b, errB := NewIPMatcher(&quot;192.168.1.1/24&quot;)
if errB != nil {
t.Error(errB)
}
if b.IP.String() != &quot;192.168.1.1&quot; || b.SubNet == nil {
t.Errorf(&quot;ip match error: %s, %v&quot;, b.IP.String(), b.SubNet)
}
if !b.Match(&quot;192.168.1.1&quot;) || !b.Match(&quot;192.168.1.2&quot;) {
t.Error(&quot;ip match error&quot;)
}
}
func TestIPMatchers(t *testing.T)  {
var WhiteListIPs = []string{&quot;127.0.0.1&quot;, &quot;192.168.1.0/24&quot;, &quot;10.1.0.0/16&quot;}
M, err := NewIPMatchers(WhiteListIPs)
if err != nil {
t.Error(err)
}
if !M.Match(&quot;127.0.0.1&quot;) || !M.Match(&quot;192.168.1.1&quot;) || !M.Match(&quot;192.168.1.199&quot;) ||
!M.Match(&quot;10.1.0.1&quot;) || !M.Match(&quot;10.1.3.1&quot;) {
t.Error(&quot;ip match error&quot;)
}
if M.Match(&quot;127.0.0.2&quot;) || M.Match(&quot;192.168.2.1&quot;) || M.Match(&quot;10.2.0.1&quot;) {
t.Error(&quot;ip match error 2&quot;)
}
}

see in gist

答案8

得分: 0

IPAddress Go库可以以多态的方式快速处理IPv4和IPv6地址。仓库在这里。免责声明:我是项目经理。

import (
	"fmt"
	"github.com/seancfoley/ipaddress-go/ipaddr"
)

func main() {
	isInRange("216.14.49.184", "216.14.49.191", "216.14.49.190")
	isInRange("2001:db8:85a3::8a2e:0370:7334",
		"2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a03:a:b")
}

func getAddress(str string) *ipaddr.IPAddress {
	return ipaddr.NewIPAddressString(str).GetAddress()
}

func isInRange(range1Str, range2Str, addrStr string) {
	range1, range2 := getAddress(range1Str), getAddress(range2Str)
	addr := getAddress(addrStr)
	rng := range1.SpanWithRange(range2)
	fmt.Printf("%v 包含 %v %t\n", rng, addr, rng.Contains(addr))
}

输出:

216.14.49.184 -> 216.14.49.191 包含 216.14.49.190 true
2001:db8:85a3::8a00:ff:ffff -> 2001:db8:85a3::8a2e:370:7334 包含 2001:db8:85a3::8a03:a:b true
英文:

The IPAddress Go library can do this quickly in a polymorphic manner with both IPv4 and IPv6 addresses. Repository here. Disclaimer: I am the project manager.

import (
	&quot;fmt&quot;
	&quot;github.com/seancfoley/ipaddress-go/ipaddr&quot;
)

func main() {
	isInRange(&quot;216.14.49.184&quot;, &quot;216.14.49.191&quot;, &quot;216.14.49.190&quot;)
	isInRange(&quot;2001:db8:85a3::8a2e:0370:7334&quot;,
		&quot;2001:db8:85a3::8a00:ff:ffff&quot;, &quot;2001:db8:85a3::8a03:a:b&quot;)
}

func getAddress(str string) *ipaddr.IPAddress {
	return ipaddr.NewIPAddressString(str).GetAddress()
}

func isInRange(range1Str, range2Str, addrStr string) {
	range1, range2 := getAddress(range1Str), getAddress(range2Str)
	addr := getAddress(addrStr)
	rng := range1.SpanWithRange(range2)
	fmt.Printf(&quot;%v contains %v %t\n&quot;, rng, addr, rng.Contains(addr))
}

Output:

216.14.49.184 -&gt; 216.14.49.191 contains 216.14.49.190 true
2001:db8:85a3::8a00:ff:ffff -&gt; 2001:db8:85a3::8a2e:370:7334 contains 2001:db8:85a3::8a03:a:b true

huangapple
  • 本文由 发表于 2013年11月10日 04:53:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/19882961.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定