2013-11-09 30 views
14

Go/GoLang'da, bir IP adresinin belirli bir aralıkta olup olmadığını kontrol etmenin en hızlı yolu nedir? Örneğin, verilen aralık 216.14.49.184 - 216.14.49.191 için verilen aralıkta, verilen bir giriş IP adresinin bu aralıkta olup olmadığını nasıl kontrol edebilirim?Go/GoLang kontrol IP adresi menzil içinde

+0

nasıl aralıkları temsil edilir olduğunu ayrıştırmak sadece var Kullanmak için? –

+0

Başlat: "216.14.49.184", Bitiş: "216.14.49.191". CIDR için çevrimiçi bir çözüm buldum, ancak birlikte çalıştığım veriler bu değil. –

+1

Sadece merak ediyorum, bu ipleri bileşenlere böldüyseniz ve bunları sayısal olarak karşılaştırırsanız, bu doğru sonuç verir mi? –

cevap

26

IP adresleri seferde bigEndian []byte dilim (IP tipi) olarak temsil edilir böylece bytes.Compare kullanılarak doğru karşılaştırır. https://stackoverflow.com/a/2138724/1655418

Ve nedense olmak 1ms biter: burada bulduğu bir C# örnek kod üzerinde taşıdık

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 
+0

Endianness üzerinde parlak, teşekkür ederim! –

+5

eğer öyleyse? Neden soruyu kabul etmiyorsun ?!) –

2

üretir

Örn (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) <= 0 { 
     fmt.Printf("%v is between %v and %v\n", trial, ip1, ip2) 
     return true 
    } 
    fmt.Printf("%v is NOT between %v and %v\n", trial, ip1, ip2) 
    return false 
} 

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

Nick'in çözümünden daha hızlı.

Sorum, "en hızlı" yoluydu, bu yüzden benimkini yayınlayacağımı ve topluluğun ne düşündüğünü anladım.

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 { 
    //fmt.Printf("given ip len: %d\n", len(ip)) 
    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 
      } 
      //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 
} 

Benim sonuçları:

=== 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) 
+2

Bu tamsayı 'ms' zamanlamaları bana biraz şüpheli görünüyor - bir "Benchmark" kullanarak daha doğru sonuçlar elde edersiniz. : //golang.org/pkg/testing/ –

2

Nasıl inet_pton gibi bazı uygulama hakkında? Sonuç depolanması kolaydır.

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

ipv4/ipv6 için genel sürüm.

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) <= 0 { 
     return true 
    } 
    return false 
} 

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

Bu işlev çağrıldığında net.Contains olarak "net" paketinde stdlib zaten. Zaten var olan kodu yeniden yazmanız gerekmez!

Dökümanlara bakın here.

istenen alt ağları durumda

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

burada mantıklı değil yukarıdaki kod google play link

+0

OP'nin istediği tam olarak değil, yine de bilmek güzeldi. – PickBoy