Merge pull request #71 from multiformats/fix/panic
fully validate multiaddr byte representations on construction
This commit is contained in:
commit
9680498266
|
@ -1 +1 @@
|
||||||
1.2.7: QmUxSEGbv2nmYNnfXi7839wwQqTN3kwQeUxe8dTjZWZs7J
|
1.3.0: QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7
|
||||||
|
|
39
codec.go
39
codec.go
|
@ -26,7 +26,7 @@ func stringToBytes(s string) ([]byte, error) {
|
||||||
if p.Code == 0 {
|
if p.Code == 0 {
|
||||||
return nil, fmt.Errorf("no protocol with name %s", sp[0])
|
return nil, fmt.Errorf("no protocol with name %s", sp[0])
|
||||||
}
|
}
|
||||||
b.Write(CodeToVarint(p.Code))
|
_, _ = b.Write(CodeToVarint(p.Code))
|
||||||
sp = sp[1:]
|
sp = sp[1:]
|
||||||
|
|
||||||
if p.Size == 0 { // no length.
|
if p.Size == 0 { // no length.
|
||||||
|
@ -50,6 +50,9 @@ func stringToBytes(s string) ([]byte, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
|
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
|
||||||
}
|
}
|
||||||
|
if p.Size < 0 { // varint size.
|
||||||
|
_, _ = b.Write(CodeToVarint(len(a)))
|
||||||
|
}
|
||||||
b.Write(a)
|
b.Write(a)
|
||||||
sp = sp[1:]
|
sp = sp[1:]
|
||||||
}
|
}
|
||||||
|
@ -74,15 +77,22 @@ func validateBytes(b []byte) (err error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
size, err := sizeForAddr(p, b)
|
n, size, err := sizeForAddr(p, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b = b[n:]
|
||||||
|
|
||||||
if len(b) < size || size < 0 {
|
if len(b) < size || size < 0 {
|
||||||
return fmt.Errorf("invalid value for size")
|
return fmt.Errorf("invalid value for size")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = p.Transcoder.ValidateBytes(b[:size])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
b = b[size:]
|
b = b[size:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,11 +119,13 @@ func bytesToString(b []byte) (ret string, err error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
size, err := sizeForAddr(p, b)
|
n, size, err := sizeForAddr(p, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b = b[n:]
|
||||||
|
|
||||||
if len(b) < size || size < 0 {
|
if len(b) < size || size < 0 {
|
||||||
return "", fmt.Errorf("invalid value for size")
|
return "", fmt.Errorf("invalid value for size")
|
||||||
}
|
}
|
||||||
|
@ -125,6 +137,9 @@ func bytesToString(b []byte) (ret string, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
if p.Path && len(a) > 0 && a[0] == '/' {
|
||||||
|
a = a[1:]
|
||||||
|
}
|
||||||
if len(a) > 0 {
|
if len(a) > 0 {
|
||||||
s += "/" + a
|
s += "/" + a
|
||||||
}
|
}
|
||||||
|
@ -134,24 +149,24 @@ func bytesToString(b []byte) (ret string, err error) {
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sizeForAddr(p Protocol, b []byte) (int, error) {
|
func sizeForAddr(p Protocol, b []byte) (skip, size int, err error) {
|
||||||
switch {
|
switch {
|
||||||
case p.Size > 0:
|
case p.Size > 0:
|
||||||
return (p.Size / 8), nil
|
return 0, (p.Size / 8), nil
|
||||||
case p.Size == 0:
|
case p.Size == 0:
|
||||||
return 0, nil
|
return 0, 0, nil
|
||||||
case p.Path:
|
case p.Path:
|
||||||
size, n, err := ReadVarintCode(b)
|
size, n, err := ReadVarintCode(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
return size + n, nil
|
return n, size, nil
|
||||||
default:
|
default:
|
||||||
size, n, err := ReadVarintCode(b)
|
size, n, err := ReadVarintCode(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
return size + n, nil
|
return n, size, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,12 +183,12 @@ func bytesSplit(b []byte) ([][]byte, error) {
|
||||||
return nil, fmt.Errorf("no protocol with code %d", b[0])
|
return nil, fmt.Errorf("no protocol with code %d", b[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
size, err := sizeForAddr(p, b[n:])
|
n2, size, err := sizeForAddr(p, b[n:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
length := n + size
|
length := n + n2 + size
|
||||||
ret = append(ret, b[:length])
|
ret = append(ret, b[:length])
|
||||||
b = b[length:]
|
b = b[length:]
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,12 +86,12 @@ func (m *multiaddr) Protocols() []Protocol {
|
||||||
ps = append(ps, p)
|
ps = append(ps, p)
|
||||||
b = b[n:]
|
b = b[n:]
|
||||||
|
|
||||||
size, err := sizeForAddr(p, b)
|
n, size, err := sizeForAddr(p, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b = b[size:]
|
b = b[n+size:]
|
||||||
}
|
}
|
||||||
return ps
|
return ps
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,3 +478,17 @@ func TestIPFSvP2P(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInvalidP2PAddr(t *testing.T) {
|
||||||
|
badAddr := "a503221221c05877cbae039d70a5e600ea02c6f9f2942439285c9e344e26f8d280c850fad6"
|
||||||
|
bts, err := hex.DecodeString(badAddr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ma, err := NewMultiaddrBytes(bts)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("should have failed")
|
||||||
|
// Check for panic
|
||||||
|
_ = ma.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,6 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"name": "go-multiaddr",
|
"name": "go-multiaddr",
|
||||||
"releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
|
"releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
|
||||||
"version": "1.2.7"
|
"version": "1.3.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ package multiaddr
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"math/bits"
|
"math/bits"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Protocol is a Multiaddr protocol description structure.
|
// Protocol is a Multiaddr protocol description structure.
|
||||||
|
@ -170,7 +170,7 @@ func ProtocolsWithString(s string) ([]Protocol, error) {
|
||||||
|
|
||||||
// CodeToVarint converts an integer to a varint-encoded []byte
|
// CodeToVarint converts an integer to a varint-encoded []byte
|
||||||
func CodeToVarint(num int) []byte {
|
func CodeToVarint(num int) []byte {
|
||||||
buf := make([]byte, bits.Len(uint(num))/7 + 1)
|
buf := make([]byte, bits.Len(uint(num))/7+1)
|
||||||
n := binary.PutUvarint(buf, uint64(num))
|
n := binary.PutUvarint(buf, uint64(num))
|
||||||
return buf[:n]
|
return buf[:n]
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package multiaddr
|
||||||
import (
|
import (
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -15,17 +14,21 @@ import (
|
||||||
type Transcoder interface {
|
type Transcoder interface {
|
||||||
StringToBytes(string) ([]byte, error)
|
StringToBytes(string) ([]byte, error)
|
||||||
BytesToString([]byte) (string, error)
|
BytesToString([]byte) (string, error)
|
||||||
|
ValidateBytes([]byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTranscoderFromFunctions(s2b func(string) ([]byte, error),
|
func NewTranscoderFromFunctions(
|
||||||
b2s func([]byte) (string, error)) Transcoder {
|
s2b func(string) ([]byte, error),
|
||||||
|
b2s func([]byte) (string, error),
|
||||||
return twrp{s2b, b2s}
|
val func([]byte) error,
|
||||||
|
) Transcoder {
|
||||||
|
return twrp{s2b, b2s, val}
|
||||||
}
|
}
|
||||||
|
|
||||||
type twrp struct {
|
type twrp struct {
|
||||||
strtobyte func(string) ([]byte, error)
|
strtobyte func(string) ([]byte, error)
|
||||||
bytetostr func([]byte) (string, error)
|
bytetostr func([]byte) (string, error)
|
||||||
|
validbyte func([]byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t twrp) StringToBytes(s string) ([]byte, error) {
|
func (t twrp) StringToBytes(s string) ([]byte, error) {
|
||||||
|
@ -35,8 +38,15 @@ func (t twrp) BytesToString(b []byte) (string, error) {
|
||||||
return t.bytetostr(b)
|
return t.bytetostr(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
var TranscoderIP4 = NewTranscoderFromFunctions(ip4StB, ipBtS)
|
func (t twrp) ValidateBytes(b []byte) error {
|
||||||
var TranscoderIP6 = NewTranscoderFromFunctions(ip6StB, ipBtS)
|
if t.validbyte == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return t.validbyte(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
var TranscoderIP4 = NewTranscoderFromFunctions(ip4StB, ipBtS, nil)
|
||||||
|
var TranscoderIP6 = NewTranscoderFromFunctions(ip6StB, ipBtS, nil)
|
||||||
|
|
||||||
func ip4StB(s string) ([]byte, error) {
|
func ip4StB(s string) ([]byte, error) {
|
||||||
i := net.ParseIP(s).To4()
|
i := net.ParseIP(s).To4()
|
||||||
|
@ -58,7 +68,7 @@ func ipBtS(b []byte) (string, error) {
|
||||||
return net.IP(b).String(), nil
|
return net.IP(b).String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var TranscoderPort = NewTranscoderFromFunctions(portStB, portBtS)
|
var TranscoderPort = NewTranscoderFromFunctions(portStB, portBtS, nil)
|
||||||
|
|
||||||
func portStB(s string) ([]byte, error) {
|
func portStB(s string) ([]byte, error) {
|
||||||
i, err := strconv.Atoi(s)
|
i, err := strconv.Atoi(s)
|
||||||
|
@ -78,7 +88,7 @@ func portBtS(b []byte) (string, error) {
|
||||||
return strconv.Itoa(int(i)), nil
|
return strconv.Itoa(int(i)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var TranscoderOnion = NewTranscoderFromFunctions(onionStB, onionBtS)
|
var TranscoderOnion = NewTranscoderFromFunctions(onionStB, onionBtS, nil)
|
||||||
|
|
||||||
func onionStB(s string) ([]byte, error) {
|
func onionStB(s string) ([]byte, error) {
|
||||||
addr := strings.Split(s, ":")
|
addr := strings.Split(s, ":")
|
||||||
|
@ -121,7 +131,7 @@ func onionBtS(b []byte) (string, error) {
|
||||||
return addr + ":" + strconv.Itoa(int(port)), nil
|
return addr + ":" + strconv.Itoa(int(port)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var TranscoderP2P = NewTranscoderFromFunctions(p2pStB, p2pBtS)
|
var TranscoderP2P = NewTranscoderFromFunctions(p2pStB, p2pBtS, p2pVal)
|
||||||
|
|
||||||
func p2pStB(s string) ([]byte, error) {
|
func p2pStB(s string) ([]byte, error) {
|
||||||
// the address is a varint prefixed multihash string representation
|
// the address is a varint prefixed multihash string representation
|
||||||
|
@ -129,22 +139,15 @@ func p2pStB(s string) ([]byte, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err)
|
return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err)
|
||||||
}
|
}
|
||||||
size := CodeToVarint(len(m))
|
return m, nil
|
||||||
b := append(size, m...)
|
}
|
||||||
return b, nil
|
|
||||||
|
func p2pVal(b []byte) error {
|
||||||
|
_, err := mh.Cast(b)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func p2pBtS(b []byte) (string, error) {
|
func p2pBtS(b []byte) (string, error) {
|
||||||
// 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)
|
m, err := mh.Cast(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -152,30 +155,12 @@ func p2pBtS(b []byte) (string, error) {
|
||||||
return m.B58String(), nil
|
return m.B58String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var TranscoderUnix = NewTranscoderFromFunctions(unixStB, unixBtS)
|
var TranscoderUnix = NewTranscoderFromFunctions(unixStB, unixBtS, nil)
|
||||||
|
|
||||||
func unixStB(s string) ([]byte, error) {
|
func unixStB(s string) ([]byte, error) {
|
||||||
// the address is the whole remaining string, prefixed by a varint len
|
return []byte(s), nil
|
||||||
size := CodeToVarint(len(s))
|
|
||||||
b := append(size, []byte(s)...)
|
|
||||||
return b, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func unixBtS(b []byte) (string, error) {
|
func unixBtS(b []byte) (string, error) {
|
||||||
// the address is a varint len prefixed string
|
return string(b), nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue