Unverified Commit f5adc3b7 authored by Marco Munizaga's avatar Marco Munizaga Committed by GitHub

add ipcidr support (#177)

* Add support for ipcidr protocol

* Move test

* Fix gocheck

* PR comments

* Check byte slice len
parent 7830bb73
......@@ -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/::",
......
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()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment