go-multiaddr/codec.go

283 lines
5.6 KiB
Go
Raw Normal View History

2014-07-04 06:42:24 +00:00
package multiaddr
2014-07-04 18:21:39 +00:00
import (
"bytes"
"encoding/base32"
2014-07-04 18:21:39 +00:00
"encoding/binary"
"fmt"
"net"
"strconv"
"strings"
2015-01-18 05:12:54 +00:00
mh "github.com/jbenet/go-multihash"
2014-07-04 06:42:24 +00:00
)
2014-09-11 17:47:56 +00:00
func stringToBytes(s string) ([]byte, error) {
2014-10-11 03:40:51 +00:00
// consume trailing slashes
s = strings.TrimRight(s, "/")
b := new(bytes.Buffer)
2014-07-04 18:21:39 +00:00
sp := strings.Split(s, "/")
2014-07-04 06:42:24 +00:00
2014-09-11 17:45:20 +00:00
if sp[0] != "" {
return nil, fmt.Errorf("invalid multiaddr, must begin with /")
}
2014-07-04 18:21:39 +00:00
// consume first empty elem
sp = sp[1:]
2014-07-04 06:42:24 +00:00
2014-07-04 18:21:39 +00:00
for len(sp) > 0 {
p := ProtocolWithName(sp[0])
2015-01-09 13:37:02 +00:00
if p.Code == 0 {
2014-07-04 18:21:39 +00:00
return nil, fmt.Errorf("no protocol with name %s", sp[0])
}
b.Write(CodeToVarint(p.Code))
2014-11-19 21:01:52 +00:00
sp = sp[1:]
2014-07-04 06:42:24 +00:00
2015-01-18 05:12:54 +00:00
if p.Size == 0 { // no length.
continue
}
if len(sp) < 1 {
return nil, fmt.Errorf("protocol requires address, none given: %s", p.Name)
}
2015-01-18 05:12:54 +00:00
a, err := addressStringToBytes(p, sp[0])
if err != nil {
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
2014-11-19 21:01:52 +00:00
}
b.Write(a)
2015-01-18 05:12:54 +00:00
sp = sp[1:]
2014-07-04 18:21:39 +00:00
}
return b.Bytes(), nil
2014-07-04 06:42:24 +00:00
}
func validateBytes(b []byte) (err error) {
for len(b) > 0 {
code, n, err := ReadVarintCode(b)
2016-05-04 20:26:50 +00:00
if err != nil {
return err
}
b = b[n:]
p := ProtocolWithCode(code)
if p.Code == 0 {
return fmt.Errorf("no protocol with code %d", code)
}
if p.Size == 0 {
continue
}
2014-07-04 18:21:39 +00:00
size, err := sizeForAddr(p, b)
if err != nil {
return err
}
2016-05-04 17:51:57 +00:00
if len(b) < size || size < 0 {
return fmt.Errorf("invalid value for size")
}
2016-05-04 17:51:57 +00:00
b = b[size:]
}
return nil
}
2016-05-04 20:26:50 +00:00
func bytesToString(b []byte) (ret string, err error) {
2014-07-04 18:21:39 +00:00
s := ""
for len(b) > 0 {
code, n, err := ReadVarintCode(b)
if err != nil {
return "", err
}
2014-11-19 21:01:52 +00:00
b = b[n:]
p := ProtocolWithCode(code)
2015-01-09 13:37:02 +00:00
if p.Code == 0 {
2014-11-19 21:01:52 +00:00
return "", fmt.Errorf("no protocol with code %d", code)
2014-07-04 18:21:39 +00:00
}
2015-01-20 21:54:05 +00:00
s += "/" + p.Name
2014-07-04 18:21:39 +00:00
2015-01-18 05:12:54 +00:00
if p.Size == 0 {
continue
}
size, err := sizeForAddr(p, b)
if err != nil {
return "", err
}
if len(b) < size || size < 0 {
return "", fmt.Errorf("invalid value for size")
}
2015-01-20 21:54:05 +00:00
a, err := addressBytesToString(p, b[:size])
2015-01-18 05:12:54 +00:00
if err != nil {
return "", err
}
if len(a) > 0 {
2015-01-20 21:54:05 +00:00
s += "/" + a
2014-07-04 18:21:39 +00:00
}
2015-01-20 21:54:05 +00:00
b = b[size:]
2014-07-04 18:21:39 +00:00
}
return s, nil
2014-07-04 06:42:24 +00:00
}
2014-07-04 06:44:09 +00:00
func sizeForAddr(p Protocol, b []byte) (int, error) {
2015-01-20 21:54:05 +00:00
switch {
case p.Size > 0:
return (p.Size / 8), nil
2015-01-20 21:54:05 +00:00
case p.Size == 0:
return 0, nil
2015-01-20 21:54:05 +00:00
default:
size, n, err := ReadVarintCode(b)
if err != nil {
return 0, err
}
return size + n, nil
2015-01-20 21:54:05 +00:00
}
}
func bytesSplit(b []byte) ([][]byte, error) {
var ret [][]byte
for len(b) > 0 {
code, n, err := ReadVarintCode(b)
if err != nil {
return nil, err
2014-11-05 07:20:17 +00:00
}
2014-11-19 21:01:52 +00:00
p := ProtocolWithCode(code)
2015-01-09 13:37:02 +00:00
if p.Code == 0 {
return nil, fmt.Errorf("no protocol with code %d", b[0])
}
size, err := sizeForAddr(p, b[n:])
if err != nil {
return nil, err
2014-11-05 07:20:17 +00:00
}
2015-01-20 21:54:05 +00:00
length := n + size
2014-11-05 07:20:17 +00:00
ret = append(ret, b[:length])
b = b[length:]
}
return ret, nil
}
2015-01-09 13:37:02 +00:00
func addressStringToBytes(p Protocol, s string) ([]byte, error) {
2014-07-04 18:21:39 +00:00
switch p.Code {
2014-09-13 11:47:37 +00:00
case P_IP4: // ipv4
2015-01-09 13:30:33 +00:00
i := net.ParseIP(s).To4()
if i == nil {
return nil, fmt.Errorf("failed to parse ip4 addr: %s", s)
}
return i, nil
2014-07-04 18:21:39 +00:00
2014-09-13 11:47:37 +00:00
case P_IP6: // ipv6
2015-01-09 13:30:33 +00:00
i := net.ParseIP(s).To16()
if i == nil {
return nil, fmt.Errorf("failed to parse ip6 addr: %s", s)
}
return i, nil
2014-09-13 11:47:37 +00:00
2014-07-04 18:21:39 +00:00
// tcp udp dccp sctp
2014-09-13 11:47:37 +00:00
case P_TCP, P_UDP, P_DCCP, P_SCTP:
2014-07-04 18:21:39 +00:00
i, err := strconv.Atoi(s)
2015-01-09 13:30:33 +00:00
if err != nil {
return nil, 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")
2014-07-04 18:21:39 +00:00
}
2015-01-09 13:30:33 +00:00
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, uint16(i))
return b, nil
2015-01-18 05:12:54 +00:00
case P_ONION:
addr := strings.Split(s, ":")
if len(addr) != 2 {
return nil, fmt.Errorf("failed to parse %s addr: %s does not contain a port number.", p.Name, s)
}
// 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)
}
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)
}
// 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)
}
if i >= 65536 {
return nil, 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")
}
onionPortBytes := make([]byte, 2)
binary.BigEndian.PutUint16(onionPortBytes, uint16(i))
bytes := []byte{}
bytes = append(bytes, onionHostBytes...)
bytes = append(bytes, onionPortBytes...)
return bytes, nil
2015-01-18 05:12:54 +00:00
case P_IPFS: // ipfs
2015-01-20 21:54:05 +00:00
// the address is a varint prefixed multihash string representation
2015-01-18 05:12:54 +00:00
m, err := mh.FromB58String(s)
if err != nil {
return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err)
}
2015-01-20 21:54:05 +00:00
size := CodeToVarint(len(m))
b := append(size, m...)
return b, nil
2014-07-04 18:21:39 +00:00
}
2015-01-09 13:30:33 +00:00
return []byte{}, fmt.Errorf("failed to parse %s addr: unknown", p.Name)
2014-07-04 06:44:09 +00:00
}
2015-01-18 05:12:54 +00:00
func addressBytesToString(p Protocol, b []byte) (string, error) {
2014-07-04 18:21:39 +00:00
switch p.Code {
2014-07-04 06:44:09 +00:00
2014-07-04 18:21:39 +00:00
// ipv4,6
2014-09-13 11:47:37 +00:00
case P_IP4, P_IP6:
2015-01-18 05:12:54 +00:00
return net.IP(b).String(), nil
2014-07-04 06:44:09 +00:00
2014-07-04 18:21:39 +00:00
// tcp udp dccp sctp
2014-09-13 11:47:37 +00:00
case P_TCP, P_UDP, P_DCCP, P_SCTP:
2014-07-04 18:21:39 +00:00
i := binary.BigEndian.Uint16(b)
2015-01-18 05:12:54 +00:00
return strconv.Itoa(int(i)), nil
case P_IPFS: // ipfs
2015-01-20 21:54:05 +00:00
// the address is a varint-prefixed multihash string representation
size, n, err := ReadVarintCode(b)
if err != nil {
return "", err
}
2015-01-20 21:54:05 +00:00
b = b[n:]
if len(b) != size {
return "", fmt.Errorf("inconsistent lengths")
2015-01-20 21:54:05 +00:00
}
2015-01-18 05:12:54 +00:00
m, err := mh.Cast(b)
if err != nil {
return "", err
}
return m.B58String(), nil
default:
return "", fmt.Errorf("unknown protocol")
2014-07-04 18:21:39 +00:00
}
2014-07-04 06:44:09 +00:00
}