diff --git a/.gx/lastpubver b/.gx/lastpubver new file mode 100644 index 0000000..4faec43 --- /dev/null +++ b/.gx/lastpubver @@ -0,0 +1 @@ +0.0.0: QmVamAeNWEFjKqNZLCMo4EiYrFRnZsMQyXocPvjyXZJJj2 diff --git a/codec.go b/codec.go index 64e7d04..a70b502 100644 --- a/codec.go +++ b/codec.go @@ -42,12 +42,12 @@ func stringToBytes(s string) ([]byte, error) { if len(sp) < 1 { return nil, fmt.Errorf("protocol requires address, none given: %s", p.Name) } - a, err := addressStringToBytes(p, sp[0]) + a, sr, err := addressStringToBytes(p, sp) if err != nil { return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err) } + sp = sr b = append(b, a...) - sp = sp[1:] } return b, nil } @@ -136,61 +136,64 @@ func bytesSplit(b []byte) (ret [][]byte, err error) { return ret, nil } -func addressStringToBytes(p Protocol, s string) ([]byte, error) { +func addressStringToBytes(p Protocol, s []string) ([]byte, []string, error) { switch p.Code { case P_IP4: // ipv4 - i := net.ParseIP(s).To4() + i := net.ParseIP(s[0]).To4() if i == nil { - return nil, fmt.Errorf("failed to parse ip4 addr: %s", s) + return nil, s, fmt.Errorf("failed to parse ip4 addr: %s", s[0]) } - return i, nil + s = s[1:] + return i, s, nil case P_IP6: // ipv6 - i := net.ParseIP(s).To16() + i := net.ParseIP(s[0]).To16() if i == nil { - return nil, fmt.Errorf("failed to parse ip6 addr: %s", s) + return nil, s, fmt.Errorf("failed to parse ip6 addr: %s", s) } - return i, nil + s = s[1:] + return i, s, nil // tcp udp dccp sctp case P_TCP, P_UDP, P_DCCP, P_SCTP: - i, err := strconv.Atoi(s) + i, err := strconv.Atoi(s[0]) if err != nil { - return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, err) + return nil, s, fmt.Errorf("failed to parse %s addr: %s", p.Name, err) } if i >= 65536 { - return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "greater than 65536") + return nil, s, fmt.Errorf("failed to parse %s addr: %s", p.Name, "greater than 65536") } b := make([]byte, 2) binary.BigEndian.PutUint16(b, uint16(i)) - return b, nil + s = s[1:] + return b, s, nil case P_ONION: - addr := strings.Split(s, ":") + addr := strings.Split(s[0], ":") if len(addr) != 2 { - return nil, fmt.Errorf("failed to parse %s addr: %s does not contain a port number.", p.Name, s) + return nil, s, fmt.Errorf("failed to parse %s addr: %s does not contain a port number.", p.Name, s[0]) } // onion address without the ".onion" substring if len(addr[0]) != 16 { - return nil, fmt.Errorf("failed to parse %s addr: %s not a Tor onion address.", p.Name, s) + return nil, s, fmt.Errorf("failed to parse %s addr: %s not a Tor onion address.", p.Name, s) } onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0])) if err != nil { - return nil, fmt.Errorf("failed to decode base32 %s addr: %s %s", p.Name, s, err) + return nil, s, fmt.Errorf("failed to decode base32 %s addr: %s %s", p.Name, s, err) } // onion port number i, err := strconv.Atoi(addr[1]) if err != nil { - return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, err) + return nil, s, fmt.Errorf("failed to parse %s addr: %s", p.Name, err) } if i >= 65536 { - return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "port greater than 65536") + return nil, s, fmt.Errorf("failed to parse %s addr: %s", p.Name, "port greater than 65536") } if i < 1 { - return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "port less than 1") + return nil, s, fmt.Errorf("failed to parse %s addr: %s", p.Name, "port less than 1") } onionPortBytes := make([]byte, 2) @@ -198,20 +201,36 @@ func addressStringToBytes(p Protocol, s string) ([]byte, error) { bytes := []byte{} bytes = append(bytes, onionHostBytes...) bytes = append(bytes, onionPortBytes...) - return bytes, nil + s = s[1:] + return bytes, s, nil case P_IPFS: // ipfs // the address is a varint prefixed multihash string representation - m, err := mh.FromB58String(s) + m, err := mh.FromB58String(s[0]) if err != nil { - return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err) + return nil, s, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err) } size := CodeToVarint(len(m)) b := append(size, m...) - return b, nil + s = s[1:] + return b, s, nil + + case P_DNS: // dns + b := append(CodeToVarint(len(s[0])+1), []byte(s[0])...) + s = s[1:] + if len(s) == 0 { + return nil, s, fmt.Errorf("ip version not specified in dns addr") + } + p := ProtocolWithName(s[0]) + if p.Code != P_IP4 && p.Code != P_IP6 { + return nil, s, fmt.Errorf("unsupported ip version in dns addr: %s", s[0]) + } + b = append(b, byte(p.Code)) + s = s[1:] + return b, s, nil } - return []byte{}, fmt.Errorf("failed to parse %s addr: unknown", p.Name) + return []byte{}, s, fmt.Errorf("failed to parse %s addr: unknown", p.Name) } func addressBytesToString(p Protocol, b []byte) (string, error) { @@ -238,6 +257,21 @@ func addressBytesToString(p Protocol, b []byte) (string, error) { return "", err } return m.B58String(), nil + + case P_DNS: // dns + size, n := ReadVarintCode(b) + b = b[n:] + if len(b) != size { + panic("inconsistent lengths") + } + s := string(b[:len(b)-1]) + c := int(b[len(b)-1]) + p := ProtocolWithCode(c) + if p.Code != P_IP4 && p.Code != P_IP6 { + panic(fmt.Sprintf("unsupported dns address protocol %s", s[0])) + } + + return fmt.Sprintf("%s/%s", s, p.Name), nil } return "", fmt.Errorf("unknown protocol") diff --git a/multiaddr.go b/multiaddr.go index 0dbcede..b2adb1f 100644 --- a/multiaddr.go +++ b/multiaddr.go @@ -123,7 +123,7 @@ func (m *multiaddr) ValueForProtocol(code int) (string, error) { if p.Size == 0 { return "", nil } - return strings.Split(sub.String(), "/")[2], nil + return strings.Join(strings.Split(sub.String(), "/")[2:], "/"), nil } } diff --git a/multiaddr_test.go b/multiaddr_test.go index 7c75274..a6b6f7e 100644 --- a/multiaddr_test.go +++ b/multiaddr_test.go @@ -40,6 +40,9 @@ func TestConstructFails(t *testing.T) { "/ip4/127.0.0.1/tcp", "/ip4/127.0.0.1/ipfs", "/ip4/127.0.0.1/ipfs/tcp", + "/dns/ipfs.io", + "/dns/ipfs.io/ip3/tcp/1234", + "/dns/ipfs.io/udp/1234", } for _, a := range cases { @@ -78,6 +81,8 @@ func TestConstructSucceeds(t *testing.T) { "/ip4/127.0.0.1/tcp/1234/", "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", + "/dns/www.google.com/ip4/tcp/1234", + "/dns/www.yahoo.com/ip6/udp/1234", } for _, a := range cases { @@ -136,13 +141,14 @@ func TestStringToBytes(t *testing.T) { } if !bytes.Equal(b1, b2) { - t.Error("failed to convert", s, "to", b1, "got", b2) + t.Error("failed to convert", s, "to", hex.EncodeToString(b1), "got", hex.EncodeToString(b2)) } } testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2") testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1") testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1") + testString("/dns/www.google.com/ip4/tcp/1234", "bd030f7777772e676f6f676c652e636f6d040604d2") } func TestBytesToString(t *testing.T) { @@ -159,13 +165,14 @@ func TestBytesToString(t *testing.T) { } if s1 != s2 { - t.Error("failed to convert", b, "to", s1, "got", s2) + t.Error("failed to convert", hex.EncodeToString(b), "to", s1, "got", s2) } } testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2") testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1") testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1") + testString("/dns/www.google.com/ip4/tcp/1234", "bd030f7777772e676f6f676c652e636f6d040604d2") } func TestBytesSplitAndJoin(t *testing.T) { @@ -211,6 +218,7 @@ func TestBytesSplitAndJoin(t *testing.T) { []string{"/ip4/1.2.3.4", "/tcp/1", "/ip4/2.3.4.5", "/udp/2"}) testString("/ip4/1.2.3.4/utp/ip4/2.3.4.5/udp/2/udt", []string{"/ip4/1.2.3.4", "/utp", "/ip4/2.3.4.5", "/udp/2", "/udt"}) + testString("/dns/www.google.com/ip4/udp/2", []string{"/dns/www.google.com/ip4", "/udp/2"}) } func TestProtocols(t *testing.T) { @@ -299,6 +307,17 @@ func TestEncapsulate(t *testing.T) { if s := d.String(); s != "" { t.Error("decapsulate /ip4 failed.", "/", s) } + + m5, _ := NewMultiaddr("/dns/www.google.com/ip4") + e := m5.Encapsulate(m3) + if s := e.String(); s != "/dns/www.google.com/ip4/udp/5678" { + t.Error("encapsulate /dns/www.google.com/ip4/udp/5678") + } + + f := e.Decapsulate(m3) + if s := f.String(); s != "/dns/www.google.com/ip4" { + t.Error("decapsulate /udp failed.", "/dns/www.google.com/ip4", s) + } } func assertValueForProto(t *testing.T, a Multiaddr, p int, exp string) { @@ -341,4 +360,8 @@ func TestGetValue(t *testing.T) { assertValueForProto(t, a, P_IP4, "0.0.0.0") assertValueForProto(t, a, P_UDP, "12345") assertValueForProto(t, a, P_UTP, "") + + a = newMultiaddr(t, "/dns/www.google.com/ip4/udp/12345") + assertValueForProto(t, a, P_DNS, "www.google.com/ip4") + assertValueForProto(t, a, P_UDP, "12345") } diff --git a/package.json b/package.json new file mode 100644 index 0000000..b8b9a3d --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "author": "sivachandran", + "bugs": {}, + "gx": { + "dvcsimport": "github.com/RealImage/go-multiaddr" + }, + "gxVersion": "0.4.0", + "language": "go", + "license": "", + "name": "go-multiaddr", + "version": "0.0.0" +} diff --git a/protocols.csv b/protocols.csv index fa27ba3..1b81a44 100644 --- a/protocols.csv +++ b/protocols.csv @@ -10,4 +10,5 @@ code size name 421 V ipfs 480 0 http 443 0 https -444 10 onion \ No newline at end of file +444 10 onion +445 V dns diff --git a/protocols.go b/protocols.go index 8364d4c..f525813 100644 --- a/protocols.go +++ b/protocols.go @@ -31,6 +31,7 @@ const ( P_HTTP = 480 P_HTTPS = 443 P_ONION = 444 + P_DNS = 445 ) // These are special sizes @@ -53,6 +54,7 @@ var Protocols = []Protocol{ Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP)}, Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS)}, Protocol{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS)}, + Protocol{P_DNS, LengthPrefixedVarSize, "dns", CodeToVarint(P_DNS)}, } func AddProtocol(p Protocol) error {