mirror of
https://github.com/logos-messaging/go-multiaddr.git
synced 2026-01-05 06:23:10 +00:00
add ipcidr support (#177)
* Add support for ipcidr protocol * Move test * Fix gocheck * PR comments * Check byte slice len
This commit is contained in:
parent
7830bb7303
commit
f5adc3b7a2
@ -27,6 +27,8 @@ func TestConstructFails(t *testing.T) {
|
||||
"/ip4",
|
||||
"/ip4/::1",
|
||||
"/ip4/fdpsofodsajfdoisa",
|
||||
"/ip4/::/ipcidr/256",
|
||||
"/ip6/::/ipcidr/1026",
|
||||
"/ip6",
|
||||
"/ip6zone",
|
||||
"/ip6zone/",
|
||||
@ -101,9 +103,11 @@ func TestConstructSucceeds(t *testing.T) {
|
||||
cases := []string{
|
||||
"/ip4/1.2.3.4",
|
||||
"/ip4/0.0.0.0",
|
||||
"/ip4/192.0.2.0/ipcidr/24",
|
||||
"/ip6/::1",
|
||||
"/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21",
|
||||
"/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21/udp/1234/quic",
|
||||
"/ip6/2001:db8::/ipcidr/32",
|
||||
"/ip6zone/x/ip6/fe80::1",
|
||||
"/ip6zone/x%y/ip6/fe80::1",
|
||||
"/ip6zone/x%y/ip6/::",
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package manet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
@ -51,6 +52,33 @@ func (cm *CodecMap) ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
|
||||
return p(maddr)
|
||||
}
|
||||
|
||||
// MultiaddrToIPNet converts a multiaddr to an IPNet. Useful for seeing if another IP address is contained within this multiaddr network+mask
|
||||
func MultiaddrToIPNet(m ma.Multiaddr) (*net.IPNet, error) {
|
||||
var ipString string
|
||||
var mask string
|
||||
|
||||
ma.ForEach(m, func(c ma.Component) bool {
|
||||
if c.Protocol().Code == ma.P_IP4 || c.Protocol().Code == ma.P_IP6 {
|
||||
ipString = c.Value()
|
||||
}
|
||||
if c.Protocol().Code == ma.P_IPCIDR {
|
||||
mask = c.Value()
|
||||
}
|
||||
return ipString == "" || mask == ""
|
||||
})
|
||||
|
||||
if ipString == "" {
|
||||
return nil, errors.New("no ip protocol found")
|
||||
}
|
||||
|
||||
if mask == "" {
|
||||
return nil, errors.New("no mask found")
|
||||
}
|
||||
|
||||
_, ipnet, err := net.ParseCIDR(ipString + "/" + string(mask))
|
||||
return ipnet, err
|
||||
}
|
||||
|
||||
func parseBasicNetMaddr(maddr ma.Multiaddr) (net.Addr, error) {
|
||||
network, host, err := DialArgs(maddr)
|
||||
if err != nil {
|
||||
|
||||
@ -202,3 +202,65 @@ func TestDialArgs(t *testing.T) {
|
||||
test("/dns6/abc.com/udp/1234", "udp6", "abc.com:1234") // DNS6:port
|
||||
test("/dns6/abc.com", "ip6", "abc.com") // Just DNS6
|
||||
}
|
||||
|
||||
func TestMultiaddrToIPNet(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
ma string
|
||||
ips []string
|
||||
contained []bool
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "basic",
|
||||
ma: "/ip4/1.2.3.0/ipcidr/24",
|
||||
ips: []string{"1.2.3.4", "1.2.3.9", "2.1.1.1"},
|
||||
contained: []bool{true, true, false},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ma := ma.StringCast(tc.ma)
|
||||
|
||||
ipnet, err := MultiaddrToIPNet(ma)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse multiaddr %v into ipnet", ma)
|
||||
}
|
||||
for i, ipString := range tc.ips {
|
||||
ip := net.ParseIP(ipString)
|
||||
if ip == nil {
|
||||
t.Fatalf("failed to parse IP %s", ipString)
|
||||
}
|
||||
if ipnet.Contains(ip) != tc.contained[i] {
|
||||
t.Fatalf("Contains check failed. Expected %v got %v", tc.contained[i], ipnet.Contains(ip))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFailMultiaddrToIPNet(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
ma string
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{name: "missing ip addr", ma: "/ipcidr/24"},
|
||||
{name: "wrong mask", ma: "/ip4/1.2.3.0/ipcidr/128"},
|
||||
{name: "wrong mask", ma: "/ip6/::/ipcidr/255"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ma := ma.StringCast(tc.ma)
|
||||
|
||||
_, err := MultiaddrToIPNet(ma)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error when parsing: %s", tc.ma)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ const (
|
||||
P_DCCP = 0x0021
|
||||
P_IP6 = 0x0029
|
||||
P_IP6ZONE = 0x002A
|
||||
P_IPCIDR = 0x002B
|
||||
P_QUIC = 0x01CC
|
||||
P_SCTP = 0x0084
|
||||
P_CIRCUIT = 0x0122
|
||||
@ -103,6 +104,13 @@ var (
|
||||
Size: 128,
|
||||
Transcoder: TranscoderIP6,
|
||||
}
|
||||
protoIPCIDR = Protocol{
|
||||
Name: "ipcidr",
|
||||
Code: P_IPCIDR,
|
||||
VCode: CodeToVarint(P_IPCIDR),
|
||||
Size: 8,
|
||||
Transcoder: TranscoderIPCIDR,
|
||||
}
|
||||
// these require varint
|
||||
protoIP6ZONE = Protocol{
|
||||
Name: "ip6zone",
|
||||
@ -239,6 +247,7 @@ func init() {
|
||||
protoDCCP,
|
||||
protoIP6,
|
||||
protoIP6ZONE,
|
||||
protoIPCIDR,
|
||||
protoSCTP,
|
||||
protoCIRCUIT,
|
||||
protoONION2,
|
||||
|
||||
@ -54,6 +54,22 @@ func (t twrp) ValidateBytes(b []byte) error {
|
||||
var TranscoderIP4 = NewTranscoderFromFunctions(ip4StB, ip4BtS, nil)
|
||||
var TranscoderIP6 = NewTranscoderFromFunctions(ip6StB, ip6BtS, nil)
|
||||
var TranscoderIP6Zone = NewTranscoderFromFunctions(ip6zoneStB, ip6zoneBtS, ip6zoneVal)
|
||||
var TranscoderIPCIDR = NewTranscoderFromFunctions(ipcidrStB, ipcidrBtS, nil)
|
||||
|
||||
func ipcidrBtS(b []byte) (string, error) {
|
||||
if len(b) != 1 {
|
||||
return "", fmt.Errorf("invalid length (should be == 1)")
|
||||
}
|
||||
return strconv.Itoa(int(b[0])), nil
|
||||
}
|
||||
|
||||
func ipcidrStB(s string) ([]byte, error) {
|
||||
ipMask, err := strconv.ParseUint(s, 10, 8)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte{byte(uint8(ipMask))}, nil
|
||||
}
|
||||
|
||||
func ip4StB(s string) ([]byte, error) {
|
||||
i := net.ParseIP(s).To4()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user