transcoders.go 4.33 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
package multiaddr

import (
	"encoding/base32"
	"encoding/binary"
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"

	mh "github.com/multiformats/go-multihash"
)

type Transcoder interface {
	StringToBytes(string) ([]byte, error)
	BytesToString([]byte) (string, error)
}

20 21 22 23 24 25
func NewTranscoderFromFunctions(s2b func(string) ([]byte, error),
	b2s func([]byte) (string, error)) Transcoder {

	return twrp{s2b, b2s}
}

26 27 28 29 30 31 32 33 34 35 36 37
type twrp struct {
	strtobyte func(string) ([]byte, error)
	bytetostr func([]byte) (string, error)
}

func (t twrp) StringToBytes(s string) ([]byte, error) {
	return t.strtobyte(s)
}
func (t twrp) BytesToString(b []byte) (string, error) {
	return t.bytetostr(b)
}

38 39
var TranscoderIP4 = NewTranscoderFromFunctions(ip4StB, ipBtS)
var TranscoderIP6 = NewTranscoderFromFunctions(ip6StB, ipBtS)
40 41 42 43 44 45 46 47 48 49 50 51

func ip4StB(s string) ([]byte, error) {
	i := net.ParseIP(s).To4()
	if i == nil {
		return nil, fmt.Errorf("failed to parse ip4 addr: %s", s)
	}
	return i, nil
}

func ip6StB(s string) ([]byte, error) {
	i := net.ParseIP(s).To16()
	if i == nil {
52
		return nil, fmt.Errorf("failed to parse ip6 addr: %s", s)
53 54 55 56 57 58 59 60
	}
	return i, nil
}

func ipBtS(b []byte) (string, error) {
	return net.IP(b).String(), nil
}

61
var TranscoderPort = NewTranscoderFromFunctions(portStB, portBtS)
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

func portStB(s string) ([]byte, error) {
	i, err := strconv.Atoi(s)
	if err != nil {
		return nil, fmt.Errorf("failed to parse port addr: %s", err)
	}
	if i >= 65536 {
		return nil, fmt.Errorf("failed to parse port addr: %s", "greater than 65536")
	}
	b := make([]byte, 2)
	binary.BigEndian.PutUint16(b, uint16(i))
	return b, nil
}

func portBtS(b []byte) (string, error) {
	i := binary.BigEndian.Uint16(b)
	return strconv.Itoa(int(i)), nil
}

81
var TranscoderOnion = NewTranscoderFromFunctions(onionStB, onionBtS)
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

func onionStB(s string) ([]byte, error) {
	addr := strings.Split(s, ":")
	if len(addr) != 2 {
		return nil, fmt.Errorf("failed to parse onion addr: %s does not contain a port number.", s)
	}

	// onion address without the ".onion" substring
	if len(addr[0]) != 16 {
		return nil, fmt.Errorf("failed to parse onion addr: %s not a Tor onion address.", s)
	}
	onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0]))
	if err != nil {
		return nil, fmt.Errorf("failed to decode base32 onion addr: %s %s", s, err)
	}

	// onion port number
	i, err := strconv.Atoi(addr[1])
	if err != nil {
		return nil, fmt.Errorf("failed to parse onion addr: %s", err)
	}
	if i >= 65536 {
		return nil, fmt.Errorf("failed to parse onion addr: %s", "port greater than 65536")
	}
	if i < 1 {
		return nil, fmt.Errorf("failed to parse onion addr: %s", "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
}

func onionBtS(b []byte) (string, error) {
	addr := strings.ToLower(base32.StdEncoding.EncodeToString(b[0:10]))
	port := binary.BigEndian.Uint16(b[10:12])
	return addr + ":" + strconv.Itoa(int(port)), nil
}

124
var TranscoderP2P = NewTranscoderFromFunctions(p2pStB, p2pBtS)
125

126
func p2pStB(s string) ([]byte, error) {
127 128 129
	// the address is a varint prefixed multihash string representation
	m, err := mh.FromB58String(s)
	if err != nil {
130
		return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err)
131 132 133 134 135 136
	}
	size := CodeToVarint(len(m))
	b := append(size, m...)
	return b, nil
}

137
func p2pBtS(b []byte) (string, error) {
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
	// the address is a varint-prefixed multihash string representation
	size, n, err := ReadVarintCode(b)
	if err != nil {
		return "", err
	}

	b = b[n:]
	if len(b) != size {
		return "", errors.New("inconsistent lengths")
	}
	m, err := mh.Cast(b)
	if err != nil {
		return "", err
	}
	return m.B58String(), nil
}

155
var TranscoderUnix = NewTranscoderFromFunctions(unixStB, unixBtS)
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181

func unixStB(s string) ([]byte, error) {
	// the address is the whole remaining string, prefixed by a varint len
	size := CodeToVarint(len(s))
	b := append(size, []byte(s)...)
	return b, nil
}

func unixBtS(b []byte) (string, error) {
	// the address is a varint len prefixed string
	size, n, err := ReadVarintCode(b)
	if err != nil {
		return "", err
	}

	b = b[n:]
	if len(b) != size {
		return "", errors.New("inconsistent lengths")
	}
	if size == 0 {
		return "", errors.New("invalid length")
	}
	s := string(b)
	s = s[1:] // remove starting slash
	return s, nil
}