pax_global_header00006660000000000000000000000064150451434050014513gustar00rootroot0000000000000052 comment=3b99966d90a2cefddd7a3a03996a11721dad6589 go-multiaddr-0.16.1/000077500000000000000000000000001504514340500141705ustar00rootroot00000000000000go-multiaddr-0.16.1/.github/000077500000000000000000000000001504514340500155305ustar00rootroot00000000000000go-multiaddr-0.16.1/.github/workflows/000077500000000000000000000000001504514340500175655ustar00rootroot00000000000000go-multiaddr-0.16.1/.github/workflows/generated-pr.yml000066400000000000000000000003661504514340500226720ustar00rootroot00000000000000name: Close Generated PRs on: schedule: - cron: '0 0 * * *' workflow_dispatch: permissions: issues: write pull-requests: write jobs: stale: uses: ipdxco/unified-github-workflows/.github/workflows/reusable-generated-pr.yml@v1 go-multiaddr-0.16.1/.github/workflows/go-check.yml000066400000000000000000000005741504514340500217760ustar00rootroot00000000000000name: Go Checks on: pull_request: push: branches: ["master"] workflow_dispatch: permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} cancel-in-progress: true jobs: go-check: uses: ipdxco/unified-github-workflows/.github/workflows/go-check.yml@v1.0 go-multiaddr-0.16.1/.github/workflows/go-test.yml000066400000000000000000000006671504514340500217030ustar00rootroot00000000000000name: Go Test on: pull_request: push: branches: ["master"] workflow_dispatch: permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} cancel-in-progress: true jobs: go-test: uses: ipdxco/unified-github-workflows/.github/workflows/go-test.yml@v1.0 secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} go-multiaddr-0.16.1/.github/workflows/release-check.yml000066400000000000000000000006431504514340500230060ustar00rootroot00000000000000name: Release Checker on: pull_request_target: paths: [ 'version.json' ] types: [ opened, synchronize, reopened, labeled, unlabeled ] workflow_dispatch: permissions: contents: write pull-requests: write concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: release-check: uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v1.0 go-multiaddr-0.16.1/.github/workflows/releaser.yml000066400000000000000000000004531504514340500221140ustar00rootroot00000000000000name: Releaser on: push: paths: [ 'version.json' ] workflow_dispatch: permissions: contents: write concurrency: group: ${{ github.workflow }}-${{ github.sha }} cancel-in-progress: true jobs: releaser: uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0 go-multiaddr-0.16.1/.github/workflows/stale.yml000066400000000000000000000003641504514340500214230ustar00rootroot00000000000000name: Close Stale Issues on: schedule: - cron: '0 0 * * *' workflow_dispatch: permissions: issues: write pull-requests: write jobs: stale: uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1 go-multiaddr-0.16.1/.github/workflows/tagpush.yml000066400000000000000000000004431504514340500217640ustar00rootroot00000000000000name: Tag Push Checker on: push: tags: - v* permissions: contents: read issues: write concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: releaser: uses: ipdxco/unified-github-workflows/.github/workflows/tagpush.yml@v1.0 go-multiaddr-0.16.1/.gitignore000066400000000000000000000000421504514340500161540ustar00rootroot00000000000000.vscode/ multiaddr/multiaddr tmp/ go-multiaddr-0.16.1/LICENSE000066400000000000000000000020731504514340500151770ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014 Juan Batiz-Benet Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. go-multiaddr-0.16.1/README.md000066400000000000000000000073401504514340500154530ustar00rootroot00000000000000# go-multiaddr [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats) [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs) [![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) [![GoDoc](https://godoc.org/github.com/multiformats/go-multiaddr?status.svg)](https://godoc.org/github.com/multiformats/go-multiaddr) [![Travis CI](https://img.shields.io/travis/multiformats/go-multiaddr.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-multiaddr) [![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-multiaddr.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-multiaddr?branch=master) > [multiaddr](https://github.com/multiformats/multiaddr) implementation in go Multiaddr is a standard way to represent addresses that: - Support any standard network protocols. - Self-describe (include protocols). - Have a binary packed format. - Have a nice string representation. - Encapsulate well. ## Table of Contents - [Install](#install) - [Usage](#usage) - [Example](#example) - [Simple](#simple) - [Protocols](#protocols) - [En/decapsulate](#endecapsulate) - [Tunneling](#tunneling) - [Maintainers](#maintainers) - [Contribute](#contribute) - [License](#license) ## Install ```sh go get github.com/multiformats/go-multiaddr ``` ## Usage ### Example #### Simple ```go import ma "github.com/multiformats/go-multiaddr" // construct from a string (err signals parse failure) m1, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234") // construct from bytes (err signals parse failure) m2, err := ma.NewMultiaddrBytes(m1.Bytes()) // true strings.Equal(m1.String(), "/ip4/127.0.0.1/udp/1234") strings.Equal(m1.String(), m2.String()) bytes.Equal(m1.Bytes(), m2.Bytes()) m1.Equal(m2) m2.Equal(m1) ``` #### Protocols ```go // get the multiaddr protocol description objects m1.Protocols() // []Protocol{ // Protocol{ Code: 4, Name: 'ip4', Size: 32}, // Protocol{ Code: 17, Name: 'udp', Size: 16}, // } ``` #### En/decapsulate ```go import ma "github.com/multiformats/go-multiaddr" m, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234") // sctpMA, err := ma.NewMultiaddr("/sctp/5678") m.Encapsulate(sctpMA) // udpMA, err := ma.NewMultiaddr("/udp/1234") m.Decapsulate(udpMA) // up to + inc last occurrence of subaddr // ``` #### Tunneling Multiaddr allows expressing tunnels very nicely. ```js printer, _ := ma.NewMultiaddr("/ip4/192.168.0.13/tcp/80") proxy, _ := ma.NewMultiaddr("/ip4/10.20.30.40/tcp/443") printerOverProxy := proxy.Encapsulate(printer) // /ip4/10.20.30.40/tcp/443/ip4/192.168.0.13/tcp/80 proxyAgain := printerOverProxy.Decapsulate(printer) // /ip4/10.20.30.40/tcp/443 ``` ## Contribute Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multiaddr/issues). Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. ## License [MIT](LICENSE) © 2014 Juan Batiz-Benet go-multiaddr-0.16.1/codec.go000066400000000000000000000064161504514340500156030ustar00rootroot00000000000000package multiaddr import ( "bytes" "fmt" "strings" "github.com/multiformats/go-varint" ) func stringToBytes(s string) ([]byte, error) { // consume trailing slashes s = strings.TrimRight(s, "/") var b bytes.Buffer sp := strings.Split(s, "/") if sp[0] != "" { return nil, fmt.Errorf("failed to parse multiaddr %q: must begin with /", s) } // consume first empty elem sp = sp[1:] if len(sp) == 0 { return nil, fmt.Errorf("failed to parse multiaddr %q: empty multiaddr", s) } for len(sp) > 0 { name := sp[0] p := ProtocolWithName(name) if p.Code == 0 { return nil, fmt.Errorf("failed to parse multiaddr %q: unknown protocol %s", s, sp[0]) } _, _ = b.Write(p.VCode) sp = sp[1:] if p.Size == 0 { // no length. continue } if len(sp) < 1 { return nil, fmt.Errorf("failed to parse multiaddr %q: unexpected end of multiaddr", s) } if p.Path { // it's a path protocol (terminal). // consume the rest of the address as the next component. sp = []string{"/" + strings.Join(sp, "/")} } a, err := p.Transcoder.StringToBytes(sp[0]) if err != nil { return nil, fmt.Errorf("failed to parse multiaddr %q: invalid value %q for protocol %s: %s", s, sp[0], p.Name, err) } err = p.Transcoder.ValidateBytes(a) if err != nil { return nil, fmt.Errorf("failed to validate multiaddr %q: invalid value %q for protocol %s: %w", s, sp[0], p.Name, err) } if p.Size < 0 { // varint size. _, _ = b.Write(varint.ToUvarint(uint64(len(a)))) } b.Write(a) sp = sp[1:] } return b.Bytes(), nil } func readComponent(b []byte) (int, *Component, error) { var offset int code, n, err := ReadVarintCode(b) if err != nil { return 0, nil, err } offset += n p := ProtocolWithCode(code) if p.Code == 0 { return 0, nil, fmt.Errorf("no protocol with code %d", code) } pPtr := protocolPtrByCode[code] if pPtr == nil { return 0, nil, fmt.Errorf("no protocol with code %d", code) } if p.Size == 0 { c := &Component{ bytes: string(b[:offset]), valueStartIdx: offset, protocol: pPtr, } err := validateComponent(c) if err != nil { return 0, nil, err } return offset, c, nil } var size int if p.Size < 0 { // varint var n int size, n, err = ReadVarintCode(b[offset:]) if err != nil { return 0, nil, err } offset += n } else { // Size is in bits, but we operate on bytes size = p.Size / 8 } if len(b[offset:]) < size || size <= 0 { return 0, nil, fmt.Errorf("invalid value for size %d", len(b[offset:])) } c := &Component{ bytes: string(b[:offset+size]), protocol: pPtr, valueStartIdx: offset, } err = validateComponent(c) if err != nil { return 0, nil, err } return offset + size, c, err } func readMultiaddr(b []byte) (int, Multiaddr, error) { if len(b) == 0 { return 0, nil, fmt.Errorf("empty multiaddr") } var res Multiaddr bytesRead := 0 sawPathComponent := false for len(b) > 0 { n, c, err := readComponent(b) if err != nil { return 0, nil, err } b = b[n:] bytesRead += n if sawPathComponent { // It is an error to have another component after a path component. return bytesRead, nil, fmt.Errorf("unexpected component after path component") } sawPathComponent = c.protocol.Path res = append(res, *c) } return bytesRead, res, nil } go-multiaddr-0.16.1/codecov.yml000066400000000000000000000000301504514340500163260ustar00rootroot00000000000000ignore: - "multiaddr" go-multiaddr-0.16.1/component.go000066400000000000000000000167621504514340500165350ustar00rootroot00000000000000package multiaddr import ( "bytes" "encoding/binary" "encoding/json" "fmt" "strings" "github.com/multiformats/go-varint" ) // Component is a single multiaddr Component. type Component struct { // bytes is the raw bytes of the component. It includes the protocol code as // varint, possibly the size of the value, and the value. bytes string // string for immutability. protocol *Protocol valueStartIdx int // Index of the first byte of the Component's value in the bytes array } func (c *Component) Multiaddr() Multiaddr { if c == nil { return nil } return []Component{*c} } func (c *Component) Encapsulate(o Multiaddrer) Multiaddr { return c.Multiaddr().Encapsulate(o) } func (c *Component) Decapsulate(o Multiaddrer) Multiaddr { return c.Multiaddr().Decapsulate(o) } func (c *Component) Bytes() []byte { if c == nil { return nil } return []byte(c.bytes) } func (c *Component) MarshalBinary() ([]byte, error) { if c == nil { return nil, errNilPtr } return c.Bytes(), nil } func (c *Component) UnmarshalBinary(data []byte) error { if c == nil { return errNilPtr } _, comp, err := readComponent(data) if err != nil { return err } *c = *comp return nil } func (c *Component) MarshalText() ([]byte, error) { if c == nil { return nil, errNilPtr } return []byte(c.String()), nil } func (c *Component) UnmarshalText(data []byte) error { if c == nil { return errNilPtr } bytes, err := stringToBytes(string(data)) if err != nil { return err } _, comp, err := readComponent(bytes) if err != nil { return err } *c = *comp return nil } func (c *Component) MarshalJSON() ([]byte, error) { if c == nil { return nil, errNilPtr } txt, err := c.MarshalText() if err != nil { return nil, err } return json.Marshal(string(txt)) } func (c *Component) UnmarshalJSON(data []byte) error { if c == nil { return errNilPtr } var v string if err := json.Unmarshal(data, &v); err != nil { return err } return c.UnmarshalText([]byte(v)) } func (c *Component) Equal(o *Component) bool { if c == nil || o == nil { return c == o } return c.bytes == o.bytes } func (c *Component) Compare(o *Component) int { if c == nil && o == nil { return 0 } if c == nil { return -1 } if o == nil { return 1 } return strings.Compare(c.bytes, o.bytes) } func (c *Component) Protocols() []Protocol { if c == nil { return nil } if c.protocol == nil { return nil } return []Protocol{*c.protocol} } func (c *Component) ValueForProtocol(code int) (string, error) { if c == nil { return "", fmt.Errorf("component is nil") } if c.protocol == nil { return "", fmt.Errorf("component has nil protocol") } if c.protocol.Code != code { return "", ErrProtocolNotFound } return c.Value(), nil } func (c *Component) Protocol() Protocol { if c == nil { return Protocol{} } if c.protocol == nil { return Protocol{} } return *c.protocol } func (c *Component) Code() int { if c == nil || c.protocol == nil { return 0 } return c.protocol.Code } func (c *Component) RawValue() []byte { if c == nil { return nil } return []byte(c.bytes[c.valueStartIdx:]) } func (c *Component) Value() string { if c == nil { return "" } // This Component MUST have been checked by validateComponent when created value, _ := c.valueAndErr() return value } func (c *Component) valueAndErr() (string, error) { if c == nil { return "", errNilPtr } if c.protocol == nil { return "", fmt.Errorf("component has nil protocol") } if c.protocol.Transcoder == nil { return "", nil } value, err := c.protocol.Transcoder.BytesToString([]byte(c.bytes[c.valueStartIdx:])) if err != nil { return "", err } return value, nil } func (c *Component) String() string { if c == nil { return "" } var b strings.Builder c.writeTo(&b) return b.String() } // writeTo is an efficient, private function for string-formatting a multiaddr. // Trust me, we tend to allocate a lot when doing this. func (c *Component) writeTo(b *strings.Builder) { if c == nil { return } if c.protocol == nil { return } b.WriteByte('/') b.WriteString(c.protocol.Name) value := c.Value() if len(value) == 0 { return } if !(c.protocol.Path && value[0] == '/') { b.WriteByte('/') } b.WriteString(value) } // NewComponent constructs a new multiaddr component func NewComponent(protocol, value string) (*Component, error) { p := ProtocolWithName(protocol) if p.Code == 0 { return nil, fmt.Errorf("unsupported protocol: %s", protocol) } if p.Transcoder != nil { bts, err := p.Transcoder.StringToBytes(value) if err != nil { return nil, err } return newComponent(p, bts) } else if value != "" { return nil, fmt.Errorf("protocol %s doesn't take a value", p.Name) } return newComponent(p, nil) } func newComponent(protocol Protocol, bvalue []byte) (*Component, error) { protocolPtr := protocolPtrByCode[protocol.Code] if protocolPtr == nil { protocolPtr = &protocol } size := len(bvalue) size += len(protocol.VCode) if protocol.Size < 0 { size += varint.UvarintSize(uint64(len(bvalue))) } maddr := make([]byte, size) var offset int offset += copy(maddr[offset:], protocol.VCode) if protocol.Size < 0 { offset += binary.PutUvarint(maddr[offset:], uint64(len(bvalue))) } copy(maddr[offset:], bvalue) // Shouldn't happen if len(maddr) != offset+len(bvalue) { return nil, fmt.Errorf("component size mismatch: %d != %d", len(maddr), offset+len(bvalue)) } c := &Component{ bytes: string(maddr), protocol: protocolPtr, valueStartIdx: offset, } err := validateComponent(c) if err != nil { return nil, err } return c, nil } // validateComponent MUST be called after creating a non-zero Component. // It ensures that we will be able to call all methods on Component without // error. func validateComponent(c *Component) error { if c == nil { return errNilPtr } if c.protocol == nil { return fmt.Errorf("component is missing its protocol") } if c.valueStartIdx > len(c.bytes) { return fmt.Errorf("component valueStartIdx is greater than the length of the component's bytes") } if len(c.protocol.VCode) == 0 { return fmt.Errorf("Component is missing its protocol's VCode field") } if len(c.bytes) < len(c.protocol.VCode) { return fmt.Errorf("component size mismatch: %d != %d", len(c.bytes), len(c.protocol.VCode)) } if !bytes.Equal([]byte(c.bytes[:len(c.protocol.VCode)]), c.protocol.VCode) { return fmt.Errorf("component's VCode field is invalid: %v != %v", []byte(c.bytes[:len(c.protocol.VCode)]), c.protocol.VCode) } if c.protocol.Size < 0 { size, n, err := ReadVarintCode([]byte(c.bytes[len(c.protocol.VCode):])) if err != nil { return err } if size != len(c.bytes[c.valueStartIdx:]) { return fmt.Errorf("component value size mismatch: %d != %d", size, len(c.bytes[c.valueStartIdx:])) } if len(c.protocol.VCode)+n+size != len(c.bytes) { return fmt.Errorf("component size mismatch: %d != %d", len(c.protocol.VCode)+n+size, len(c.bytes)) } } else { // Fixed size value size := c.protocol.Size / 8 if size != len(c.bytes[c.valueStartIdx:]) { return fmt.Errorf("component value size mismatch: %d != %d", size, len(c.bytes[c.valueStartIdx:])) } if len(c.protocol.VCode)+size != len(c.bytes) { return fmt.Errorf("component size mismatch: %d != %d", len(c.protocol.VCode)+size, len(c.bytes)) } } _, err := c.valueAndErr() if err != nil { return err } if c.protocol.Transcoder != nil { err = c.protocol.Transcoder.ValidateBytes([]byte(c.bytes[c.valueStartIdx:])) if err != nil { return err } } return nil } go-multiaddr-0.16.1/doc.go000066400000000000000000000021101504514340500152560ustar00rootroot00000000000000/* Package multiaddr provides an implementation of the Multiaddr network address format. Multiaddr emphasizes explicitness, self-description, and portability. It allows applications to treat addresses as opaque tokens, and to avoid making assumptions about the address representation (e.g. length). Learn more at https://github.com/multiformats/multiaddr Basic Use: import ( "bytes" "strings" ma "github.com/multiformats/go-multiaddr" ) // construct from a string (err signals parse failure) m1, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234") // construct from bytes (err signals parse failure) m2, err := ma.NewMultiaddrBytes(m1.Bytes()) // true strings.Equal(m1.String(), "/ip4/127.0.0.1/udp/1234") strings.Equal(m1.String(), m2.String()) bytes.Equal(m1.Bytes(), m2.Bytes()) m1.Equal(m2) m2.Equal(m1) // tunneling (en/decap) printer, _ := ma.NewMultiaddr("/ip4/192.168.0.13/tcp/80") proxy, _ := ma.NewMultiaddr("/ip4/10.20.30.40/tcp/443") printerOverProxy := proxy.Encapsulate(printer) proxyAgain := printerOverProxy.Decapsulate(printer) */ package multiaddr go-multiaddr-0.16.1/filter.go000066400000000000000000000064761504514340500160210ustar00rootroot00000000000000package multiaddr import ( "net" "sync" ) // Action is an enum modelling all possible filter actions. type Action int32 const ( ActionNone Action = iota // zero value. ActionAccept ActionDeny ) type filterEntry struct { f net.IPNet action Action } // Filters is a structure representing a collection of accept/deny // net.IPNet filters, together with the DefaultAction flag, which // represents the default filter policy. // // Note that the last policy added to the Filters is authoritative. type Filters struct { DefaultAction Action mu sync.RWMutex filters []*filterEntry } // NewFilters constructs and returns a new set of net.IPNet filters. // By default, the new filter accepts all addresses. func NewFilters() *Filters { return &Filters{ DefaultAction: ActionAccept, filters: make([]*filterEntry, 0), } } func (fs *Filters) find(ipnet net.IPNet) (int, *filterEntry) { s := ipnet.String() for idx, ft := range fs.filters { if ft.f.String() == s { return idx, ft } } return -1, nil } // AddFilter adds a rule to the Filters set, enforcing the desired action for // the provided IPNet mask. func (fs *Filters) AddFilter(ipnet net.IPNet, action Action) { fs.mu.Lock() defer fs.mu.Unlock() if _, f := fs.find(ipnet); f != nil { f.action = action } else { fs.filters = append(fs.filters, &filterEntry{ipnet, action}) } } // RemoveLiteral removes the first filter associated with the supplied IPNet, // returning whether something was removed or not. It makes no distinction // between whether the rule is an accept or a deny. func (fs *Filters) RemoveLiteral(ipnet net.IPNet) (removed bool) { fs.mu.Lock() defer fs.mu.Unlock() if idx, _ := fs.find(ipnet); idx != -1 { fs.filters = append(fs.filters[:idx], fs.filters[idx+1:]...) return true } return false } // AddrBlocked parses a ma.Multiaddr and, if a valid netip is found, it applies the // Filter set rules, returning true if the given address should be denied, and false if // the given address is accepted. // // If a parsing error occurs, or no filter matches, the Filters' // default is returned. // // TODO: currently, the last filter to match wins always, but it shouldn't be that way. // // Instead, the highest-specific last filter should win; that way more specific filters // override more general ones. func (fs *Filters) AddrBlocked(a Multiaddr) (deny bool) { var ( netip net.IP found bool ) ForEach(a, func(c Component) bool { switch c.Protocol().Code { case P_IP6ZONE: return true case P_IP6, P_IP4: found = true netip = net.IP(c.RawValue()) return false default: return false } }) if !found { return fs.DefaultAction == ActionDeny } fs.mu.RLock() defer fs.mu.RUnlock() action := fs.DefaultAction for _, ft := range fs.filters { if ft.f.Contains(netip) { action = ft.action } } return action == ActionDeny } func (fs *Filters) ActionForFilter(ipnet net.IPNet) (action Action, ok bool) { if _, f := fs.find(ipnet); f != nil { return f.action, true } return ActionNone, false } // FiltersForAction returns the filters associated with the indicated action. func (fs *Filters) FiltersForAction(action Action) (result []net.IPNet) { fs.mu.RLock() defer fs.mu.RUnlock() for _, ff := range fs.filters { if ff.action == action { result = append(result, ff.f) } } return result } go-multiaddr-0.16.1/filter_test.go000066400000000000000000000104531504514340500170460ustar00rootroot00000000000000package multiaddr import ( "net" "testing" ) func TestFilterListing(t *testing.T) { f := NewFilters() expected := map[string]bool{ "1.2.3.0/24": true, "4.3.2.1/32": true, "fd00::/8": true, "fc00::1/128": true, } for cidr := range expected { _, ipnet, _ := net.ParseCIDR(cidr) f.AddFilter(*ipnet, ActionDeny) } for _, filter := range f.FiltersForAction(ActionDeny) { cidr := filter.String() if expected[cidr] { delete(expected, cidr) } else { t.Errorf("unexected filter %s", cidr) } } for cidr := range expected { t.Errorf("expected filter %s", cidr) } } func TestFilterBlocking(t *testing.T) { f := NewFilters() _, ipnet, _ := net.ParseCIDR("0.1.2.3/24") f.AddFilter(*ipnet, ActionDeny) filters := f.FiltersForAction(ActionDeny) if len(filters) != 1 { t.Fatal("Expected only 1 filter") } if a, ok := f.ActionForFilter(*ipnet); !ok || a != ActionDeny { t.Fatal("Expected filter with DENY action") } if !f.RemoveLiteral(filters[0]) { t.Error("expected true value from RemoveLiteral") } for _, cidr := range []string{ "1.2.3.0/24", "4.3.2.1/32", "fd00::/8", "fc00::1/128", } { _, ipnet, _ := net.ParseCIDR(cidr) f.AddFilter(*ipnet, ActionDeny) } // These addresses should all be blocked for _, blocked := range []string{ "/ip4/1.2.3.4/tcp/123", "/ip4/4.3.2.1/udp/123", "/ip6/fd00::2/tcp/321", "/ip6/fc00::1/udp/321", } { maddr, err := NewMultiaddr(blocked) if err != nil { t.Error(err) } if !f.AddrBlocked(maddr) { t.Fatalf("expected %s to be blocked", blocked) } } // test that other net intervals are not blocked for _, addr := range []string{ "/ip4/1.2.4.1/tcp/123", "/ip4/4.3.2.2/udp/123", "/ip6/fe00::1/tcp/321", "/ip6/fc00::2/udp/321", } { maddr, err := NewMultiaddr(addr) if err != nil { t.Error(err) } if f.AddrBlocked(maddr) { t.Fatalf("expected %s to not be blocked", addr) } } } func TestFilterWhitelisting(t *testing.T) { f := NewFilters() // Add default reject filter f.DefaultAction = ActionDeny // Add a whitelist _, ipnet, _ := net.ParseCIDR("1.2.3.0/24") f.AddFilter(*ipnet, ActionAccept) if a, ok := f.ActionForFilter(*ipnet); !ok || a != ActionAccept { t.Fatal("Expected filter with ACCEPT action") } // That /24 should now be allowed for _, addr := range []string{ "/ip4/1.2.3.1/tcp/123", "/ip4/1.2.3.254/tcp/123", "/ip4/1.2.3.254/udp/321", } { maddr, err := NewMultiaddr(addr) if err != nil { t.Error(err) } if f.AddrBlocked(maddr) { t.Fatalf("expected %s to be whitelisted", addr) } } // No policy matches these maddrs, they should be blocked by default for _, blocked := range []string{ "/ip4/1.2.4.4/tcp/123", "/ip4/4.3.2.1/udp/123", "/ip6/fd00::2/tcp/321", "/ip6/fc00::1/udp/321", } { maddr, err := NewMultiaddr(blocked) if err != nil { t.Error(err) } if !f.AddrBlocked(maddr) { t.Fatalf("expected %s to be blocked", blocked) } } } func TestFiltersRemoveRules(t *testing.T) { f := NewFilters() ips := []string{ "/ip4/1.2.3.1/tcp/123", "/ip4/1.2.3.254/tcp/123", } // Add default reject filter f.DefaultAction = ActionDeny // Add whitelisting _, ipnet, _ := net.ParseCIDR("1.2.3.0/24") f.AddFilter(*ipnet, ActionAccept) if a, ok := f.ActionForFilter(*ipnet); !ok || a != ActionAccept { t.Fatal("Expected filter with ACCEPT action") } // these are all whitelisted, should be OK for _, addr := range ips { maddr, err := NewMultiaddr(addr) if err != nil { t.Error(err) } if f.AddrBlocked(maddr) { t.Fatalf("expected %s to be whitelisted", addr) } } // Test removing the filter. It'll remove multiple, so make a dupe & // a complement f.AddFilter(*ipnet, ActionDeny) // Show that they all apply, these are now blacklisted & should fail for _, addr := range ips { maddr, err := NewMultiaddr(addr) if err != nil { t.Error(err) } if !f.AddrBlocked(maddr) { t.Fatalf("expected %s to be blacklisted", addr) } } // remove those rules if !f.RemoveLiteral(*ipnet) { t.Error("expected true value from RemoveLiteral") } // our default is reject, so the 1.2.3.0/24 should be rejected now, // along with everything else for _, addr := range ips { maddr, err := NewMultiaddr(addr) if err != nil { t.Error(err) } if !f.AddrBlocked(maddr) { t.Fatalf("expected %s to be blocked", addr) } } } go-multiaddr-0.16.1/go.mod000066400000000000000000000015721504514340500153030ustar00rootroot00000000000000module github.com/multiformats/go-multiaddr go 1.23 require ( github.com/ipfs/go-cid v0.0.7 github.com/multiformats/go-multibase v0.2.0 github.com/multiformats/go-multihash v0.2.3 github.com/multiformats/go-varint v0.0.7 github.com/stretchr/testify v1.7.0 golang.org/x/exp v0.0.0-20230725012225-302865e7556b ) require ( github.com/davecgh/go-spew v1.1.0 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/sys v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.0 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) go-multiaddr-0.16.1/go.sum000066400000000000000000000120471504514340500153270ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20230725012225-302865e7556b h1:tK7yjGqVRzYdXsBcfD2MLhFAhHfDgGLm2rY1ub7FA9k= golang.org/x/exp v0.0.0-20230725012225-302865e7556b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= go-multiaddr-0.16.1/matest/000077500000000000000000000000001504514340500154655ustar00rootroot00000000000000go-multiaddr-0.16.1/matest/matest.go000066400000000000000000000040131504514340500173070ustar00rootroot00000000000000// Package matest provides utilities for testing with multiaddrs. package matest import ( "slices" "github.com/multiformats/go-multiaddr" ) type TestingT interface { Errorf(format string, args ...interface{}) } type tHelper interface { Helper() } func AssertEqualMultiaddr(t TestingT, expected, actual multiaddr.Multiaddr) bool { if h, ok := t.(tHelper); ok { h.Helper() } if !expected.Equal(actual) { t.Errorf("expected %v, got %v", expected, actual) return false } return true } func AssertEqualMultiaddrs(t TestingT, expected, actual []multiaddr.Multiaddr) bool { if h, ok := t.(tHelper); ok { h.Helper() } if len(expected) != len(actual) { t.Errorf("expected %v, got %v", expected, actual) return false } for i, e := range expected { if !e.Equal(actual[i]) { t.Errorf("expected %v, got %v", expected, actual) return false } } return true } // AssertMultiaddrsMatch is the same as AssertEqualMultiaddrs, but it ignores the order of the elements. func AssertMultiaddrsMatch(t TestingT, expected, actual []multiaddr.Multiaddr) bool { if h, ok := t.(tHelper); ok { h.Helper() } e := slices.Clone(expected) a := slices.Clone(actual) slices.SortFunc(e, func(a, b multiaddr.Multiaddr) int { return a.Compare(b) }) slices.SortFunc(a, func(a, b multiaddr.Multiaddr) int { return a.Compare(b) }) return AssertEqualMultiaddrs(t, e, a) } func AssertMultiaddrsContain(t TestingT, haystack []multiaddr.Multiaddr, needle multiaddr.Multiaddr) bool { if h, ok := t.(tHelper); ok { h.Helper() } for _, h := range haystack { if h.Equal(needle) { return true } } t.Errorf("expected %v to contain %v", haystack, needle) return false } type MultiaddrMatcher struct { multiaddr.Multiaddr } // Implements the Matcher interface for gomock.Matcher // Let's us use this struct in gomock tests. Example: // Expect(mock.Method(gomock.Any(), multiaddrMatcher).Return(nil) func (m MultiaddrMatcher) Matches(x interface{}) bool { if m2, ok := x.(multiaddr.Multiaddr); ok { return m.Equal(m2) } return false } go-multiaddr-0.16.1/meg_capturers.go000066400000000000000000000022031504514340500173540ustar00rootroot00000000000000package multiaddr import ( "encoding/binary" "fmt" "net/netip" "github.com/multiformats/go-multiaddr/x/meg" ) func CaptureAddrPort(network *string, ipPort *netip.AddrPort) (capturePattern meg.Pattern) { var ipOnly netip.Addr capturePort := func(s meg.Matchable) error { switch s.Code() { case P_UDP: *network = "udp" case P_TCP: *network = "tcp" default: return fmt.Errorf("invalid network: %s", s.Value()) } port := binary.BigEndian.Uint16(s.RawValue()) *ipPort = netip.AddrPortFrom(ipOnly, port) return nil } pattern := meg.Cat( meg.Or( meg.CaptureWithF(P_IP4, func(s meg.Matchable) error { var ok bool ipOnly, ok = netip.AddrFromSlice(s.RawValue()) if !ok { return fmt.Errorf("invalid ip4 address: %s", s.Value()) } return nil }), meg.CaptureWithF(P_IP6, func(s meg.Matchable) error { var ok bool ipOnly, ok = netip.AddrFromSlice(s.RawValue()) if !ok { return fmt.Errorf("invalid ip6 address: %s", s.Value()) } return nil }), ), meg.Or( meg.CaptureWithF(P_UDP, capturePort), meg.CaptureWithF(P_TCP, capturePort), ), ) return pattern } go-multiaddr-0.16.1/meg_test.go000066400000000000000000000031341504514340500163270ustar00rootroot00000000000000package multiaddr import ( "net/netip" "testing" "github.com/multiformats/go-multiaddr/x/meg" ) func TestMatchAndCaptureMultiaddr(t *testing.T) { m := StringCast("/ip4/1.2.3.4/udp/8231/quic-v1/webtransport/certhash/b2uaraocy6yrdblb4sfptaddgimjmmpy/certhash/zQmbWTwYGcmdyK9CYfNBcfs9nhZs17a6FQ4Y8oea278xx41") var udpPort string var certhashes []string found, _ := m.Match( meg.Or( meg.Val(P_IP4), meg.Val(P_IP6), ), meg.CaptureString(P_UDP, &udpPort), meg.Val(P_QUIC_V1), meg.Val(P_WEBTRANSPORT), meg.CaptureZeroOrMoreStrings(P_CERTHASH, &certhashes), ) if !found { t.Fatal("failed to match") } if udpPort != "8231" { t.Fatal("unexpected value") } if len(certhashes) != 2 { t.Fatal("Didn't capture all certhashes") } { m, c := SplitLast(m) if c.Value() != certhashes[1] { t.Fatal("unexpected value. Expected", c.RawValue(), "but got", []byte(certhashes[1])) } _, c = SplitLast(m) if c.Value() != certhashes[0] { t.Fatal("unexpected value. Expected", c.RawValue(), "but got", []byte(certhashes[0])) } } } func TestCaptureAddrPort(t *testing.T) { m := StringCast("/ip4/1.2.3.4/udp/8231/quic-v1/webtransport") var addrPort netip.AddrPort var network string found, err := m.Match( CaptureAddrPort(&network, &addrPort), meg.ZeroOrMore(meg.Any), ) if err != nil { t.Fatal("error", err) } if !found { t.Fatal("failed to match") } if !addrPort.IsValid() { t.Fatal("failed to capture addrPort") } if network != "udp" { t.Fatal("unexpected network", network) } if addrPort.String() != "1.2.3.4:8231" { t.Fatal("unexpected ipPort", addrPort) } } go-multiaddr-0.16.1/multiaddr.go000066400000000000000000000140341504514340500165060ustar00rootroot00000000000000package multiaddr import ( "cmp" "encoding/json" "errors" "fmt" "log" "strings" "golang.org/x/exp/slices" ) var errNilPtr = errors.New("nil ptr") // Multiaddr is the data structure representing a Multiaddr type Multiaddr []Component func (m Multiaddr) copy() Multiaddr { if m == nil { return nil } out := make(Multiaddr, len(m)) copy(out, m) return out } // NewMultiaddr parses and validates an input string, returning a *Multiaddr func NewMultiaddr(s string) (a Multiaddr, err error) { defer func() { if e := recover(); e != nil { log.Printf("Panic in NewMultiaddr on input %q: %s", s, e) err = fmt.Errorf("%v", e) } }() b, err := stringToBytes(s) if err != nil { return nil, err } return NewMultiaddrBytes(b) } // NewMultiaddrBytes initializes a Multiaddr from a byte representation. // It validates it as an input string. func NewMultiaddrBytes(b []byte) (a Multiaddr, err error) { defer func() { if e := recover(); e != nil { log.Printf("Panic in NewMultiaddrBytes on input %q: %s", b, e) err = fmt.Errorf("%v", e) } }() bytesRead, m, err := readMultiaddr(b) if err != nil { return nil, err } if bytesRead != len(b) { return nil, fmt.Errorf("unexpected extra data. %v bytes leftover", len(b)-bytesRead) } if len(m) == 0 { return nil, nil } return m, nil } // Equal tests whether two multiaddrs are equal func (m Multiaddr) Equal(m2 Multiaddr) bool { if len(m) != len(m2) { return false } for i, c := range m { if !c.Equal(&m2[i]) { return false } } return true } func (m Multiaddr) Compare(o Multiaddr) int { for i := 0; i < len(m) && i < len(o); i++ { if cmp := m[i].Compare(&o[i]); cmp != 0 { return cmp } } return cmp.Compare(len(m), len(o)) } // Bytes returns the []byte representation of this Multiaddr func (m Multiaddr) Bytes() []byte { size := 0 for _, c := range m { size += len(c.bytes) } // This method is inlined in the caller. Using a fixed sized array // avoids an allocation. var out []byte if size < 128 { var o [128]byte out = o[:0] } else { out = make([]byte, 0, size) } for _, c := range m { out = append(out, c.bytes...) } return out } // String returns the string representation of a Multiaddr func (m Multiaddr) String() string { var buf strings.Builder for _, c := range m { c.writeTo(&buf) } return buf.String() } func (m Multiaddr) MarshalBinary() ([]byte, error) { return m.Bytes(), nil } func (m *Multiaddr) UnmarshalBinary(data []byte) error { if m == nil { return errNilPtr } new, err := NewMultiaddrBytes(data) if err != nil { return err } *m = new return nil } func (m Multiaddr) MarshalText() ([]byte, error) { return []byte(m.String()), nil } func (m *Multiaddr) UnmarshalText(data []byte) error { if m == nil { return errNilPtr } new, err := NewMultiaddr(string(data)) if err != nil { return err } *m = new return nil } func (m Multiaddr) MarshalJSON() ([]byte, error) { return json.Marshal(m.String()) } func (m *Multiaddr) UnmarshalJSON(data []byte) error { if m == nil { return errNilPtr } var v string if err := json.Unmarshal(data, &v); err != nil { return err } new, err := NewMultiaddr(v) *m = new return err } // Protocols returns the list of protocols this Multiaddr has. // will panic in case we access bytes incorrectly. func (m Multiaddr) Protocols() []Protocol { out := make([]Protocol, 0, len(m)) for _, c := range m { out = append(out, c.Protocol()) } return out } type Multiaddrer interface { // Multiaddr returns the Multiaddr representation Multiaddr() Multiaddr } func (m Multiaddr) Multiaddr() Multiaddr { return m } // AppendComponent is the same as using `append(m, *c)`, but with a safety check // for a nil Component. func (m Multiaddr) AppendComponent(cs ...*Component) Multiaddr { for _, c := range cs { if c == nil { continue } m = append(m, *c) } return m } // Encapsulate wraps a given Multiaddr, returning the resulting joined Multiaddr func (m Multiaddr) Encapsulate(other Multiaddrer) Multiaddr { return Join(m, other) } // Decapsulate unwraps Multiaddr up until the given Multiaddr is found. func (m Multiaddr) Decapsulate(rightPartsAny Multiaddrer) Multiaddr { if rightPartsAny == nil { return m } rightParts := rightPartsAny.Multiaddr() leftParts := m lastIndex := -1 for i := range leftParts { foundMatch := false for j, rightC := range rightParts { if len(leftParts) <= i+j { foundMatch = false break } foundMatch = rightC.Equal(&leftParts[i+j]) if !foundMatch { break } } if foundMatch { lastIndex = i } } if lastIndex == 0 { return nil } if lastIndex < 0 { return m } return leftParts[:lastIndex] } var ErrProtocolNotFound = fmt.Errorf("protocol not found in multiaddr") func (m Multiaddr) ValueForProtocol(code int) (value string, err error) { for _, c := range m { if c.Protocol().Code == code { return c.Value(), nil } } return "", ErrProtocolNotFound } // FilterAddrs is a filter that removes certain addresses, according to the given filters. // If all filters return true, the address is kept. func FilterAddrs(a []Multiaddr, filters ...func(Multiaddr) bool) []Multiaddr { b := make([]Multiaddr, 0, len(a)) addrloop: for _, addr := range a { for _, filter := range filters { if !filter(addr) { continue addrloop } } b = append(b, addr) } return b } // Contains reports whether addr is contained in addrs. func Contains(addrs []Multiaddr, addr Multiaddr) bool { for _, a := range addrs { if addr.Equal(a) { return true } } return false } // Unique deduplicates addresses in place, leave only unique addresses. // It doesn't allocate. func Unique(addrs []Multiaddr) []Multiaddr { if len(addrs) == 0 { return addrs } // Use the new slices package here, as the sort function doesn't allocate (sort.Slice does). slices.SortFunc(addrs, func(a, b Multiaddr) int { return a.Compare(b) }) idx := 1 for i := 1; i < len(addrs); i++ { if !addrs[i-1].Equal(addrs[i]) { addrs[idx] = addrs[i] idx++ } } for i := idx; i < len(addrs); i++ { addrs[i] = nil } return addrs[:idx] } go-multiaddr-0.16.1/multiaddr/000077500000000000000000000000001504514340500161555ustar00rootroot00000000000000go-multiaddr-0.16.1/multiaddr/main.go000066400000000000000000000042041504514340500174300ustar00rootroot00000000000000package main import ( "encoding/hex" "flag" "fmt" "os" "strings" maddr "github.com/multiformats/go-multiaddr" ) var ( flagHelp bool ) func main() { flag.Usage = func() { usage := `usage: %s [options] ADDR Print details about the given multiaddr. Options: ` fmt.Fprintf(os.Stderr, usage, os.Args[0]) flag.PrintDefaults() } flag.BoolVar(&flagHelp, "h", false, "display help message") flag.Parse() if flagHelp || len(flag.Args()) == 0 { flag.Usage() os.Exit(0) } addrStr := flag.Args()[0] var addr maddr.Multiaddr var merr error if strings.HasPrefix(addrStr, "0x") { addrBytes, err := hex.DecodeString(addrStr[2:]) if err != nil { fmt.Fprintf(os.Stderr, "parse error: %s\n", err) os.Exit(1) } addr, merr = maddr.NewMultiaddrBytes(addrBytes) } else { addr, merr = maddr.NewMultiaddr(addrStr) } if merr != nil { fmt.Fprintf(os.Stderr, "parse error: %s\n", merr) os.Exit(1) } infoCommand(addr) } func infoCommand(addr maddr.Multiaddr) { var compsJson []string for _, comp := range addr { lengthPrefix := "" if comp.Protocol().Size == maddr.LengthPrefixedVarSize { lengthPrefix = "0x" + hex.EncodeToString(maddr.CodeToVarint(len(comp.RawValue()))) } compsJson = append(compsJson, `{`+ fmt.Sprintf(`"string": "%s", `, comp.String())+ fmt.Sprintf(`"stringSize": "%d", `, len(comp.String()))+ fmt.Sprintf(`"packed": "0x%x", `, comp.Bytes())+ fmt.Sprintf(`"packedSize": "%d", `, len(comp.Bytes()))+ fmt.Sprintf(`"value": %#v, `, comp.Value())+ fmt.Sprintf(`"rawValue": "0x%x", `, comp.RawValue())+ fmt.Sprintf(`"valueSize": "%d", `, len(comp.RawValue()))+ fmt.Sprintf(`"protocol": "%s", `, comp.Protocol().Name)+ fmt.Sprintf(`"codec": "%d", `, comp.Protocol().Code)+ fmt.Sprintf(`"uvarint": "0x%x", `, comp.Protocol().VCode)+ fmt.Sprintf(`"lengthPrefix": "%s"`, lengthPrefix)+ `}`) } addrJson := `{ "string": "%[1]s", "stringSize": "%[2]d", "packed": "0x%[3]x", "packedSize": "%[4]d", "components": [ %[5]s ] }` fmt.Fprintf(os.Stdout, addrJson+"\n", addr.String(), len(addr.String()), addr.Bytes(), len(addr.Bytes()), strings.Join(compsJson, ",\n ")) } go-multiaddr-0.16.1/multiaddr_test.go000066400000000000000000001277441504514340500175620ustar00rootroot00000000000000package multiaddr import ( "bytes" "encoding/hex" "fmt" "math" "math/rand" "testing" "github.com/ipfs/go-cid" mh "github.com/multiformats/go-multihash" "github.com/stretchr/testify/require" ) func newMultiaddr(t *testing.T, a string) Multiaddr { m, err := NewMultiaddr(a) if err != nil { t.Error(err) } return m } func TestReturnsNilOnEmpty(t *testing.T) { a := StringCast("/ip4/1.2.3.4") a, _ = SplitLast(a) require.Nil(t, a) a, _ = SplitLast(a) require.Nil(t, a) a, c := SplitLast(nil) require.Zero(t, len(a.Protocols())) require.Nil(t, a) require.Nil(t, c) // Test that empty multiaddr from various operations returns nil a = StringCast("/ip4/1.2.3.4/tcp/1234") _, a = SplitFirst(a) _, a = SplitFirst(a) require.Nil(t, a) _, a = SplitFirst(a) require.Nil(t, a) c, a = SplitFirst(nil) require.Nil(t, a) require.Nil(t, c) a = StringCast("/ip4/1.2.3.4/tcp/1234") a = a.Decapsulate(a) require.Nil(t, a) a = StringCast("/ip4/1.2.3.4/tcp/1234") a = a.Decapsulate(StringCast("/tcp/1234")) a = a.Decapsulate(StringCast("/ip4/1.2.3.4")) require.Nil(t, a) // Test that SplitFunc returns nil when we split at beginning and end a = StringCast("/ip4/1.2.3.4/tcp/1234") pre, _ := SplitFunc(a, func(c Component) bool { return c.Protocol().Code == P_IP4 }) require.Nil(t, pre) a = StringCast("/ip4/1.2.3.4/tcp/1234") _, post := SplitFunc(a, func(c Component) bool { return false }) require.Nil(t, post) _, err := NewMultiaddr("") require.Error(t, err) var nilMultiaddr Multiaddr a = nilMultiaddr.AppendComponent() require.Nil(t, a) a = Join() require.Nil(t, a) } func TestJoinWithComponents(t *testing.T) { var m Multiaddr c, err := NewComponent("ip4", "127.0.0.1") require.NoError(t, err) expected := "/ip4/127.0.0.1" require.Equal(t, expected, Join(m, c).String()) } func TestConstructFails(t *testing.T) { cases := []string{ "/ip4", "/ip4/::1", "/ip4/fdpsofodsajfdoisa", "/ip4/::/ipcidr/256", "/ip6/::/ipcidr/1026", "/ip6", "/ip6zone", "/ip6zone/", "/ip6zone//ip6/fe80::1", "/udp", "/tcp", "/sctp", "/udp/65536", "/tcp/65536", "/quic/65536", "/quic-v1/65536", "/onion/9imaq4ygg2iegci7:80", "/onion/aaimaq4ygg2iegci7:80", "/onion/timaq4ygg2iegci7:0", "/onion/timaq4ygg2iegci7:-1", "/onion/timaq4ygg2iegci7", "/onion/timaq4ygg2iegci@:666", "/onion3/9ww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:80", "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd7:80", "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:0", "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:-1", "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd", "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyy@:666", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA7:80", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA:0", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA:0", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA:-1", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA@:666", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA7:80", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA:0", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA:0", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA:-1", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA@:666", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzu", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzu77", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzu:80", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq:-1", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzu@", "/udp/1234/sctp", "/udp/1234/udt/1234", "/udp/1234/utp/1234", "/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa", "/ip4/127.0.0.1/udp", "/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa", "/ip4/127.0.0.1/tcp", "/ip4/127.0.0.1/quic/1234", "/ip4/127.0.0.1/quic-v1/1234", "/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash", "/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash/b2uaraocy6yrdblb4sfptaddgimjmmp", // 1 character missing from certhash "/ip4/127.0.0.1/ipfs", "/ip4/127.0.0.1/ipfs/tcp", "/ip4/127.0.0.1/p2p", "/ip4/127.0.0.1/p2p/tcp", "/unix", "/ip4/1.2.3.4/tcp/80/unix", "/ip4/1.2.3.4/tcp/-1", "/ip4/127.0.0.1/tcp/9090/http/p2p-webcrt-direct", fmt.Sprintf("/memory/%d1", uint64(1<<63)), "/", "", "/p2p/QmxoHT6iViN5xAjoz1VZ553cL31U9F94ht3QvWR1FrEbZY", // sha256 multihash with digest len > 32 } for _, a := range cases { if _, err := NewMultiaddr(a); err == nil { t.Errorf("should have failed: %s - %s", a, err) } } } func TestEmptyMultiaddr(t *testing.T) { _, err := NewMultiaddrBytes([]byte{}) if err == nil { t.Fatal("should have failed to parse empty multiaddr") } } var good = []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/2601:9:4f81:9700:803e:ca65:66e8:c21/udp/1234/quic-v1", "/ip6/2001:db8::/ipcidr/32", "/ip6zone/x/ip6/fe80::1", "/ip6zone/x%y/ip6/fe80::1", "/ip6zone/x%y/ip6/::", "/ip6zone/x/ip6/fe80::1/udp/1234/quic", "/ip6zone/x/ip6/fe80::1/udp/1234/quic-v1", "/onion/timaq4ygg2iegci7:1234", "/onion/timaq4ygg2iegci7:80/http", "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234", "/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:80/http", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA/http", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA/udp/8080", "/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA/tcp/8080", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuqzwas", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuqzwassw", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq/http", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq/tcp/8080", "/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq/udp/8080", "/udp/0", "/tcp/0", "/sctp/0", "/udp/1234", "/tcp/1234", "/sctp/1234", "/udp/65535", "/tcp/65535", "/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", "/ipfs/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7", "/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", "/p2p/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7", "/p2p/bafzbeigvf25ytwc3akrijfecaotc74udrhcxzh2cx3we5qqnw5vgrei4bm", "/p2p/12D3KooWCryG7Mon9orvQxcS1rYZjotPgpwoJNHHKcLLfE4Hf5mV", "/p2p/k51qzi5uqu5dhb6l8spkdx7yxafegfkee5by8h7lmjh2ehc2sgg34z7c15vzqs", "/p2p/bafzaajaiaejcalj543iwv2d7pkjt7ykvefrkfu7qjfi6sduakhso4lay6abn2d5u", "/udp/1234/sctp/1234", "/udp/1234/udt", "/udp/1234/utp", "/tcp/1234/http", "/tcp/1234/tls/http", "/tcp/1234/https", "/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", "/ipfs/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7/tcp/1234", "/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", "/p2p/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7/tcp/1234", "/ip4/127.0.0.1/udp/1234", "/ip4/127.0.0.1/udp/0", "/ip4/127.0.0.1/tcp/1234", "/ip4/127.0.0.1/tcp/1234/", "/ip4/127.0.0.1/udp/1234/quic", "/ip4/127.0.0.1/udp/1234/quic-v1", "/ip4/127.0.0.1/udp/1234/quic-v1/webtransport", "/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash/b2uaraocy6yrdblb4sfptaddgimjmmpy", "/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash/b2uaraocy6yrdblb4sfptaddgimjmmpy/certhash/zQmbWTwYGcmdyK9CYfNBcfs9nhZs17a6FQ4Y8oea278xx41", "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", "/ip4/127.0.0.1/ipfs/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7", "/ip4/127.0.0.1/ipfs/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7/tcp/1234", "/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", "/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", "/ip4/127.0.0.1/p2p/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7", "/ip4/127.0.0.1/p2p/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7/tcp/1234", "/unix/a/b/c/d/e", "/unix/stdio", "/ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f", "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio", "/ip4/127.0.0.1/ipfs/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7/tcp/1234/unix/stdio", "/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio", "/ip4/127.0.0.1/p2p/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7/tcp/1234/unix/stdio", "/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct", "/ip4/127.0.0.1/tcp/127/ws", "/ip4/127.0.0.1/tcp/127/ws", "/ip4/127.0.0.1/tcp/127/tls", "/ip4/127.0.0.1/tcp/127/tls/ws", "/ip4/127.0.0.1/tcp/127/noise", "/ip4/127.0.0.1/tcp/127/wss", "/ip4/127.0.0.1/tcp/127/wss", "/ip4/127.0.0.1/tcp/127/webrtc-direct", "/ip4/127.0.0.1/tcp/127/webrtc", "/http-path/tmp%2Fbar", "/http-path/tmp%2Fbar%2Fbaz", "/http-path/foo", "/ip4/127.0.0.1/tcp/0/p2p/12D3KooWCryG7Mon9orvQxcS1rYZjotPgpwoJNHHKcLLfE4Hf5mV/http-path/foo", "/ip4/127.0.0.1/tcp/443/tls/sni/example.com/http/http-path/foo", "/memory/4", } func TestConstructSucceeds(t *testing.T) { for _, a := range good { if _, err := NewMultiaddr(a); err != nil { t.Errorf("should have succeeded: %s -- %s", a, err) } } } func TestEqual(t *testing.T) { m1 := newMultiaddr(t, "/ip4/127.0.0.1/udp/1234") m2 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234") m3 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234") m4 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234/") if m1.Equal(m2) { t.Error("should not be equal") } if m2.Equal(m1) { t.Error("should not be equal") } if !m2.Equal(m3) { t.Error("should be equal") } if !m3.Equal(m2) { t.Error("should be equal") } if !m1.Equal(m1) { t.Error("should be equal") } if !m2.Equal(m4) { t.Error("should be equal") } if !m4.Equal(m3) { t.Error("should be equal") } } // TestNilInterface makes sure funcs that accept a multiaddr interface don't // panic if it's passed a nil interface. func TestNilInterface(t *testing.T) { m1 := newMultiaddr(t, "/ip4/127.0.0.1/udp/1234") var m2 Multiaddr m1.Equal(m2) m1.Encapsulate(m2) m1.Decapsulate(m2) // Test components c, _ := SplitFirst(m1) c.Multiaddr().Equal(m2) c.Encapsulate(m2) c.Decapsulate(m2) // Util funcs _ = Split(m2) _, _ = SplitFirst(m2) _, _ = SplitLast(m2) ForEach(m2, func(c Component) bool { return true }) } func TestStringToBytes(t *testing.T) { testString := func(s string, h string) { b1, err := hex.DecodeString(h) if err != nil { t.Error("failed to decode hex", h) } // t.Log("196", h, []byte(b1)) b2, err := stringToBytes(s) if err != nil { t.Error("failed to convert", s, err) } if !bytes.Equal(b1, b2) { t.Error("failed to convert \n", s, "to\n", hex.EncodeToString(b1), "got\n", hex.EncodeToString(b2)) } if _, err := NewMultiaddrBytes(b2); err != nil { t.Error(err, "len:", len(b2)) } } testString("/ip4/127.0.0.1/udp/1234", "047f000001910204d2") testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1") testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f000001910204d2047f0000010610e1") testString("/onion/aaimaq4ygg2iegci:80", "bc030010c0439831b48218480050") testString("/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234", "bd03adadec040be047f9658668b11a504f3155001f231a37f54c4476c07fb4cc139ed7e30304d2") testString("/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA", "be0383038d3fc8c976a86ae4e78ba378e75ec41bc9ab1542a9cb422581987e118f5cb0c024f3639d6ad9b3aff613672f07bfbbbfc2f920ef910534ecaa6ff9c03e0fa4872a764d2fce6d4cfc5a5a9800cd95944cc9ef0241f753fe71494a175f334b35682459acadc4076428ab49b5a83a49d2ea2366b06461e4a559b0111fa750e0de0c138a94d1231ed5979572ff53922905636221994bdabc44bd0c17fef11622b16432db3f193400af53cc61aa9bfc0c4c8d874b41a6e18732f0b60f5662ef1a89c80589dd8366c90bb58bb85ead56356aba2a244950ca170abbd01094539014f84bdd383e4a10e00cee63dfc3e809506e2d9b54edbdca1bace6eaa119e68573d30533791fba830f5d80be5c051a77c09415e3b8fe3139400848be5244b8ae96bb0c4a24f819cba0488f34985eac741d3359180bd72cafa1559e4c19f54ea8cedbb6a5afde4319396eb92aab340c60a50cc2284580cb3ad09017e8d9abc60269b3d8d687680bd86ce834412273d4f2e3bf68dd3d6fe87e2426ac658cd5c77fd5c0aa000000") testString("/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq", "bf0320efbcd45d0c5dc79781ac6f20ea5055a036afb48d45a52e7d68ec7d4338919e69") } func TestBytesToString(t *testing.T) { testString := func(s1 string, h string) { t.Helper() b, err := hex.DecodeString(h) if err != nil { t.Error("failed to decode hex", h) } if _, err := NewMultiaddrBytes(b); err != nil { t.Error(err) } m, err := NewMultiaddrBytes(b) s2 := m.String() if err != nil { t.Log("236", s1, ":", string(h), ":", s2) t.Error("failed to convert", b, err) } if s1 != s2 { t.Error("failed to convert", b, "to", s1, "got", s2) } } testString("/ip4/127.0.0.1/udp/1234", "047f000001910204d2") testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1") testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f000001910204d2047f0000010610e1") testString("/onion/aaimaq4ygg2iegci:80", "bc030010c0439831b48218480050") testString("/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234", "bd03adadec040be047f9658668b11a504f3155001f231a37f54c4476c07fb4cc139ed7e30304d2") testString("/garlic64/jT~IyXaoauTni6N4517EG8mrFUKpy0IlgZh-EY9csMAk82Odatmzr~YTZy8Hv7u~wvkg75EFNOyqb~nAPg-khyp2TS~ObUz8WlqYAM2VlEzJ7wJB91P-cUlKF18zSzVoJFmsrcQHZCirSbWoOknS6iNmsGRh5KVZsBEfp1Dg3gwTipTRIx7Vl5Vy~1OSKQVjYiGZS9q8RL0MF~7xFiKxZDLbPxk0AK9TzGGqm~wMTI2HS0Gm4Ycy8LYPVmLvGonIBYndg2bJC7WLuF6tVjVquiokSVDKFwq70BCUU5AU-EvdOD5KEOAM7mPfw-gJUG4tm1TtvcobrObqoRnmhXPTBTN5H7qDD12AvlwFGnfAlBXjuP4xOUAISL5SRLiulrsMSiT4GcugSI80mF6sdB0zWRgL1yyvoVWeTBn1TqjO27alr95DGTluuSqrNAxgpQzCKEWAyzrQkBfo2avGAmmz2NaHaAvYbOg0QSJz1PLjv2jdPW~ofiQmrGWM1cd~1cCqAAAA", "be0383038d3fc8c976a86ae4e78ba378e75ec41bc9ab1542a9cb422581987e118f5cb0c024f3639d6ad9b3aff613672f07bfbbbfc2f920ef910534ecaa6ff9c03e0fa4872a764d2fce6d4cfc5a5a9800cd95944cc9ef0241f753fe71494a175f334b35682459acadc4076428ab49b5a83a49d2ea2366b06461e4a559b0111fa750e0de0c138a94d1231ed5979572ff53922905636221994bdabc44bd0c17fef11622b16432db3f193400af53cc61aa9bfc0c4c8d874b41a6e18732f0b60f5662ef1a89c80589dd8366c90bb58bb85ead56356aba2a244950ca170abbd01094539014f84bdd383e4a10e00cee63dfc3e809506e2d9b54edbdca1bace6eaa119e68573d30533791fba830f5d80be5c051a77c09415e3b8fe3139400848be5244b8ae96bb0c4a24f819cba0488f34985eac741d3359180bd72cafa1559e4c19f54ea8cedbb6a5afde4319396eb92aab340c60a50cc2284580cb3ad09017e8d9abc60269b3d8d687680bd86ce834412273d4f2e3bf68dd3d6fe87e2426ac658cd5c77fd5c0aa000000") testString("/garlic32/566niximlxdzpanmn4qouucvua3k7neniwss47li5r6ugoertzuq", "bf0320efbcd45d0c5dc79781ac6f20ea5055a036afb48d45a52e7d68ec7d4338919e69") } func TestBytesSplitAndJoin(t *testing.T) { testString := func(s string, res []string) { m, err := NewMultiaddr(s) if err != nil { t.Fatal("failed to convert", s, err) } split := Split(m) if len(split) != len(res) { t.Error("not enough split components", split) return } for i, a := range split { if a.String() != res[i] { t.Errorf("split component failed: %s != %s", &a, res[i]) } } joined := append(Multiaddr{}, split...) if !m.Equal(joined) { t.Errorf("joined components failed: %s != %s", m, joined) } for i, a := range split { if a.String() != res[i] { t.Errorf("split component failed: %s != %s", &a, res[i]) } } } testString("/ip4/1.2.3.4/udp/1234", []string{"/ip4/1.2.3.4", "/udp/1234"}) testString("/ip4/1.2.3.4/tcp/1/ip4/2.3.4.5/udp/2", []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"}) } func TestProtocols(t *testing.T) { m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234") if err != nil { t.Error("failed to construct", "/ip4/127.0.0.1/udp/1234") } ps := m.Protocols() if ps[0].Code != ProtocolWithName("ip4").Code { t.Error(ps[0], ProtocolWithName("ip4")) t.Error("failed to get ip4 protocol") } if ps[1].Code != ProtocolWithName("udp").Code { t.Error(ps[1], ProtocolWithName("udp")) t.Error("failed to get udp protocol") } } func TestProtocolsWithString(t *testing.T) { pwn := ProtocolWithName good := map[string][]Protocol{ "/ip4": {pwn("ip4")}, "/ip4/tcp": {pwn("ip4"), pwn("tcp")}, "ip4/tcp/udp/ip6": {pwn("ip4"), pwn("tcp"), pwn("udp"), pwn("ip6")}, "////////ip4/tcp": {pwn("ip4"), pwn("tcp")}, "ip4/udp/////////": {pwn("ip4"), pwn("udp")}, "////////ip4/tcp////////": {pwn("ip4"), pwn("tcp")}, } for s, ps1 := range good { ps2, err := ProtocolsWithString(s) if err != nil { t.Errorf("ProtocolsWithString(%s) should have succeeded", s) } for i, ps1p := range ps1 { ps2p := ps2[i] if ps1p.Code != ps2p.Code { t.Errorf("mismatch: %s != %s, %s", ps1p.Name, ps2p.Name, s) } } } bad := []string{ "dsijafd", // bogus proto "/ip4/tcp/fidosafoidsa", // bogus proto "////////ip4/tcp/21432141/////////", // bogus proto "////////ip4///////tcp/////////", // empty protos in between } for _, s := range bad { if _, err := ProtocolsWithString(s); err == nil { t.Errorf("ProtocolsWithString(%s) should have failed", s) } } } func TestEncapsulate(t *testing.T) { m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234") if err != nil { t.Error(err) } m2, err := NewMultiaddr("/udp/5678") if err != nil { t.Error(err) } b := m.Encapsulate(m2) if s := b.String(); s != "/ip4/127.0.0.1/udp/1234/udp/5678" { t.Error("encapsulate /ip4/127.0.0.1/udp/1234/udp/5678 failed.", s) } m3, _ := NewMultiaddr("/udp/5678") c := b.Decapsulate(m3) if s := c.String(); s != "/ip4/127.0.0.1/udp/1234" { t.Error("decapsulate /udp failed.", "/ip4/127.0.0.1/udp/1234", s) } m4, _ := NewMultiaddr("/ip4/127.0.0.1") d := c.Decapsulate(m4) if d != nil { t.Error("decapsulate /ip4 failed: ", d) } t.Run("Encapsulating with components", func(t *testing.T) { left, last := SplitLast(m) joined := left.Encapsulate(last) require.True(t, joined.Equal(m)) first, rest := SplitFirst(m) joined = first.Encapsulate(rest) require.True(t, joined.Equal(m)) // Component type joined = (*first).Encapsulate(rest) require.True(t, joined.Equal(m)) }) } func TestDecapsulateComment(t *testing.T) { // shows the behavior from the interface comment m := StringCast("/ip4/1.2.3.4/tcp/80") rest := m.Decapsulate(StringCast("/tcp/80")) if rest.String() != "/ip4/1.2.3.4" { t.Fatalf("Documented behavior is not correct. Expected %v saw %v", "/ip4/1.2.3.4/", rest.String()) } m = StringCast("/ip4/1.2.3.4/tcp/80") rest = m.Decapsulate(StringCast("/udp/80")) if !rest.Equal(m) { t.Fatalf("Documented behavior is not correct. Expected %v saw %v", "/ip4/1.2.3.4/tcp/80", rest.String()) } m = StringCast("/ip4/1.2.3.4/tcp/80") rest = m.Decapsulate(StringCast("/ip4/1.2.3.4")) require.Nil(t, rest, "expected a nil multiaddr if we decapsulate everything") } func TestDecapsulate(t *testing.T) { t.Run("right is nil", func(t *testing.T) { left := StringCast("/ip4/1.2.3.4/tcp/1") var right Multiaddr left.Decapsulate(right) }) testcases := []struct { left, right, expected string }{ {"/ip4/1.2.3.4/tcp/1234", "/ip4/1.2.3.4", ""}, {"/ip4/1.2.3.4", "/ip4/1.2.3.4/tcp/1234", "/ip4/1.2.3.4"}, {"/ip4/1.2.3.5/tcp/1234", "/ip4/5.3.2.1", "/ip4/1.2.3.5/tcp/1234"}, {"/ip4/1.2.3.5/udp/1234/quic-v1", "/udp/1234", "/ip4/1.2.3.5"}, {"/ip4/1.2.3.6/udp/1234/quic-v1", "/udp/1234/quic-v1", "/ip4/1.2.3.6"}, {"/ip4/1.2.3.7/tcp/1234", "/ws", "/ip4/1.2.3.7/tcp/1234"}, {"/dnsaddr/wss.com/tcp/4001", "/ws", "/dnsaddr/wss.com/tcp/4001"}, {"/dnsaddr/wss.com/tcp/4001/ws", "/wss", "/dnsaddr/wss.com/tcp/4001/ws"}, {"/dnsaddr/wss.com/ws", "/wss", "/dnsaddr/wss.com/ws"}, {"/dnsaddr/wss.com/ws", "/dnsaddr/wss.com", ""}, {"/dnsaddr/wss.com/tcp/4001/wss", "/wss", "/dnsaddr/wss.com/tcp/4001"}, } for _, tc := range testcases { t.Run(tc.left, func(t *testing.T) { left := StringCast(tc.left) right := StringCast(tc.right) actualMa := left.Decapsulate(right) if tc.expected == "" { require.Nil(t, actualMa, "expected nil") return } actual := actualMa.String() expected := StringCast(tc.expected).String() require.Equal(t, expected, actual) }) } for _, tc := range testcases { t.Run("Decapsulating with components"+tc.left, func(t *testing.T) { left, last := SplitLast(StringCast(tc.left)) butLast := left.Decapsulate(last) require.Equal(t, butLast.String(), left.String()) // Round trip require.Equal(t, tc.left, butLast.Encapsulate(last).String()) }) } } func assertValueForProto(t *testing.T, a Multiaddr, p int, exp string) { t.Logf("checking for %s in %s", ProtocolWithCode(p).Name, a) fv, err := a.ValueForProtocol(p) if err != nil { t.Fatal(err) } if fv != exp { t.Fatalf("expected %q for %d in %s, but got %q instead", exp, p, a, fv) } } func TestAppendComponent(t *testing.T) { var m Multiaddr res := m.AppendComponent(nil) require.Equal(t, m, res) c, err := NewComponent("ip4", "127.0.0.1") require.NoError(t, err) res = m.AppendComponent(c) require.Equal(t, "/ip4/127.0.0.1", res.String()) } func TestGetValue(t *testing.T) { a := newMultiaddr(t, "/ip4/127.0.0.1/utp/tcp/5555/udp/1234/tls/utp/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP") assertValueForProto(t, a, P_IP4, "127.0.0.1") assertValueForProto(t, a, P_UTP, "") assertValueForProto(t, a, P_TLS, "") assertValueForProto(t, a, P_TCP, "5555") assertValueForProto(t, a, P_UDP, "1234") assertValueForProto(t, a, P_IPFS, "QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP") assertValueForProto(t, a, P_P2P, "QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP") _, err := a.ValueForProtocol(P_IP6) switch err { case ErrProtocolNotFound: break case nil: t.Fatal("expected value lookup to fail") default: t.Fatalf("expected ErrProtocolNotFound but got: %s", err) } a = newMultiaddr(t, "/ip4/0.0.0.0") // only one addr assertValueForProto(t, a, P_IP4, "0.0.0.0") a = newMultiaddr(t, "/ip4/0.0.0.0/ip4/0.0.0.0/ip4/0.0.0.0") // same sub-addr assertValueForProto(t, a, P_IP4, "0.0.0.0") a = newMultiaddr(t, "/ip4/0.0.0.0/udp/12345/utp") // ending in a no-value one. assertValueForProto(t, a, P_IP4, "0.0.0.0") assertValueForProto(t, a, P_UDP, "12345") assertValueForProto(t, a, P_UTP, "") a = newMultiaddr(t, "/ip4/0.0.0.0/unix/a/b/c/d") // ending in a path one. assertValueForProto(t, a, P_IP4, "0.0.0.0") assertValueForProto(t, a, P_UNIX, "/a/b/c/d") } func FuzzNewMultiaddrBytes(f *testing.F) { for _, v := range good { ma, err := NewMultiaddr(v) if err != nil { f.Fatal(err) } f.Add(ma.Bytes()) } f.Fuzz(func(t *testing.T, b []byte) { // just checking that it doesn't panic ma, err := NewMultiaddrBytes(b) if err == nil { // for any valid multiaddrs, make sure these calls don't panic ma.Protocols() roundTripBytes(t, ma) roundTripString(t, ma) } }) } func FuzzNewMultiaddrString(f *testing.F) { for _, v := range good { if _, err := NewMultiaddr(v); err != nil { // Validate maddrs f.Fatal(err) } f.Add(v) } f.Fuzz(func(t *testing.T, s string) { // just checking that it doesn't panic ma, err := NewMultiaddr(s) if err == nil { // for any valid multiaddrs, make sure these calls don't panic ma.Protocols() roundTripBytes(t, ma) roundTripString(t, ma) } }) } func roundTripBytes(t *testing.T, orig Multiaddr) { m2, err := NewMultiaddrBytes(orig.Bytes()) if err != nil { t.Fatalf("failed to parse maddr back from ma.Bytes, %v: %v", orig, err) } if !m2.Equal(orig) { t.Fatalf("unequal maddr after roundTripBytes %v %v", orig, m2) } } func roundTripString(t *testing.T, orig Multiaddr) { m2, err := NewMultiaddr(orig.String()) if err != nil { t.Fatalf("failed to parse maddr back from ma.String, %v: %v", orig, err) } if !m2.Equal(orig) { t.Fatalf("unequal maddr after roundTripString %v %v\n% 02x\n% 02x\n", orig, m2, orig.Bytes(), m2.Bytes()) } } func TestBinaryRepresentation(t *testing.T) { expected := []byte{0x4, 0x7f, 0x0, 0x0, 0x1, 0x91, 0x2, 0x4, 0xd2} ma, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234") if err != nil { t.Error(err) } if !bytes.Equal(ma.Bytes(), expected) { t.Errorf("expected %x, got %x", expected, ma.Bytes()) } } func TestRoundTrip(t *testing.T) { for _, s := range []string{ "/unix/a/b/c/d", "/ip6/::ffff:127.0.0.1/tcp/111", "/ip4/127.0.0.1/tcp/123", "/ip4/127.0.0.1/tcp/123/tls", "/ip4/127.0.0.1/udp/123", "/ip4/127.0.0.1/udp/123/ip6/::", "/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash/uEiDDq4_xNyDorZBH3TlGazyJdOWSwvo4PUo5YHFMrvDE8g", "/p2p/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP", "/p2p/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP/unix/a/b/c", "/http-path/tmp%2Fbar", } { ma, err := NewMultiaddr(s) if err != nil { t.Errorf("error when parsing %q: %s", s, err) continue } if ma.String() != s { t.Errorf("failed to round trip %q", s) } } } func TestIPFSvP2P(t *testing.T) { var ( p2pAddr = "/p2p/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP" ipfsAddr = "/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP" ) for _, s := range []string{p2pAddr, ipfsAddr} { ma, err := NewMultiaddr(s) if err != nil { t.Errorf("error when parsing %q: %s", s, err) } if ma.String() != p2pAddr { t.Errorf("expected %q, got %q", p2pAddr, ma.String()) } } } func TestInvalidP2PAddrBytes(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() } } func TestInvalidP2PAddrString(t *testing.T) { hashedData, err := mh.Sum([]byte("test"), mh.SHA2_256, -1) if err != nil { t.Fatal(err) } // using MD5 since it's not a valid data codec unknownCodecCID := cid.NewCidV1(mh.MD5, hashedData).String() badStringAddrs := []string{ "/p2p/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl-", // invalid multibase encoding "/p2p/?unknownmultibase", // invalid multibase encoding "/p2p/k2jmtxwoe2phm1hbqp0e7nufqf6umvuu2e9qd7ana7h411a0haqj6i2z", // non-libp2p-key codec "/p2p/" + unknownCodecCID, // impossible codec } for _, a := range badStringAddrs { ma, err := NewMultiaddr(a) if err == nil { t.Error("should have failed") // Check for panic _ = ma.String() } } } func TestZone(t *testing.T) { ip6String := "/ip6zone/eth0/ip6/::1" ip6Bytes := []byte{ 0x2a, 4, 'e', 't', 'h', '0', 0x29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, } ma, err := NewMultiaddr(ip6String) if err != nil { t.Error(err) } if !bytes.Equal(ma.Bytes(), ip6Bytes) { t.Errorf("expected %x, got %x", ip6Bytes, ma.Bytes()) } ma2, err2 := NewMultiaddrBytes(ip6Bytes) if err2 != nil { t.Error(err) } if ma2.String() != ip6String { t.Errorf("expected %s, got %s", ip6String, ma2.String()) } } func TestBinaryMarshaler(t *testing.T) { addr := newMultiaddr(t, "/ip4/0.0.0.0/tcp/4001/tls") b, err := addr.MarshalBinary() if err != nil { t.Fatal(err) } var addr2 Multiaddr if err = addr2.UnmarshalBinary(b); err != nil { t.Fatal(err) } if !addr.Equal(addr2) { t.Error("expected equal addresses in circular marshaling test") } } func TestTextMarshaler(t *testing.T) { addr := newMultiaddr(t, "/ip4/0.0.0.0/tcp/4001/tls") b, err := addr.MarshalText() if err != nil { t.Fatal(err) } var addr2 Multiaddr if err = addr2.UnmarshalText(b); err != nil { t.Fatal(err) } if !addr.Equal(addr2) { t.Error("expected equal addresses in circular marshaling test") } } func TestJSONMarshaler(t *testing.T) { addr := newMultiaddr(t, "/ip4/0.0.0.0/tcp/4001/tls") b, err := addr.MarshalJSON() if err != nil { t.Fatal(err) } var addr2 Multiaddr if err = addr2.UnmarshalJSON(b); err != nil { t.Fatal(err) } if !addr.Equal(addr2) { t.Error("expected equal addresses in circular marshaling test") } } func TestComponentBinaryMarshaler(t *testing.T) { comp, err := NewComponent("ip4", "0.0.0.0") if err != nil { t.Fatal(err) } b, err := comp.MarshalBinary() if err != nil { t.Fatal(err) } var comp2 Component if err = comp2.UnmarshalBinary(b); err != nil { t.Fatal(err) } if !comp.Equal(&comp2) { t.Error("expected equal components in circular marshaling test") } } func TestComponentTextMarshaler(t *testing.T) { comp, err := NewComponent("ip4", "0.0.0.0") if err != nil { t.Fatal(err) } b, err := comp.MarshalText() if err != nil { t.Fatal(err) } var comp2 Component if err = comp2.UnmarshalText(b); err != nil { t.Fatal(err) } if !comp.Equal(&comp2) { t.Error("expected equal components in circular marshaling test") } } func TestComponentJSONMarshaler(t *testing.T) { comp, err := NewComponent("ip4", "0.0.0.0") if err != nil { t.Fatal(err) } b, err := comp.MarshalJSON() if err != nil { t.Fatal(err) } var comp2 Component if err = comp2.UnmarshalJSON(b); err != nil { t.Fatal(err) } if !comp.Equal(&comp2) { t.Error("expected equal components in circular marshaling test") } } func TestUseNil(t *testing.T) { f := func() Multiaddr { return nil } _ = f() var foo Multiaddr = nil _, right := SplitFirst(foo) right.Protocols() foo.Protocols() foo.Bytes() foo.Compare(nil) foo.Decapsulate(nil) foo.Encapsulate(nil) foo.Equal(nil) _, _ = foo.MarshalBinary() _, _ = foo.MarshalJSON() _, _ = foo.MarshalText() foo.Protocols() _ = foo.String() _ = foo.UnmarshalBinary(nil) _ = foo.UnmarshalJSON(nil) _ = foo.UnmarshalText(nil) _, _ = foo.ValueForProtocol(0) } func TestUseNilComponent(t *testing.T) { var foo *Component foo.Multiaddr() foo.Encapsulate(nil) foo.Decapsulate(nil) require.True(t, foo == nil) foo.Bytes() foo.MarshalBinary() foo.MarshalJSON() foo.MarshalText() foo.UnmarshalBinary(nil) foo.UnmarshalJSON(nil) foo.UnmarshalText(nil) foo.Equal(nil) foo.Compare(nil) foo.Protocols() foo.ValueForProtocol(0) foo.Protocol() foo.RawValue() foo.Value() _ = foo.String() var m Multiaddr = nil m.Encapsulate(foo) } func TestFilterAddrs(t *testing.T) { bad := []Multiaddr{ newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), newMultiaddr(t, "/ip6/fe80::100/tcp/1234"), } good := []Multiaddr{ newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), newMultiaddr(t, "/ip4/1.1.1.1/tcp/999"), newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/utp"), } goodAndBad := append(good, bad...) filter := func(addr Multiaddr) bool { return addr.Protocols()[0].Code == P_IP4 } require.Empty(t, FilterAddrs(bad, filter)) require.ElementsMatch(t, FilterAddrs(good, filter), good) require.ElementsMatch(t, FilterAddrs(goodAndBad, filter), good) } func TestContains(t *testing.T) { a1 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234") a2 := newMultiaddr(t, "/ip4/1.1.1.1/tcp/999") a3 := newMultiaddr(t, "/ip4/1.2.3.4/udp/443/quic") a4 := newMultiaddr(t, "/ip4/1.2.3.4/udp/443/quic-v1") addrs := []Multiaddr{a1, a2, a3, a4} require.True(t, Contains(addrs, a1)) require.True(t, Contains(addrs, a2)) require.True(t, Contains(addrs, a3)) require.True(t, Contains(addrs, a4)) require.False(t, Contains(addrs, newMultiaddr(t, "/ip4/4.3.2.1/udp/1234/utp"))) require.False(t, Contains(nil, a1)) } func TestUniqueAddrs(t *testing.T) { tcpAddr := StringCast("/ip4/127.0.0.1/tcp/1234") quicAddr := StringCast("/ip4/127.0.0.1/udp/1234/quic-v1") wsAddr := StringCast("/ip4/127.0.0.1/tcp/1234/ws") type testcase struct { in, out []Multiaddr } for i, tc := range []testcase{ {in: nil, out: nil}, {in: []Multiaddr{tcpAddr}, out: []Multiaddr{tcpAddr}}, {in: []Multiaddr{tcpAddr, tcpAddr, tcpAddr}, out: []Multiaddr{tcpAddr}}, {in: []Multiaddr{tcpAddr, quicAddr, tcpAddr}, out: []Multiaddr{tcpAddr, quicAddr}}, {in: []Multiaddr{tcpAddr, quicAddr, wsAddr}, out: []Multiaddr{tcpAddr, quicAddr, wsAddr}}, } { tc := tc t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) { deduped := Unique(tc.in) for _, a := range tc.out { require.Contains(t, deduped, a) } }) } } func BenchmarkUniqueAddrs(b *testing.B) { b.ReportAllocs() var addrs []Multiaddr r := rand.New(rand.NewSource(1234)) for i := 0; i < 100; i++ { tcpAddr := StringCast(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", r.Intn(math.MaxUint16))) quicAddr := StringCast(fmt.Sprintf("/ip4/127.0.0.1/udp/%d/quic-v1", r.Intn(math.MaxUint16))) wsAddr := StringCast(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/ws", r.Intn(math.MaxUint16))) addrs = append(addrs, tcpAddr, tcpAddr, quicAddr, quicAddr, wsAddr) } for _, sz := range []int{10, 20, 30, 50, 100} { b.Run(fmt.Sprintf("%d", sz), func(b *testing.B) { items := make([]Multiaddr, sz) for i := 0; i < b.N; i++ { copy(items, addrs[:sz]) Unique(items) } }) } } func TestDNS(t *testing.T) { b := []byte("7*000000000000000000000000000000000000000000") a, err := NewMultiaddrBytes(b) if err != nil { t.Fatal(err) } aa := StringCast(a.String()) if !a.Equal(aa) { t.Fatal("expected equality") } } func TestHTTPPath(t *testing.T) { t.Run("bad addr", func(t *testing.T) { badAddr := "/http-path/thisIsMissingAfullByte%f" _, err := NewMultiaddr(badAddr) require.Error(t, err) }) t.Run("only reads the http-path part", func(t *testing.T) { addr := "/http-path/tmp%2Fbar/p2p-circuit" // The http-path only reference the part immediately after it. It does not include the rest of the multiaddr (like the /path component sometimes does) m, err := NewMultiaddr(addr) require.NoError(t, err) m.ValueForProtocol(P_HTTP_PATH) v, err := m.ValueForProtocol(P_HTTP_PATH) require.NoError(t, err) require.Equal(t, "tmp%2Fbar", v) }) t.Run("round trip", func(t *testing.T) { cases := []string{ "/http-path/tmp%2Fbar", "/http-path/tmp%2Fbar%2Fbaz", "/http-path/foo", "/ip4/127.0.0.1/tcp/0/p2p/12D3KooWCryG7Mon9orvQxcS1rYZjotPgpwoJNHHKcLLfE4Hf5mV/http-path/foo", "/ip4/127.0.0.1/tcp/443/tls/sni/example.com/http/http-path/foo", } for _, c := range cases { m, err := NewMultiaddr(c) require.NoError(t, err) require.Equal(t, c, m.String()) } }) t.Run("value for protocol", func(t *testing.T) { m := StringCast("/http-path/tmp%2Fbar") v, err := m.ValueForProtocol(P_HTTP_PATH) require.NoError(t, err) // This gives us the url escaped version require.Equal(t, "tmp%2Fbar", v) // If we want the raw unescaped version, we can use the component and read it _, component := SplitLast(m) require.Equal(t, "tmp/bar", string(component.RawValue())) }) } func FuzzSplitRoundtrip(f *testing.F) { for _, v := range good { f.Add(v) } otherMultiaddr := StringCast("/udp/1337") f.Fuzz(func(t *testing.T, addrStr string) { addr, err := NewMultiaddr(addrStr) if err != nil { t.Skip() // Skip inputs that are not valid multiaddrs } // Test SplitFirst first, rest := SplitFirst(addr) joined := Join(first, rest) require.True(t, addr.Equal(joined), "SplitFirst and Join should round-trip") // Test SplitLast rest, last := SplitLast(addr) joined = Join(rest, last) require.True(t, addr.Equal(joined), "SplitLast and Join should round-trip") p := addr.Protocols() if len(p) == 0 { t.Skip() } tryPubMethods := func(a Multiaddr) { if a == nil { return } _ = a.Equal(otherMultiaddr) _ = a.Bytes() _ = a.String() _ = a.Protocols() _ = a.Encapsulate(otherMultiaddr) _ = a.Decapsulate(otherMultiaddr) _, _ = a.ValueForProtocol(P_TCP) } for _, proto := range p { splitFunc := func(c Component) bool { return c.Protocol().Code == proto.Code } beforeC, after := SplitFirst(addr) joined = Join(beforeC, after) require.True(t, addr.Equal(joined)) tryPubMethods(after) before, afterC := SplitLast(addr) joined = Join(before, afterC) require.True(t, addr.Equal(joined)) tryPubMethods(before) before, after = SplitFunc(addr, splitFunc) joined = Join(before, after) require.True(t, addr.Equal(joined)) tryPubMethods(before) tryPubMethods(after) } }) } func BenchmarkComponentValidation(b *testing.B) { comp, err := NewComponent("ip4", "127.0.0.1") if err != nil { b.Fatal(err) } b.ReportAllocs() for i := 0; i < b.N; i++ { err := validateComponent(comp) if err != nil { b.Fatal(err) } } } func FuzzComponents(f *testing.F) { for _, v := range good { m := StringCast(v) for _, c := range m { f.Add(c.Bytes()) } } f.Fuzz(func(t *testing.T, compBytes []byte) { n, c, err := readComponent(compBytes) if err != nil { t.Skip() } if c.protocol == nil { t.Fatal("component has nil protocol") } if c.protocol.Code == 0 { t.Fatal("component has nil protocol code") } if !bytes.Equal(c.Bytes(), compBytes[:n]) { t.Logf("component bytes: %v", c.Bytes()) t.Logf("original bytes: %v", compBytes[:n]) t.Fatal("component bytes are not equal to the original bytes") } }) } func BenchmarkBytes(b *testing.B) { addr := StringCast("/ip4/127.0.0.1/tcp/1234") b.ReportAllocs() b.ResetTimer() m := make(map[string]Multiaddr) for i := 0; i < b.N; i++ { _ = addr.Bytes() if _, ok := m[string(addr.Bytes())]; !ok { m["a"] = addr } } } go-multiaddr-0.16.1/net/000077500000000000000000000000001504514340500147565ustar00rootroot00000000000000go-multiaddr-0.16.1/net/convert.go000066400000000000000000000176541504514340500170020ustar00rootroot00000000000000package manet import ( "errors" "fmt" "net" "path/filepath" "runtime" "strings" ma "github.com/multiformats/go-multiaddr" ) var errIncorrectNetAddr = fmt.Errorf("incorrect network addr conversion") var errNotIP = fmt.Errorf("multiaddr does not start with an IP address") // FromNetAddr converts a net.Addr type to a Multiaddr. func FromNetAddr(a net.Addr) (ma.Multiaddr, error) { return defaultCodecs.FromNetAddr(a) } // FromNetAddr converts a net.Addr to Multiaddress. func (cm *CodecMap) FromNetAddr(a net.Addr) (ma.Multiaddr, error) { if a == nil { return nil, fmt.Errorf("nil multiaddr") } p, err := cm.getAddrParser(a.Network()) if err != nil { return nil, err } return p(a) } // ToNetAddr converts a Multiaddr to a net.Addr // Must be ThinWaist. acceptable protocol stacks are: // /ip{4,6}/{tcp, udp} func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) { return defaultCodecs.ToNetAddr(maddr) } // ToNetAddr converts a Multiaddress to a standard net.Addr. func (cm *CodecMap) ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) { protos := maddr.Protocols() final := protos[len(protos)-1] p, err := cm.getMaddrParser(final.Name) if err != nil { return nil, err } 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 for _, c := range m { 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() } if ipString != "" && mask != "" { break } } 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 { return nil, err } switch network { case "tcp", "tcp4", "tcp6": return net.ResolveTCPAddr(network, host) case "udp", "udp4", "udp6": return net.ResolveUDPAddr(network, host) case "ip", "ip4", "ip6": return net.ResolveIPAddr(network, host) case "unix": return net.ResolveUnixAddr(network, host) } return nil, fmt.Errorf("network not supported: %s", network) } func FromIPAndZone(ip net.IP, zone string) (ma.Multiaddr, error) { switch { case ip.To4() != nil: c, err := ma.NewComponent("ip4", ip.String()) if err != nil { return nil, err } return c.Multiaddr(), nil case ip.To16() != nil: ip6C, err := ma.NewComponent("ip6", ip.String()) if err != nil { return nil, err } ip6 := ip6C.Multiaddr() if zone == "" { return ip6, nil } else { zone, err := ma.NewComponent("ip6zone", zone) if err != nil { return nil, err } return zone.Encapsulate(ip6), nil } default: return nil, errIncorrectNetAddr } } // FromIP converts a net.IP type to a Multiaddr. func FromIP(ip net.IP) (ma.Multiaddr, error) { return FromIPAndZone(ip, "") } // ToIP converts a Multiaddr to a net.IP when possible func ToIP(addr ma.Multiaddr) (net.IP, error) { var ip net.IP for _, c := range addr { switch c.Protocol().Code { case ma.P_IP6ZONE: // we can't return these anyways. continue case ma.P_IP6, ma.P_IP4: ip = net.IP(c.RawValue()) return ip, nil } return nil, errNotIP } return nil, errNotIP } // DialArgs is a convenience function that returns network and address as // expected by net.Dial. See https://godoc.org/net#Dial for an overview of // possible return values (we do not support the unixpacket ones yet). Unix // addresses do not, at present, compose. func DialArgs(m ma.Multiaddr) (string, string, error) { zone, network, ip, port, hostname, err := dialArgComponents(m) if err != nil { return "", "", err } // If we have a hostname (dns*), we don't want any fancy ipv6 formatting // logic (zone, brackets, etc.). if hostname { switch network { case "ip", "ip4", "ip6": return network, ip, nil case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6": return network, ip + ":" + port, nil } // Hostname is only true when network is one of the above. return "", "", errors.New("no hostname") // should be unreachable } switch network { case "ip6": if zone != "" { ip += "%" + zone } fallthrough case "ip4": return network, ip, nil case "tcp4", "udp4": return network, ip + ":" + port, nil case "tcp6", "udp6": if zone != "" { ip += "%" + zone } return network, "[" + ip + "]" + ":" + port, nil case "unix": if runtime.GOOS == "windows" { // convert /c:/... to c:\... ip = filepath.FromSlash(strings.TrimLeft(ip, "/")) } return network, ip, nil default: return "", "", fmt.Errorf("%s is not a 'thin waist' address", m) } } // dialArgComponents extracts the raw pieces used in dialing a Multiaddr func dialArgComponents(m ma.Multiaddr) (zone, network, ip, port string, hostname bool, err error) { for _, c := range m { switch network { case "": switch c.Protocol().Code { case ma.P_IP6ZONE: if zone != "" { err = fmt.Errorf("%s has multiple zones", m) return } zone = c.Value() continue case ma.P_IP6: network = "ip6" ip = c.Value() continue case ma.P_IP4: if zone != "" { err = fmt.Errorf("%s has ip4 with zone", m) return } network = "ip4" ip = c.Value() continue case ma.P_DNS: network = "ip" hostname = true ip = c.Value() continue case ma.P_DNS4: network = "ip4" hostname = true ip = c.Value() continue case ma.P_DNS6: network = "ip6" hostname = true ip = c.Value() continue case ma.P_UNIX: network = "unix" ip = c.Value() return } case "ip": switch c.Protocol().Code { case ma.P_UDP: network = "udp" case ma.P_TCP: network = "tcp" default: return } port = c.Value() case "ip4": switch c.Protocol().Code { case ma.P_UDP: network = "udp4" case ma.P_TCP: network = "tcp4" default: return } port = c.Value() case "ip6": switch c.Protocol().Code { case ma.P_UDP: network = "udp6" case ma.P_TCP: network = "tcp6" default: return } port = c.Value() } // Done. return } return } func parseTCPNetAddr(a net.Addr) (ma.Multiaddr, error) { ac, ok := a.(*net.TCPAddr) if !ok { return nil, errIncorrectNetAddr } // Get IP Addr ipm, err := FromIPAndZone(ac.IP, ac.Zone) if err != nil { return nil, errIncorrectNetAddr } // Get TCP Addr tcpm, err := ma.NewMultiaddr(fmt.Sprintf("/tcp/%d", ac.Port)) if err != nil { return nil, errIncorrectNetAddr } // Encapsulate return ipm.Encapsulate(tcpm), nil } func parseUDPNetAddr(a net.Addr) (ma.Multiaddr, error) { ac, ok := a.(*net.UDPAddr) if !ok { return nil, errIncorrectNetAddr } // Get IP Addr ipm, err := FromIPAndZone(ac.IP, ac.Zone) if err != nil { return nil, errIncorrectNetAddr } // Get UDP Addr udpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d", ac.Port)) if err != nil { return nil, errIncorrectNetAddr } // Encapsulate return ipm.Encapsulate(udpm), nil } func parseIPNetAddr(a net.Addr) (ma.Multiaddr, error) { ac, ok := a.(*net.IPAddr) if !ok { return nil, errIncorrectNetAddr } return FromIPAndZone(ac.IP, ac.Zone) } func parseIPPlusNetAddr(a net.Addr) (ma.Multiaddr, error) { ac, ok := a.(*net.IPNet) if !ok { return nil, errIncorrectNetAddr } return FromIP(ac.IP) } func parseUnixNetAddr(a net.Addr) (ma.Multiaddr, error) { ac, ok := a.(*net.UnixAddr) if !ok { return nil, errIncorrectNetAddr } path := ac.Name if runtime.GOOS == "windows" { // Convert c:\foobar\... to c:/foobar/... path = filepath.ToSlash(path) } if len(path) == 0 || path[0] != '/' { // convert "" and "c:/..." to "/..." path = "/" + path } c, err := ma.NewComponent("unix", path) if err != nil { return nil, err } return c.Multiaddr(), nil } go-multiaddr-0.16.1/net/convert_test.go000066400000000000000000000160341504514340500200300ustar00rootroot00000000000000package manet import ( "net" "runtime" "testing" ma "github.com/multiformats/go-multiaddr" ) type GenFunc func() (ma.Multiaddr, error) func testConvert(t *testing.T, s string, gen GenFunc) { m, err := gen() if err != nil { t.Fatal("failed to generate.") } if s2 := m.String(); err != nil || s2 != s { t.Fatal("failed to convert: " + s + " != " + s2) } } func testToNetAddr(t *testing.T, maddr, ntwk, addr string) { m, err := ma.NewMultiaddr(maddr) if err != nil { t.Fatal("failed to generate.") } naddr, err := ToNetAddr(m) if addr == "" { // should fail if err == nil { t.Fatalf("failed to error: %s", m) } return } // shouldn't fail if err != nil { t.Fatalf("failed to convert to net addr: %s", m) } if naddr.String() != addr { t.Fatalf("naddr.Address() == %s != %s", naddr, addr) } if naddr.Network() != ntwk { t.Fatalf("naddr.Network() == %s != %s", naddr.Network(), ntwk) } // should convert properly switch ntwk { case "tcp": taddr := naddr.(*net.TCPAddr) if ip, err := ToIP(m); err != nil || !taddr.IP.Equal(ip) { t.Fatalf("ToIP() and ToNetAddr diverged: %s != %s", taddr, ip) } case "udp": uaddr := naddr.(*net.UDPAddr) if ip, err := ToIP(m); err != nil || !uaddr.IP.Equal(ip) { t.Fatalf("ToIP() and ToNetAddr diverged: %s != %s", uaddr, ip) } case "ip": ipaddr := naddr.(*net.IPAddr) if ip, err := ToIP(m); err != nil || !ipaddr.IP.Equal(ip) { t.Fatalf("ToIP() and ToNetAddr diverged: %s != %s", ipaddr, ip) } } } func TestFromIP4(t *testing.T) { testConvert(t, "/ip4/10.20.30.40", func() (ma.Multiaddr, error) { return FromNetAddr(&net.IPAddr{IP: net.ParseIP("10.20.30.40")}) }) } func TestFromUnix(t *testing.T) { path := "/C:/foo/bar" if runtime.GOOS == "windows" { path = `C:\foo\bar` } testConvert(t, "/unix/C:/foo/bar", func() (ma.Multiaddr, error) { return FromNetAddr(&net.UnixAddr{Name: path, Net: "unix"}) }) } func TestToUnix(t *testing.T) { path := "/C:/foo/bar" if runtime.GOOS == "windows" { path = `C:\foo\bar` } testToNetAddr(t, "/unix/C:/foo/bar", "unix", path) } func TestFromIP6(t *testing.T) { testConvert(t, "/ip6/2001:4860:0:2001::68", func() (ma.Multiaddr, error) { return FromNetAddr(&net.IPAddr{IP: net.ParseIP("2001:4860:0:2001::68")}) }) } func TestFromTCP(t *testing.T) { testConvert(t, "/ip4/10.20.30.40/tcp/1234", func() (ma.Multiaddr, error) { return FromNetAddr(&net.TCPAddr{ IP: net.ParseIP("10.20.30.40"), Port: 1234, }) }) } func TestFromUDP(t *testing.T) { testConvert(t, "/ip4/10.20.30.40/udp/1234", func() (ma.Multiaddr, error) { return FromNetAddr(&net.UDPAddr{ IP: net.ParseIP("10.20.30.40"), Port: 1234, }) }) } func TestThinWaist(t *testing.T) { addrs := map[string]bool{ "/ip4/127.0.0.1/udp/1234": true, "/ip4/127.0.0.1/tcp/1234": true, "/ip4/127.0.0.1/udp/1234/tcp/1234": true, "/ip4/127.0.0.1/tcp/12345/ip4/1.2.3.4": true, "/ip6/::1/tcp/80": true, "/ip6/::1/udp/80": true, "/ip6/::1": true, "/ip6zone/hello/ip6/fe80::1/tcp/80": true, "/ip6zone/hello/ip6/fe80::1": true, "/tcp/1234/ip4/1.2.3.4": false, "/tcp/1234": false, "/tcp/1234/udp/1234": false, "/ip4/1.2.3.4/ip4/2.3.4.5": true, "/ip6/fe80::1/ip4/2.3.4.5": true, "/ip6zone/hello/ip6/fe80::1/ip4/2.3.4.5": true, // Invalid ip6zone usage: "/ip6zone/hello": false, "/ip6zone/hello/ip4/1.1.1.1": false, } for a, res := range addrs { m, err := ma.NewMultiaddr(a) if err != nil { t.Fatalf("failed to construct Multiaddr: %s", a) } if IsThinWaist(m) != res { t.Fatalf("IsThinWaist(%s) != %v", a, res) } } } func TestDialArgs(t *testing.T) { test := func(e_maddr, e_nw, e_host string) { m, err := ma.NewMultiaddr(e_maddr) if err != nil { t.Fatal("failed to construct", e_maddr) } nw, host, err := DialArgs(m) if err != nil { t.Fatal("failed to get dial args", e_maddr, m, err) } if nw != e_nw { t.Error("failed to get udp network Dial Arg", e_nw, nw) } if host != e_host { t.Error("failed to get host:port Dial Arg", e_host, host) } } test_error := func(e_maddr string) { m, err := ma.NewMultiaddr(e_maddr) if err != nil { t.Fatal("failed to construct", e_maddr) } _, _, err = DialArgs(m) if err == nil { t.Fatal("expected DialArgs to fail on", e_maddr) } } test("/ip4/127.0.0.1/udp/1234", "udp4", "127.0.0.1:1234") test("/ip4/127.0.0.1/tcp/4321", "tcp4", "127.0.0.1:4321") test("/ip6/::1/udp/1234", "udp6", "[::1]:1234") test("/ip6/::1/tcp/4321", "tcp6", "[::1]:4321") test("/ip6/::1", "ip6", "::1") // Just an IP test("/ip4/1.2.3.4", "ip4", "1.2.3.4") // Just an IP test("/ip6zone/foo/ip6/::1/tcp/4321", "tcp6", "[::1%foo]:4321") // zone test("/ip6zone/foo/ip6/::1/udp/4321", "udp6", "[::1%foo]:4321") // zone test("/ip6zone/foo/ip6/::1", "ip6", "::1%foo") // no TCP test_error("/ip6zone/foo/ip4/127.0.0.1") // IP4 doesn't take zone test("/ip6zone/foo/ip6/::1/ip6zone/bar", "ip6", "::1%foo") // IP over IP test_error("/ip6zone/foo/ip6zone/bar/ip6/::1") // Only one zone per IP6 test("/dns/abc.com/tcp/1234", "tcp", "abc.com:1234") // DNS4:port test("/dns4/abc.com/tcp/1234", "tcp4", "abc.com:1234") // DNS4:port test("/dns4/abc.com", "ip4", "abc.com") // Just DNS4 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) } }) } } go-multiaddr-0.16.1/net/doc.go000066400000000000000000000003541504514340500160540ustar00rootroot00000000000000// Package manet provides Multiaddr specific versions of common // functions in stdlib's net package. This means wrappers of // standard net symbols like net.Dial and net.Listen, as well // as conversion to/from net.Addr. package manet go-multiaddr-0.16.1/net/ip.go000066400000000000000000000064121504514340500157200ustar00rootroot00000000000000package manet import ( "net" ma "github.com/multiformats/go-multiaddr" ) // Loopback Addresses var ( // IP4Loopback is the ip4 loopback multiaddr IP4Loopback = ma.StringCast("/ip4/127.0.0.1") // IP6Loopback is the ip6 loopback multiaddr IP6Loopback = ma.StringCast("/ip6/::1") // IP4MappedIP6Loopback is the IPv4 Mapped IPv6 loopback address. IP4MappedIP6Loopback = ma.StringCast("/ip6/::ffff:127.0.0.1") ) // Unspecified Addresses (used for ) var ( IP4Unspecified = ma.StringCast("/ip4/0.0.0.0") IP6Unspecified = ma.StringCast("/ip6/::") ) // IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols. // This means: /{IP4, IP6}[/{TCP, UDP}] func IsThinWaist(m ma.Multiaddr) bool { m = zoneless(m) if m == nil { return false } p := m.Protocols() // nothing? not even a waist. if len(p) == 0 { return false } if p[0].Code != ma.P_IP4 && p[0].Code != ma.P_IP6 { return false } // only IP? still counts. if len(p) == 1 { return true } switch p[1].Code { case ma.P_TCP, ma.P_UDP, ma.P_IP4, ma.P_IP6: return true default: return false } } // IsIPLoopback returns whether a Multiaddr starts with a "Loopback" IP address // This means either /ip4/127.*.*.*/*, /ip6/::1/*, or /ip6/::ffff:127.*.*.*.*/*, // or /ip6zone//ip6//* func IsIPLoopback(m ma.Multiaddr) bool { m = zoneless(m) if m == nil { return false } head, _ := splitFirstSlice(m) if len(head) == 0 { return false } switch head[0].Code() { case ma.P_IP4, ma.P_IP6: return net.IP(head[0].RawValue()).IsLoopback() } return false } // IsIP6LinkLocal returns whether a Multiaddr starts with an IPv6 link-local // multiaddress (with zero or one leading zone). These addresses are non // routable. func IsIP6LinkLocal(m ma.Multiaddr) bool { m = zoneless(m) if m == nil { return false } head, _ := splitFirstSlice(m) if len(head) == 0 || head[0].Code() != ma.P_IP6 { return false } ip := net.IP(head[0].RawValue()) return ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() } // IsIPUnspecified returns whether a Multiaddr starts with an Unspecified IP address // This means either /ip4/0.0.0.0/* or /ip6/::/* func IsIPUnspecified(m ma.Multiaddr) bool { m = zoneless(m) if len(m) == 0 { return false } head, _ := splitFirstSlice(m) if len(head) == 0 { return false } return net.IP(head[0].RawValue()).IsUnspecified() } func splitFirstSlice(m ma.Multiaddr) (ma.Multiaddr, ma.Multiaddr) { switch len(m) { case 0: return nil, nil case 1: return m, nil default: return m[:1], m[1:] } } // If m matches [zone,ip6,...], return [ip6,...] // else if m matches [], [zone], or [zone,...], return nil // else return m func zoneless(m ma.Multiaddr) ma.Multiaddr { head, tail := splitFirstSlice(m) if len(head) == 0 { return nil } if head[0].Code() == ma.P_IP6ZONE { if len(tail) == 0 { return nil } if tail[0].Code() != ma.P_IP6 { return nil } return tail } else { return m } } // IsNAT64IPv4ConvertedIPv6Addr returns whether addr is a well-known prefix "64:ff9b::/96" addr // used for NAT64 Translation. See RFC 6052 func IsNAT64IPv4ConvertedIPv6Addr(addr ma.Multiaddr) bool { head, _ := splitFirstSlice(addr) return len(head) > 0 && head[0].Code() == ma.P_IP6 && inAddrRange(head[0].RawValue(), nat64) } go-multiaddr-0.16.1/net/ip_test.go000066400000000000000000000026001504514340500167520ustar00rootroot00000000000000package manet import ( "fmt" "testing" ma "github.com/multiformats/go-multiaddr" ) func TestIsWellKnownPrefixIPv4ConvertedIPv6Address(t *testing.T) { cases := []struct { addr ma.Multiaddr want bool failureReason string }{ { addr: ma.StringCast("/ip4/1.2.3.4/tcp/1234"), want: false, failureReason: "ip4 addresses should return false", }, { addr: ma.StringCast("/ip6/1::4/tcp/1234"), want: false, failureReason: "ip6 addresses doesn't have well-known prefix", }, { addr: ma.StringCast("/ip6/::1/tcp/1234"), want: false, failureReason: "localhost addresses should return false", }, { addr: ma.StringCast("/ip6/64:ff9b::192.0.1.2/tcp/1234"), want: true, failureReason: "ip6 address begins with well-known prefix", }, { addr: ma.StringCast("/ip6/64:ff9b::1:192.0.1.2/tcp/1234"), want: false, failureReason: "64:ff9b::1 is not well-known prefix", }, { addr: ma.StringCast("/ip6/64:ff9b:1::1:192.0.1.2/tcp/1234"), want: true, failureReason: "64:ff9b:1::1 is allowed for NAT64 translation", }, } for i, tc := range cases { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { if IsNAT64IPv4ConvertedIPv6Addr(tc.addr) != tc.want { t.Fatalf("%s %s", tc.addr, tc.failureReason) } }) } } go-multiaddr-0.16.1/net/net.go000066400000000000000000000262361504514340500161040ustar00rootroot00000000000000// Package manet provides Multiaddr // (https://github.com/multiformats/go-multiaddr) specific versions of common // functions in Go's standard `net` package. This means wrappers of standard // net symbols like `net.Dial` and `net.Listen`, as well as conversion to // and from `net.Addr`. package manet import ( "context" "fmt" "net" ma "github.com/multiformats/go-multiaddr" ) // Conn is the equivalent of a net.Conn object. It is the // result of calling the Dial or Listen functions in this // package, with associated local and remote Multiaddrs. type Conn interface { net.Conn // LocalMultiaddr returns the local Multiaddr associated // with this connection LocalMultiaddr() ma.Multiaddr // RemoteMultiaddr returns the remote Multiaddr associated // with this connection RemoteMultiaddr() ma.Multiaddr } type halfOpen interface { net.Conn CloseRead() error CloseWrite() error } func wrap(nconn net.Conn, laddr, raddr ma.Multiaddr) Conn { endpts := maEndpoints{ laddr: laddr, raddr: raddr, } // This sucks. However, it's the only way to reliably expose the // underlying methods. This way, users that need access to, e.g., // CloseRead and CloseWrite, can do so via type assertions. switch nconn := nconn.(type) { case *net.TCPConn: return &struct { *net.TCPConn maEndpoints }{nconn, endpts} case *net.UDPConn: return &struct { *net.UDPConn maEndpoints }{nconn, endpts} case *net.IPConn: return &struct { *net.IPConn maEndpoints }{nconn, endpts} case *net.UnixConn: return &struct { *net.UnixConn maEndpoints }{nconn, endpts} case halfOpen: return &struct { halfOpen maEndpoints }{nconn, endpts} default: return &struct { net.Conn maEndpoints }{nconn, endpts} } } // WrapNetConn wraps a net.Conn object with a Multiaddr friendly Conn. // // This function does it's best to avoid "hiding" methods exposed by the wrapped // type. Guarantees: // // - If the wrapped connection exposes the "half-open" closer methods // (CloseWrite, CloseRead), these will be available on the wrapped connection // via type assertions. // - If the wrapped connection is a UnixConn, IPConn, TCPConn, or UDPConn, all // methods on these wrapped connections will be available via type assertions. func WrapNetConn(nconn net.Conn) (Conn, error) { if nconn == nil { return nil, fmt.Errorf("failed to convert nconn.LocalAddr: nil") } laddr, err := FromNetAddr(nconn.LocalAddr()) if err != nil { return nil, fmt.Errorf("failed to convert nconn.LocalAddr: %s", err) } raddr, err := FromNetAddr(nconn.RemoteAddr()) if err != nil { return nil, fmt.Errorf("failed to convert nconn.RemoteAddr: %s", err) } return wrap(nconn, laddr, raddr), nil } type maEndpoints struct { laddr ma.Multiaddr raddr ma.Multiaddr } // LocalMultiaddr returns the local address associated with // this connection func (c *maEndpoints) LocalMultiaddr() ma.Multiaddr { return c.laddr } // RemoteMultiaddr returns the remote address associated with // this connection func (c *maEndpoints) RemoteMultiaddr() ma.Multiaddr { return c.raddr } // Dialer contains options for connecting to an address. It // is effectively the same as net.Dialer, but its LocalAddr // and RemoteAddr options are Multiaddrs, instead of net.Addrs. type Dialer struct { // Dialer is just an embedded net.Dialer, with all its options. net.Dialer // LocalAddr is the local address to use when dialing an // address. The address must be of a compatible type for the // network being dialed. // If nil, a local address is automatically chosen. LocalAddr ma.Multiaddr } // Dial connects to a remote address, using the options of the // Dialer. Dialer uses an underlying net.Dialer to Dial a // net.Conn, then wraps that in a Conn object (with local and // remote Multiaddrs). func (d *Dialer) Dial(remote ma.Multiaddr) (Conn, error) { return d.DialContext(context.Background(), remote) } // DialContext allows to provide a custom context to Dial(). func (d *Dialer) DialContext(ctx context.Context, remote ma.Multiaddr) (Conn, error) { // if a LocalAddr is specified, use it on the embedded dialer. if d.LocalAddr != nil { // convert our multiaddr to net.Addr friendly naddr, err := ToNetAddr(d.LocalAddr) if err != nil { return nil, err } // set the dialer's LocalAddr as naddr d.Dialer.LocalAddr = naddr } // get the net.Dial friendly arguments from the remote addr rnet, rnaddr, err := DialArgs(remote) if err != nil { return nil, err } // ok, Dial! var nconn net.Conn switch rnet { case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "unix": nconn, err = d.Dialer.DialContext(ctx, rnet, rnaddr) if err != nil { return nil, err } default: return nil, fmt.Errorf("unrecognized network: %s", rnet) } // get local address (pre-specified or assigned within net.Conn) local := d.LocalAddr // This block helps us avoid parsing addresses in transports (such as unix // sockets) that don't have local addresses when dialing out. if local == nil && nconn.LocalAddr().String() != "" { local, err = FromNetAddr(nconn.LocalAddr()) if err != nil { return nil, err } } return wrap(nconn, local, remote), nil } // Dial connects to a remote address. It uses an underlying net.Conn, // then wraps it in a Conn object (with local and remote Multiaddrs). func Dial(remote ma.Multiaddr) (Conn, error) { return (&Dialer{}).Dial(remote) } // A Listener is a generic network listener for stream-oriented protocols. // it uses an embedded net.Listener, overriding net.Listener.Accept to // return a Conn and providing Multiaddr. type Listener interface { // Accept waits for and returns the next connection to the listener. // Returns a Multiaddr friendly Conn Accept() (Conn, error) // Close closes the listener. // Any blocked Accept operations will be unblocked and return errors. Close() error // Multiaddr returns the listener's (local) Multiaddr. Multiaddr() ma.Multiaddr // Addr returns the net.Listener's network address. Addr() net.Addr } type netListenerAdapter struct { Listener } func (nla *netListenerAdapter) Accept() (net.Conn, error) { return nla.Listener.Accept() } // NetListener turns this Listener into a net.Listener. // // - Connections returned from Accept implement multiaddr/net Conn. // - Calling WrapNetListener on the net.Listener returned by this function will // return the original (underlying) multiaddr/net Listener. func NetListener(l Listener) net.Listener { return &netListenerAdapter{l} } // maListener implements Listener type maListener struct { net.Listener laddr ma.Multiaddr } // Accept waits for and returns the next connection to the listener. // Returns a Multiaddr friendly Conn func (l *maListener) Accept() (Conn, error) { nconn, err := l.Listener.Accept() if err != nil { return nil, err } var raddr ma.Multiaddr // This block protects us in transports (i.e. unix sockets) that don't have // remote addresses for inbound connections. if addr := nconn.RemoteAddr(); addr != nil && addr.String() != "" { raddr, err = FromNetAddr(addr) if err != nil { return nil, fmt.Errorf("failed to convert conn.RemoteAddr: %s", err) } } var laddr ma.Multiaddr if addr := nconn.LocalAddr(); addr != nil && addr.String() != "" { laddr, err = FromNetAddr(addr) if err != nil { return nil, fmt.Errorf("failed to convert conn.LocalAddr: %s", err) } } return wrap(nconn, laddr, raddr), nil } // Multiaddr returns the listener's (local) Multiaddr. func (l *maListener) Multiaddr() ma.Multiaddr { return l.laddr } // Addr returns the listener's network address. func (l *maListener) Addr() net.Addr { return l.Listener.Addr() } // Listen announces on the local network address laddr. // The Multiaddr must be a "ThinWaist" stream-oriented network: // ip4/tcp, ip6/tcp, (TODO: unix, unixpacket) // See Dial for the syntax of laddr. func Listen(laddr ma.Multiaddr) (Listener, error) { // get the net.Listen friendly arguments from the remote addr lnet, lnaddr, err := DialArgs(laddr) if err != nil { return nil, err } nl, err := net.Listen(lnet, lnaddr) if err != nil { return nil, err } // we want to fetch the new multiaddr from the listener, as it may // have resolved to some other value. WrapNetListener does it for us. return WrapNetListener(nl) } // WrapNetListener wraps a net.Listener with a manet.Listener. func WrapNetListener(nl net.Listener) (Listener, error) { if nla, ok := nl.(*netListenerAdapter); ok { return nla.Listener, nil } laddr, err := FromNetAddr(nl.Addr()) if err != nil { return nil, err } return &maListener{ Listener: nl, laddr: laddr, }, nil } // A PacketConn is a generic packet oriented network connection which uses an // underlying net.PacketConn, wrapped with the locally bound Multiaddr. type PacketConn interface { net.PacketConn LocalMultiaddr() ma.Multiaddr ReadFromMultiaddr(b []byte) (int, ma.Multiaddr, error) WriteToMultiaddr(b []byte, maddr ma.Multiaddr) (int, error) } // maPacketConn implements PacketConn type maPacketConn struct { net.PacketConn laddr ma.Multiaddr } var _ PacketConn = (*maPacketConn)(nil) // LocalMultiaddr returns the bound local Multiaddr. func (l *maPacketConn) LocalMultiaddr() ma.Multiaddr { return l.laddr } func (l *maPacketConn) ReadFromMultiaddr(b []byte) (int, ma.Multiaddr, error) { n, addr, err := l.ReadFrom(b) maddr, _ := FromNetAddr(addr) return n, maddr, err } func (l *maPacketConn) WriteToMultiaddr(b []byte, maddr ma.Multiaddr) (int, error) { addr, err := ToNetAddr(maddr) if err != nil { return 0, err } return l.WriteTo(b, addr) } // ListenPacket announces on the local network address laddr. // The Multiaddr must be a packet driven network, like udp4 or udp6. // See Dial for the syntax of laddr. func ListenPacket(laddr ma.Multiaddr) (PacketConn, error) { lnet, lnaddr, err := DialArgs(laddr) if err != nil { return nil, err } pc, err := net.ListenPacket(lnet, lnaddr) if err != nil { return nil, err } // We want to fetch the new multiaddr from the listener, as it may // have resolved to some other value. WrapPacketConn does this. return WrapPacketConn(pc) } // WrapPacketConn wraps a net.PacketConn with a manet.PacketConn. func WrapPacketConn(pc net.PacketConn) (PacketConn, error) { laddr, err := FromNetAddr(pc.LocalAddr()) if err != nil { return nil, err } return &maPacketConn{ PacketConn: pc, laddr: laddr, }, nil } // InterfaceMultiaddrs will return the addresses matching net.InterfaceAddrs func InterfaceMultiaddrs() ([]ma.Multiaddr, error) { addrs, err := net.InterfaceAddrs() if err != nil { return nil, err } maddrs := make([]ma.Multiaddr, len(addrs)) for i, a := range addrs { maddrs[i], err = FromNetAddr(a) if err != nil { return nil, err } } return maddrs, nil } // AddrMatch returns the Multiaddrs that match the protocol stack on addr func AddrMatch(match ma.Multiaddr, addrs []ma.Multiaddr) []ma.Multiaddr { // we should match transports entirely. p1s := match.Protocols() out := make([]ma.Multiaddr, 0, len(addrs)) for _, a := range addrs { p2s := a.Protocols() if len(p1s) != len(p2s) { continue } match := true for i, p2 := range p2s { if p1s[i].Code != p2.Code { match = false break } } if match { out = append(out, a) } } return out } go-multiaddr-0.16.1/net/net_test.go000066400000000000000000000372121504514340500171370ustar00rootroot00000000000000package manet import ( "bytes" "fmt" "net" "os" "path/filepath" "sync" "testing" "time" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" ) func newMultiaddr(t *testing.T, m string) ma.Multiaddr { maddr, err := ma.NewMultiaddr(m) if err != nil { t.Fatal("failed to construct multiaddr:", m, err) } return maddr } func TestDial(t *testing.T) { listener, err := net.Listen("tcp", "127.0.0.1:4321") if err != nil { t.Fatal("failed to listen") } var wg sync.WaitGroup wg.Add(1) go func() { cB, err := listener.Accept() if err != nil { t.Error("failed to accept") } // echo out buf := make([]byte, 1024) for { _, err := cB.Read(buf) if err != nil { break } cB.Write(buf) } wg.Done() }() maddr := newMultiaddr(t, "/ip4/127.0.0.1/tcp/4321") cA, err := Dial(maddr) if err != nil { t.Fatal("failed to dial") } buf := make([]byte, 1024) if _, err := cA.Write([]byte("beep boop")); err != nil { t.Fatal("failed to write:", err) } if _, err := cA.Read(buf); err != nil { t.Fatal("failed to read:", buf, err) } if !bytes.Equal(buf[:9], []byte("beep boop")) { t.Fatal("failed to echo:", buf) } maddr2 := cA.RemoteMultiaddr() if !maddr2.Equal(maddr) { t.Fatal("remote multiaddr not equal:", maddr, maddr2) } cA.Close() wg.Wait() } func TestUnixSockets(t *testing.T) { dir, err := os.MkdirTemp(os.TempDir(), "manettest") if err != nil { t.Fatal(err) } path := filepath.Join(dir, "listen.sock") maddr := newMultiaddr(t, "/unix/"+path) listener, err := Listen(maddr) if err != nil { t.Fatal(err) } payload := []byte("hello") // listen done := make(chan struct{}, 1) go func() { conn, err := listener.Accept() if err != nil { t.Error(err) } defer conn.Close() buf := make([]byte, 1024) n, err := conn.Read(buf) if err != nil { t.Error(err) } if n != len(payload) { t.Error("failed to read appropriate number of bytes") } if !bytes.Equal(buf[0:n], payload) { t.Error("payload did not match") } done <- struct{}{} }() // dial conn, err := Dial(maddr) if err != nil { t.Fatal(err) } n, err := conn.Write(payload) if err != nil { t.Fatal(err) } if n != len(payload) { t.Fatal("failed to write appropriate number of bytes") } select { case <-done: case <-time.After(1 * time.Second): t.Fatal("timed out waiting for read") } } func TestListen(t *testing.T) { maddr := newMultiaddr(t, "/ip4/127.0.0.1/tcp/4322") listener, err := Listen(maddr) if err != nil { t.Fatal("failed to listen") } var wg sync.WaitGroup wg.Add(1) go func() { cB, err := listener.Accept() if err != nil { t.Error("failed to accept") } if !cB.LocalMultiaddr().Equal(maddr) { t.Error("local multiaddr not equal:", maddr, cB.LocalMultiaddr()) } // echo out buf := make([]byte, 1024) for { _, err := cB.Read(buf) if err != nil { break } cB.Write(buf) } wg.Done() }() cA, err := net.Dial("tcp", "127.0.0.1:4322") if err != nil { t.Fatal("failed to dial") } buf := make([]byte, 1024) if _, err := cA.Write([]byte("beep boop")); err != nil { t.Fatal("failed to write:", err) } if _, err := cA.Read(buf); err != nil { t.Fatal("failed to read:", buf, err) } if !bytes.Equal(buf[:9], []byte("beep boop")) { t.Fatal("failed to echo:", buf) } maddr2, err := FromNetAddr(cA.RemoteAddr()) if err != nil { t.Fatal("failed to convert", err) } if !maddr2.Equal(maddr) { t.Fatal("remote multiaddr not equal:", maddr, maddr2) } cA.Close() wg.Wait() } func TestListenAddrs(t *testing.T) { test := func(addr, resaddr string, succeed bool) { if resaddr == "" { resaddr = addr } maddr := newMultiaddr(t, addr) l, err := Listen(maddr) if !succeed { if err == nil { t.Fatal("succeeded in listening", addr) } return } if succeed && err != nil { t.Error("failed to listen", addr, err) } if l == nil { t.Error("failed to listen", addr, succeed, err) } if l.Multiaddr().String() != resaddr { t.Error("listen addr did not resolve properly", l.Multiaddr().String(), resaddr, succeed, err) } if err = l.Close(); err != nil { t.Fatal("failed to close listener", addr, err) } } test("/ip4/127.0.0.1/tcp/4324", "", true) test("/ip4/127.0.0.1/udp/4325", "", false) test("/ip4/127.0.0.1/udp/4326/udt", "", false) if len(os.Getenv("CI")) > 0 { test("/ip4/0.0.0.0/tcp/4324", "", true) test("/ip4/0.0.0.0/udp/4325", "", false) test("/ip4/0.0.0.0/udp/4326/udt", "", false) test("/ip6/::1/tcp/4324", "", true) test("/ip6/::1/udp/4325", "", false) test("/ip6/::1/udp/4326/udt", "", false) test("/ip6/::/tcp/4324", "", true) test("/ip6/::/udp/4325", "", false) test("/ip6/::/udp/4326/udt", "", false) /* "An implementation should also support the concept of a "default" * zone for each scope. And, when supported, the index value zero * at each scope SHOULD be reserved to mean "use the default zone"." * -- rfc4007. So, this _should_ work everywhere(?). */ test("/ip6zone/0/ip6/::1/tcp/4324", "/ip6/::1/tcp/4324", true) test("/ip6zone/0/ip6/::1/udp/4324", "", false) } else { t.Skip("all tests only run on CI") } } func TestListenAndDial(t *testing.T) { maddr := newMultiaddr(t, "/ip4/127.0.0.1/tcp/4323") listener, err := Listen(maddr) if err != nil { t.Fatal("failed to listen") } var wg sync.WaitGroup wg.Add(1) go func() { cB, err := listener.Accept() if err != nil { t.Error("failed to accept") } if !cB.LocalMultiaddr().Equal(maddr) { t.Error("local multiaddr not equal:", maddr, cB.LocalMultiaddr()) } // echo out buf := make([]byte, 1024) for { _, err := cB.Read(buf) if err != nil { break } cB.Write(buf) } wg.Done() }() cA, err := Dial(newMultiaddr(t, "/ip4/127.0.0.1/tcp/4323")) if err != nil { t.Fatal("failed to dial") } buf := make([]byte, 1024) if _, err := cA.Write([]byte("beep boop")); err != nil { t.Fatal("failed to write:", err) } if _, err := cA.Read(buf); err != nil { t.Fatal("failed to read:", buf, err) } if !bytes.Equal(buf[:9], []byte("beep boop")) { t.Fatal("failed to echo:", buf) } maddr2 := cA.RemoteMultiaddr() if !maddr2.Equal(maddr) { t.Fatal("remote multiaddr not equal:", maddr, maddr2) } cA.Close() wg.Wait() } func TestListenPacketAndDial(t *testing.T) { maddr := newMultiaddr(t, "/ip4/127.0.0.1/udp/4324") pc, err := ListenPacket(maddr) if err != nil { t.Fatal("failed to listen", err) } var wg sync.WaitGroup wg.Add(1) go func() { if !pc.LocalMultiaddr().Equal(maddr) { t.Error("connection multiaddr not equal:", maddr, pc.LocalMultiaddr()) } buffer := make([]byte, 1024) _, addr, err := pc.ReadFrom(buffer) if err != nil { t.Error("failed to read into buffer", err) } pc.WriteTo(buffer, addr) wg.Done() }() cn, err := Dial(maddr) if err != nil { t.Fatal("failed to dial", err) } buf := make([]byte, 1024) if _, err := cn.Write([]byte("beep boop")); err != nil { t.Fatal("failed to write", err) } if _, err := cn.Read(buf); err != nil { t.Fatal("failed to read:", buf, err) } if !bytes.Equal(buf[:9], []byte("beep boop")) { t.Fatal("failed to echk:", buf) } maddr2 := cn.RemoteMultiaddr() if !maddr2.Equal(maddr) { t.Fatal("remote multiaddr not equal:", maddr, maddr2) } cn.Close() pc.Close() wg.Wait() } func TestIPLoopback(t *testing.T) { if IP4Loopback.String() != "/ip4/127.0.0.1" { t.Error("IP4Loopback incorrect:", IP4Loopback) } if IP6Loopback.String() != "/ip6/::1" { t.Error("IP6Loopback incorrect:", IP6Loopback) } if IP4MappedIP6Loopback.String() != "/ip6/::ffff:127.0.0.1" { t.Error("IP4MappedIP6Loopback incorrect:", IP4MappedIP6Loopback) } if !IsIPLoopback(IP4Loopback) { t.Error("IsIPLoopback failed (IP4Loopback)") } if !IsIPLoopback(newMultiaddr(t, "/ip4/127.1.80.9")) { t.Error("IsIPLoopback failed (/ip4/127.1.80.9)") } if IsIPLoopback(newMultiaddr(t, "/ip4/112.123.11.1")) { t.Error("IsIPLoopback false positive (/ip4/112.123.11.1)") } if IsIPLoopback(newMultiaddr(t, "/ip4/192.168.0.1/ip6/::1")) { t.Error("IsIPLoopback false positive (/ip4/192.168.0.1/ip6/::1)") } if !IsIPLoopback(IP6Loopback) { t.Error("IsIPLoopback failed (IP6Loopback)") } if !IsIPLoopback(newMultiaddr(t, "/ip6/127.0.0.1")) { t.Error("IsIPLoopback failed (/ip6/127.0.0.1)") } if !IsIPLoopback(newMultiaddr(t, "/ip6/127.99.3.2")) { t.Error("IsIPLoopback failed (/ip6/127.99.3.2)") } if IsIPLoopback(newMultiaddr(t, "/ip6/::fffa:127.99.3.2")) { t.Error("IsIPLoopback false positive (/ip6/::fffa:127.99.3.2)") } if !IsIPLoopback(newMultiaddr(t, "/ip6zone/0/ip6/::1")) { t.Error("IsIPLoopback failed (/ip6zone/0/ip6/::1)") } if !IsIPLoopback(newMultiaddr(t, "/ip6zone/xxx/ip6/::1")) { t.Error("IsIPLoopback failed (/ip6zone/xxx/ip6/::1)") } if IsIPLoopback(newMultiaddr(t, "/ip6zone/0/ip6/1::1")) { t.Errorf("IsIPLoopback false positive (/ip6zone/0/ip6/1::1)") } } func TestIPUnspecified(t *testing.T) { if IP4Unspecified.String() != "/ip4/0.0.0.0" { t.Error("IP4Unspecified incorrect:", IP4Unspecified) } if IP6Unspecified.String() != "/ip6/::" { t.Error("IP6Unspecified incorrect:", IP6Unspecified) } if !IsIPUnspecified(IP4Unspecified) { t.Error("IsIPUnspecified failed (IP4Unspecified)") } if !IsIPUnspecified(IP6Unspecified) { t.Error("IsIPUnspecified failed (IP6Unspecified)") } if !IsIPUnspecified(newMultiaddr(t, "/ip6zone/xxx/ip6/::")) { t.Error("IsIPUnspecified failed (/ip6zone/xxx/ip6/::)") } } func TestIP6LinkLocal(t *testing.T) { for a := 0; a < 65536; a++ { isLinkLocal := a&0xffc0 == 0xfe80 || a&0xff0f == 0xff02 m := newMultiaddr(t, fmt.Sprintf("/ip6/%x::1", a)) if IsIP6LinkLocal(m) != isLinkLocal { t.Errorf("IsIP6LinkLocal failed (%s != %v)", m, isLinkLocal) } } if !IsIP6LinkLocal(newMultiaddr(t, "/ip6zone/hello/ip6/fe80::9999")) { t.Error("IsIP6LinkLocal failed (/ip6/fe80::9999)") } bad := []ma.Multiaddr{ newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), // link local newMultiaddr(t, "/ip6/fe80::100/tcp/1234"), // link local } good := []ma.Multiaddr{ newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), newMultiaddr(t, "/ip6/::1/tcp/1234"), newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/utp"), } for _, addr := range bad { require.True(t, IsIP6LinkLocal(addr), "%s is a link local addr", addr) } for _, addr := range good { require.False(t, IsIP6LinkLocal(addr), "%s is not a link local addr", addr) } } func TestConvertNetAddr(t *testing.T) { m1 := newMultiaddr(t, "/ip4/1.2.3.4/tcp/4001") n1, err := ToNetAddr(m1) if err != nil { t.Fatal(err) } m2, err := FromNetAddr(n1) if err != nil { t.Fatal(err) } if m1.String() != m2.String() { t.Fatal("ToNetAddr + FromNetAddr did not work") } } func TestWrapNetConn(t *testing.T) { // test WrapNetConn nil if _, err := WrapNetConn(nil); err == nil { t.Error("WrapNetConn(nil) should return an error") } checkErr := func(err error, s string) { if err != nil { t.Fatal(s, err) } } listener, err := net.Listen("tcp", "127.0.0.1:0") checkErr(err, "failed to listen") var wg sync.WaitGroup defer wg.Wait() wg.Add(1) go func() { defer wg.Done() cB, err := listener.Accept() checkErr(err, "failed to accept") _ = cB.(halfOpen) cB.Close() }() cA, err := net.Dial("tcp", listener.Addr().String()) checkErr(err, "failed to dial") defer cA.Close() _ = cA.(halfOpen) lmaddr, err := FromNetAddr(cA.LocalAddr()) checkErr(err, "failed to get local addr") rmaddr, err := FromNetAddr(cA.RemoteAddr()) checkErr(err, "failed to get remote addr") mcA, err := WrapNetConn(cA) checkErr(err, "failed to wrap conn") _ = mcA.(halfOpen) if mcA.LocalAddr().String() != cA.LocalAddr().String() { t.Error("wrapped conn local addr differs") } if mcA.RemoteAddr().String() != cA.RemoteAddr().String() { t.Error("wrapped conn remote addr differs") } if mcA.LocalMultiaddr().String() != lmaddr.String() { t.Error("wrapped conn local maddr differs") } if mcA.RemoteMultiaddr().String() != rmaddr.String() { t.Error("wrapped conn remote maddr differs") } } func TestAddrMatch(t *testing.T) { test := func(m ma.Multiaddr, input, expect []ma.Multiaddr) { actual := AddrMatch(m, input) testSliceEqual(t, expect, actual) } a := []ma.Multiaddr{ newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/2345"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"), newMultiaddr(t, "/ip6/::1/tcp/1234"), newMultiaddr(t, "/ip6/::1/tcp/2345"), newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"), newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"), newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"), newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"), newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"), newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"), } test(a[0], a, []ma.Multiaddr{ newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/2345"), }) test(a[2], a, []ma.Multiaddr{ newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"), }) test(a[4], a, []ma.Multiaddr{ newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"), }) test(a[6], a, []ma.Multiaddr{ newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"), }) test(a[8], a, []ma.Multiaddr{ newMultiaddr(t, "/ip6/::1/tcp/1234"), newMultiaddr(t, "/ip6/::1/tcp/2345"), }) test(a[10], a, []ma.Multiaddr{ newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"), newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"), }) test(a[12], a, []ma.Multiaddr{ newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"), newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"), }) test(a[14], a, []ma.Multiaddr{ newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"), newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"), }) } func testSliceEqual(t *testing.T, a, b []ma.Multiaddr) { if len(a) != len(b) { t.Error("differ", a, b) } for i, addrA := range a { if !addrA.Equal(b[i]) { t.Error("differ", a, b) } } } func TestInterfaceAddressesWorks(t *testing.T) { _, err := InterfaceMultiaddrs() if err != nil { t.Fatal(err) } } func TestNetListener(t *testing.T) { listener, err := net.Listen("tcp", "127.0.0.1:1234") if err != nil { t.Fatal(err) } defer listener.Close() malist, err := WrapNetListener(listener) if err != nil { t.Fatal(err) } if !malist.Multiaddr().Equal(newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234")) { t.Fatal("unexpected multiaddr") } go func() { c, err := Dial(malist.Multiaddr()) if err != nil { t.Error("failed to dial") } if !c.RemoteMultiaddr().Equal(malist.Multiaddr()) { t.Error("dialed wrong target") } c.Close() c, err = Dial(malist.Multiaddr()) if err != nil { t.Error("failed to dial") } c.Close() }() c, err := malist.Accept() if err != nil { t.Fatal(err) } c.Close() netList := NetListener(malist) malist2, err := WrapNetListener(netList) if err != nil { t.Fatal(err) } if malist2 != malist { t.Fatal("expected WrapNetListener(NetListener(malist)) == malist") } nc, err := netList.Accept() if err != nil { t.Fatal(err) } if !nc.(Conn).LocalMultiaddr().Equal(malist.Multiaddr()) { t.Fatal("wrong multiaddr on conn") } nc.Close() } func BenchmarkResolveUnspecifiedAddress(b *testing.B) { a := ma.StringCast("/ip4/0.0.0.0/udp/42/quic-v1") iaddrs := []ma.Multiaddr{ ma.StringCast("/ip4/127.0.0.1/udp/42/quic-v1"), ma.StringCast("/ip4/192.168.1.1/udp/42/quic-v1"), } b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { ResolveUnspecifiedAddress(a, iaddrs) } } go-multiaddr-0.16.1/net/private.go000066400000000000000000000125641504514340500167670ustar00rootroot00000000000000package manet import ( "net" "strings" ma "github.com/multiformats/go-multiaddr" ) // Private4 and Private6 are well-known private networks var Private4, Private6 []*net.IPNet var privateCIDR4 = []string{ // localhost "127.0.0.0/8", // private networks "10.0.0.0/8", "100.64.0.0/10", "172.16.0.0/12", "192.168.0.0/16", // link local "169.254.0.0/16", } var privateCIDR6 = []string{ // localhost "::1/128", // ULA reserved "fc00::/7", // link local "fe80::/10", } // Unroutable4 and Unroutable6 are well known unroutable address ranges var Unroutable4, Unroutable6 []*net.IPNet var unroutableCIDR4 = []string{ "0.0.0.0/8", "192.0.0.0/26", "192.0.2.0/24", "192.88.99.0/24", "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "224.0.0.0/4", "240.0.0.0/4", "255.255.255.255/32", } var unroutableCIDR6 = []string{ "ff00::/8", // multicast "2001:db8::/32", // documentation } var globalUnicast []*net.IPNet var globalUnicastCIDR6 = []string{ "2000::/3", } var nat64CIDRs = []string{ "64:ff9b:1::/48", // RFC 8215 "64:ff9b::/96", // RFC 6052 } var nat64 []*net.IPNet // unResolvableDomains do not resolve to an IP address. // Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names var unResolvableDomains = []string{ // Reverse DNS Lookup ".in-addr.arpa", ".ip6.arpa", // RFC 6761: Users MAY assume that queries for "invalid" names will always return NXDOMAIN // responses ".invalid", } // privateUseDomains are reserved for private use and have no central authority for consistent // address resolution // Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names var privateUseDomains = []string{ // RFC 8375: Reserved for home networks ".home.arpa", // MDNS ".local", // RFC 6761: No central authority for .test names ".test", } // RFC 6761: Users may assume that IPv4 and IPv6 address queries for localhost names will // always resolve to the respective IP loopback address const localHostDomain = ".localhost" func init() { Private4 = parseCIDR(privateCIDR4) Private6 = parseCIDR(privateCIDR6) Unroutable4 = parseCIDR(unroutableCIDR4) Unroutable6 = parseCIDR(unroutableCIDR6) globalUnicast = parseCIDR(globalUnicastCIDR6) nat64 = parseCIDR(nat64CIDRs) } func parseCIDR(cidrs []string) []*net.IPNet { ipnets := make([]*net.IPNet, len(cidrs)) for i, cidr := range cidrs { _, ipnet, err := net.ParseCIDR(cidr) if err != nil { panic(err) } ipnets[i] = ipnet } return ipnets } // IsPublicAddr returns true if the IP part of the multiaddr is a publicly routable address // or if it's a dns address without a special use domain e.g. .local. func IsPublicAddr(a ma.Multiaddr) bool { isPublic := false ma.ForEach(a, func(c ma.Component) bool { switch c.Protocol().Code { case ma.P_IP6ZONE: return true case ma.P_IP4: ip := net.IP(c.RawValue()) isPublic = !inAddrRange(ip, Private4) && !inAddrRange(ip, Unroutable4) case ma.P_IP6: ip := net.IP(c.RawValue()) // IP6 documentation prefix(part of Unroutable6) is a subset of the ip6 // global unicast allocation so we ensure that it's not a documentation // prefix by diffing with Unroutable6 isPublicUnicastAddr := inAddrRange(ip, globalUnicast) && !inAddrRange(ip, Unroutable6) if isPublicUnicastAddr { isPublic = true return false } // The WellKnown NAT64 prefix(RFC 6052) can only reference a public IPv4 // address. // The Local use NAT64 prefix(RFC 8215) can reference private IPv4 // addresses. But since the translation from Local use NAT64 prefix to IPv4 // address is left to the user we have no way of knowing which IPv4 address // is referenced. We count these as Public addresses because a false // negative for this method here is generally worse than a false positive. isPublic = inAddrRange(ip, nat64) return false case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR: dnsAddr := c.Value() isPublic = true if isSubdomain(dnsAddr, localHostDomain) { isPublic = false return false } for _, ud := range unResolvableDomains { if isSubdomain(dnsAddr, ud) { isPublic = false return false } } for _, pd := range privateUseDomains { if isSubdomain(dnsAddr, pd) { isPublic = false break } } } return false }) return isPublic } // isSubdomain checks if child is sub domain of parent. It also returns true if child and parent are // the same domain. // Parent must have a "." prefix. func isSubdomain(child, parent string) bool { return strings.HasSuffix(child, parent) || child == parent[1:] } // IsPrivateAddr returns true if the IP part of the mutiaddr is in a private network func IsPrivateAddr(a ma.Multiaddr) bool { isPrivate := false ma.ForEach(a, func(c ma.Component) bool { switch c.Protocol().Code { case ma.P_IP6ZONE: return true case ma.P_IP4: isPrivate = inAddrRange(net.IP(c.RawValue()), Private4) case ma.P_IP6: isPrivate = inAddrRange(net.IP(c.RawValue()), Private6) case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR: dnsAddr := c.Value() if isSubdomain(dnsAddr, localHostDomain) { isPrivate = true } // We don't check for privateUseDomains because private use domains can // resolve to public IP addresses } return false }) return isPrivate } func inAddrRange(ip net.IP, ipnets []*net.IPNet) bool { for _, ipnet := range ipnets { if ipnet.Contains(ip) { return true } } return false } go-multiaddr-0.16.1/net/private_test.go000066400000000000000000000036271504514340500200260ustar00rootroot00000000000000package manet import ( "fmt" "testing" ma "github.com/multiformats/go-multiaddr" ) func TestIsPublicAddr(t *testing.T) { tests := []struct { addr ma.Multiaddr isPublic bool isPrivate bool }{ { addr: ma.StringCast("/ip4/192.168.1.1/tcp/80"), isPublic: false, isPrivate: true, }, { addr: ma.StringCast("/ip4/1.1.1.1/tcp/80"), isPublic: true, isPrivate: false, }, { addr: ma.StringCast("/tcp/80/ip4/1.1.1.1"), isPublic: false, isPrivate: false, }, { addr: ma.StringCast("/dns/node.libp2p.io/udp/1/quic-v1"), isPublic: true, isPrivate: false, }, { addr: ma.StringCast("/dnsaddr/node.libp2p.io/udp/1/quic-v1"), isPublic: true, isPrivate: false, }, { addr: ma.StringCast("/dns/node.libp2p.local/udp/1/quic-v1"), isPublic: false, isPrivate: false, // You can configure .local domains in local networks to return public addrs }, { addr: ma.StringCast("/dns/localhost/udp/1/quic-v1"), isPublic: false, isPrivate: true, }, { addr: ma.StringCast("/dns/a.localhost/tcp/1"), isPublic: false, isPrivate: true, }, { addr: ma.StringCast("/ip6/2400::1/tcp/10"), isPublic: true, isPrivate: false, }, { addr: ma.StringCast("/ip6/2001:db8::42/tcp/10"), isPublic: false, isPrivate: false, }, { addr: ma.StringCast("/ip6/64:ff9b::1.1.1.1/tcp/10"), isPublic: true, isPrivate: false, }, } for i, tt := range tests { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { isPublic := IsPublicAddr(tt.addr) isPrivate := IsPrivateAddr(tt.addr) if isPublic != tt.isPublic { t.Errorf("IsPublicAddr check failed for %s: expected %t, got %t", tt.addr, tt.isPublic, isPublic) } if isPrivate != tt.isPrivate { t.Errorf("IsPrivateAddr check failed for %s: expected %t, got %t", tt.addr, tt.isPrivate, isPrivate) } }) } } go-multiaddr-0.16.1/net/registry.go000066400000000000000000000053451504514340500171640ustar00rootroot00000000000000package manet import ( "fmt" "net" "sync" ma "github.com/multiformats/go-multiaddr" ) // FromNetAddrFunc is a generic function which converts a net.Addr to Multiaddress type FromNetAddrFunc func(a net.Addr) (ma.Multiaddr, error) // ToNetAddrFunc is a generic function which converts a Multiaddress to net.Addr type ToNetAddrFunc func(ma ma.Multiaddr) (net.Addr, error) var defaultCodecs = NewCodecMap() func init() { RegisterFromNetAddr(parseTCPNetAddr, "tcp", "tcp4", "tcp6") RegisterFromNetAddr(parseUDPNetAddr, "udp", "udp4", "udp6") RegisterFromNetAddr(parseIPNetAddr, "ip", "ip4", "ip6") RegisterFromNetAddr(parseIPPlusNetAddr, "ip+net") RegisterFromNetAddr(parseUnixNetAddr, "unix") RegisterToNetAddr(parseBasicNetMaddr, "tcp", "udp", "ip6", "ip4", "unix") } // CodecMap holds a map of NetCodecs indexed by their Protocol ID // along with parsers for the addresses they use. // It is used to keep a list of supported network address codecs (protocols // which addresses can be converted to and from multiaddresses). type CodecMap struct { addrParsers map[string]FromNetAddrFunc maddrParsers map[string]ToNetAddrFunc lk sync.Mutex } // NewCodecMap initializes and returns a CodecMap object. func NewCodecMap() *CodecMap { return &CodecMap{ addrParsers: make(map[string]FromNetAddrFunc), maddrParsers: make(map[string]ToNetAddrFunc), } } // RegisterFromNetAddr registers a conversion from net.Addr instances to multiaddrs. func RegisterFromNetAddr(from FromNetAddrFunc, networks ...string) { defaultCodecs.RegisterFromNetAddr(from, networks...) } // RegisterToNetAddr registers a conversion from multiaddrs to net.Addr instances. func RegisterToNetAddr(to ToNetAddrFunc, protocols ...string) { defaultCodecs.RegisterToNetAddr(to, protocols...) } // RegisterFromNetAddr registers a conversion from net.Addr instances to multiaddrs func (cm *CodecMap) RegisterFromNetAddr(from FromNetAddrFunc, networks ...string) { cm.lk.Lock() defer cm.lk.Unlock() for _, n := range networks { cm.addrParsers[n] = from } } // RegisterToNetAddr registers a conversion from multiaddrs to net.Addr instances func (cm *CodecMap) RegisterToNetAddr(to ToNetAddrFunc, protocols ...string) { cm.lk.Lock() defer cm.lk.Unlock() for _, p := range protocols { cm.maddrParsers[p] = to } } func (cm *CodecMap) getAddrParser(net string) (FromNetAddrFunc, error) { cm.lk.Lock() defer cm.lk.Unlock() parser, ok := cm.addrParsers[net] if !ok { return nil, fmt.Errorf("unknown network %v", net) } return parser, nil } func (cm *CodecMap) getMaddrParser(name string) (ToNetAddrFunc, error) { cm.lk.Lock() defer cm.lk.Unlock() p, ok := cm.maddrParsers[name] if !ok { return nil, fmt.Errorf("network not supported: %s", name) } return p, nil } go-multiaddr-0.16.1/net/registry_test.go000066400000000000000000000017651504514340500202250ustar00rootroot00000000000000package manet import ( "net" "testing" ma "github.com/multiformats/go-multiaddr" ) func TestRegisterFrom(t *testing.T) { cm := NewCodecMap() cm.RegisterFromNetAddr( func(a net.Addr) (ma.Multiaddr, error) { return nil, nil }, "test", "iptest", "blahtest", ) if _, ok := cm.addrParsers["test"]; !ok { t.Fatal("myproto not properly registered") } if _, ok := cm.addrParsers["iptest"]; !ok { t.Fatal("myproto not properly registered") } if _, ok := cm.addrParsers["blahtest"]; !ok { t.Fatal("myproto not properly registered") } } func TestRegisterTo(t *testing.T) { cm := NewCodecMap() cm.RegisterToNetAddr( func(a ma.Multiaddr) (net.Addr, error) { return nil, nil }, "test", "iptest", "blahtest", ) if _, ok := cm.maddrParsers["test"]; !ok { t.Fatal("myproto not properly registered") } if _, ok := cm.maddrParsers["iptest"]; !ok { t.Fatal("myproto not properly registered") } if _, ok := cm.maddrParsers["blahtest"]; !ok { t.Fatal("myproto not properly registered") } } go-multiaddr-0.16.1/net/resolve.go000066400000000000000000000046021504514340500167660ustar00rootroot00000000000000package manet import ( "fmt" ma "github.com/multiformats/go-multiaddr" ) // ResolveUnspecifiedAddress expands an unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to // use the known local interfaces. func ResolveUnspecifiedAddress(resolve ma.Multiaddr, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) { // split address into its components first, rest := splitFirstSlice(resolve) // if first component (ip) is not unspecified, use it as is. if !IsIPUnspecified(first) { return []ma.Multiaddr{resolve}, nil } resolveProto := first[0].Code() out := make([]ma.Multiaddr, 0, len(ifaceAddrs)) for _, ia := range ifaceAddrs { iafirst, _ := splitFirstSlice(ia) // must match the first protocol to be resolve. if len(iafirst) == 0 || iafirst[0].Code() != resolveProto { continue } joined := ia if len(rest) > 0 { joined = make(ma.Multiaddr, 0, len(iafirst)+len(rest)) joined = append(joined, iafirst...) joined = append(joined, rest...) } out = append(out, joined) } if len(out) < 1 { return nil, fmt.Errorf("failed to resolve: %s", resolve) } return out, nil } // ResolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to // use the known local interfaces. func ResolveUnspecifiedAddresses(unspecAddrs, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) { // todo optimize: only fetch these if we have a "any" addr. if len(ifaceAddrs) < 1 { var err error ifaceAddrs, err = interfaceAddresses() if err != nil { return nil, err } } var outputAddrs []ma.Multiaddr for _, a := range unspecAddrs { // unspecified? resolved, err := ResolveUnspecifiedAddress(a, ifaceAddrs) if err != nil { continue // optimistic. if we can't resolve anything, we'll know at the bottom. } outputAddrs = append(outputAddrs, resolved...) } if len(outputAddrs) < 1 { return nil, fmt.Errorf("failed to specify addrs: %s", unspecAddrs) } return outputAddrs, nil } // interfaceAddresses returns a list of addresses associated with local machine // Note: we do not return link local addresses. IP loopback is ok, because we // may be connecting to other nodes in the same machine. func interfaceAddresses() ([]ma.Multiaddr, error) { maddrs, err := InterfaceMultiaddrs() if err != nil { return nil, err } var out []ma.Multiaddr for _, a := range maddrs { if IsIP6LinkLocal(a) { continue } out = append(out, a) } return out, nil } go-multiaddr-0.16.1/net/resolve_test.go000066400000000000000000000033461504514340500200310ustar00rootroot00000000000000package manet import ( "testing" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" ) func TestResolvingAddrs(t *testing.T) { unspec := []ma.Multiaddr{ newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), newMultiaddr(t, "/ip6/::/tcp/1234"), newMultiaddr(t, "/ip6/::100/tcp/1234"), newMultiaddr(t, "/ip4/0.0.0.0"), } iface := []ma.Multiaddr{ newMultiaddr(t, "/ip4/127.0.0.1"), newMultiaddr(t, "/ip4/10.20.30.40"), newMultiaddr(t, "/ip6/::1"), newMultiaddr(t, "/ip6/::f"), } spec := []ma.Multiaddr{ newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), newMultiaddr(t, "/ip4/10.20.30.40/tcp/1234"), newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), newMultiaddr(t, "/ip6/::1/tcp/1234"), newMultiaddr(t, "/ip6/::f/tcp/1234"), newMultiaddr(t, "/ip6/::100/tcp/1234"), newMultiaddr(t, "/ip4/127.0.0.1"), newMultiaddr(t, "/ip4/10.20.30.40"), } actual, err := ResolveUnspecifiedAddresses(unspec, iface) require.NoError(t, err) require.Equal(t, len(actual), len(spec)) for i := range actual { require.True(t, actual[i].Equal(spec[i])) } ip4u := []ma.Multiaddr{newMultiaddr(t, "/ip4/0.0.0.0")} ip4i := []ma.Multiaddr{newMultiaddr(t, "/ip4/1.2.3.4")} ip6u := []ma.Multiaddr{newMultiaddr(t, "/ip6/::")} ip6i := []ma.Multiaddr{newMultiaddr(t, "/ip6/::1")} if _, err := ResolveUnspecifiedAddress(ip4u[0], ip6i); err == nil { t.Fatal("should have failed") } if _, err := ResolveUnspecifiedAddress(ip6u[0], ip4i); err == nil { t.Fatal("should have failed") } if _, err := ResolveUnspecifiedAddresses(ip6u, ip4i); err == nil { t.Fatal("should have failed") } if _, err := ResolveUnspecifiedAddresses(ip4u, ip6i); err == nil { t.Fatal("should have failed") } } go-multiaddr-0.16.1/package.json000066400000000000000000000010041504514340500164510ustar00rootroot00000000000000{ "author": "multiformats", "bugs": { "url": "https://github.com/multiformats/go-multiaddr/issues" }, "gx": { "dvcsimport": "github.com/multiformats/go-multiaddr" }, "gxDependencies": [ { "hash": "QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW", "name": "go-multihash", "version": "1.0.9" } ], "gxVersion": "0.9.0", "language": "go", "license": "MIT", "name": "go-multiaddr", "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", "version": "1.4.1" } go-multiaddr-0.16.1/protocol.go000066400000000000000000000057531504514340500163720ustar00rootroot00000000000000package multiaddr import ( "fmt" "strings" ) // These are special sizes const ( LengthPrefixedVarSize = -1 ) // Protocol is a Multiaddr protocol description structure. type Protocol struct { // Name is the string representation of the protocol code. E.g., ip4, // ip6, tcp, udp, etc. Name string // Code is the protocol's multicodec (a normal, non-varint number). Code int // VCode is a precomputed varint encoded version of Code. VCode []byte // Size is the size of the argument to this protocol. // // * Size == 0 means this protocol takes no argument. // * Size > 0 means this protocol takes a constant sized argument. // * Size < 0 means this protocol takes a variable length, varint // prefixed argument. Size int // a size of -1 indicates a length-prefixed variable size // Path indicates a path protocol (e.g., unix). When parsing multiaddr // strings, path protocols consume the remainder of the address instead // of stopping at the next forward slash. // // Size must be LengthPrefixedVarSize. Path bool // Transcoder converts between the byte representation and the string // representation of this protocol's argument (if any). // // This should only be non-nil if Size != 0 Transcoder Transcoder } var protocolsByName = map[string]Protocol{} var protocolsByCode = map[int]Protocol{} // Keep a map of pointers so that we can reuse the same pointer for the same protocol. var protocolPtrByCode = map[int]*Protocol{} // Protocols is the list of multiaddr protocols supported by this module. var Protocols = []Protocol{} func AddProtocol(p Protocol) error { if _, ok := protocolsByName[p.Name]; ok { return fmt.Errorf("protocol by the name %q already exists", p.Name) } if _, ok := protocolsByCode[p.Code]; ok { return fmt.Errorf("protocol code %d already taken by %q", p.Code, p.Code) } if p.Size != 0 && p.Transcoder == nil { return fmt.Errorf("protocols with arguments must define transcoders") } if p.Path && p.Size >= 0 { return fmt.Errorf("path protocols must have variable-length sizes") } if len(p.VCode) == 0 { return fmt.Errorf("protocol code %d is missing its VCode field", p.Code) } Protocols = append(Protocols, p) protocolsByName[p.Name] = p protocolsByCode[p.Code] = p protocolPtrByCode[p.Code] = &p return nil } // ProtocolWithName returns the Protocol description with given string name. func ProtocolWithName(s string) Protocol { return protocolsByName[s] } // ProtocolWithCode returns the Protocol description with given protocol code. func ProtocolWithCode(c int) Protocol { return protocolsByCode[c] } // ProtocolsWithString returns a slice of protocols matching given string. func ProtocolsWithString(s string) ([]Protocol, error) { s = strings.Trim(s, "/") sp := strings.Split(s, "/") if len(sp) == 0 { return nil, nil } t := make([]Protocol, len(sp)) for i, name := range sp { p := ProtocolWithName(name) if p.Code == 0 { return nil, fmt.Errorf("no protocol with name: %s", name) } t[i] = p } return t, nil } go-multiaddr-0.16.1/protocols.go000066400000000000000000000170031504514340500165440ustar00rootroot00000000000000package multiaddr // You **MUST** register your multicodecs with // https://github.com/multiformats/multicodec before adding them here. const ( P_IP4 = 4 P_TCP = 6 P_DNS = 53 // 4 or 6 P_DNS4 = 54 P_DNS6 = 55 P_DNSADDR = 56 P_UDP = 273 P_DCCP = 33 P_IP6 = 41 P_IP6ZONE = 42 P_IPCIDR = 43 P_QUIC = 460 P_QUIC_V1 = 461 P_WEBTRANSPORT = 465 P_CERTHASH = 466 P_SCTP = 132 P_CIRCUIT = 290 P_UDT = 301 P_UTP = 302 P_UNIX = 400 P_P2P = 421 P_IPFS = P_P2P // alias for backwards compatibility P_HTTP = 480 P_HTTP_PATH = 481 P_HTTPS = 443 // deprecated alias for /tls/http P_ONION = 444 // also for backwards compatibility P_ONION3 = 445 P_GARLIC64 = 446 P_GARLIC32 = 447 P_P2P_WEBRTC_DIRECT = 276 // Deprecated. use webrtc-direct instead P_TLS = 448 P_SNI = 449 P_NOISE = 454 P_WS = 477 P_WSS = 478 // deprecated alias for /tls/ws P_PLAINTEXTV2 = 7367777 P_WEBRTC_DIRECT = 280 P_WEBRTC = 281 P_MEMORY = 777 ) var ( protoIP4 = Protocol{ Name: "ip4", Code: P_IP4, VCode: CodeToVarint(P_IP4), Size: 32, Path: false, Transcoder: TranscoderIP4, } protoTCP = Protocol{ Name: "tcp", Code: P_TCP, VCode: CodeToVarint(P_TCP), Size: 16, Path: false, Transcoder: TranscoderPort, } protoDNS = Protocol{ Code: P_DNS, Size: LengthPrefixedVarSize, Name: "dns", VCode: CodeToVarint(P_DNS), Transcoder: TranscoderDns, } protoDNS4 = Protocol{ Code: P_DNS4, Size: LengthPrefixedVarSize, Name: "dns4", VCode: CodeToVarint(P_DNS4), Transcoder: TranscoderDns, } protoDNS6 = Protocol{ Code: P_DNS6, Size: LengthPrefixedVarSize, Name: "dns6", VCode: CodeToVarint(P_DNS6), Transcoder: TranscoderDns, } protoDNSADDR = Protocol{ Code: P_DNSADDR, Size: LengthPrefixedVarSize, Name: "dnsaddr", VCode: CodeToVarint(P_DNSADDR), Transcoder: TranscoderDns, } protoUDP = Protocol{ Name: "udp", Code: P_UDP, VCode: CodeToVarint(P_UDP), Size: 16, Path: false, Transcoder: TranscoderPort, } protoDCCP = Protocol{ Name: "dccp", Code: P_DCCP, VCode: CodeToVarint(P_DCCP), Size: 16, Path: false, Transcoder: TranscoderPort, } protoIP6 = Protocol{ Name: "ip6", Code: P_IP6, VCode: CodeToVarint(P_IP6), 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", Code: P_IP6ZONE, VCode: CodeToVarint(P_IP6ZONE), Size: LengthPrefixedVarSize, Path: false, Transcoder: TranscoderIP6Zone, } protoSCTP = Protocol{ Name: "sctp", Code: P_SCTP, VCode: CodeToVarint(P_SCTP), Size: 16, Transcoder: TranscoderPort, } protoCIRCUIT = Protocol{ Code: P_CIRCUIT, Size: 0, Name: "p2p-circuit", VCode: CodeToVarint(P_CIRCUIT), } protoONION2 = Protocol{ Name: "onion", Code: P_ONION, VCode: CodeToVarint(P_ONION), Size: 96, Transcoder: TranscoderOnion, } protoONION3 = Protocol{ Name: "onion3", Code: P_ONION3, VCode: CodeToVarint(P_ONION3), Size: 296, Transcoder: TranscoderOnion3, } protoGARLIC64 = Protocol{ Name: "garlic64", Code: P_GARLIC64, VCode: CodeToVarint(P_GARLIC64), Size: LengthPrefixedVarSize, Transcoder: TranscoderGarlic64, } protoGARLIC32 = Protocol{ Name: "garlic32", Code: P_GARLIC32, VCode: CodeToVarint(P_GARLIC32), Size: LengthPrefixedVarSize, Transcoder: TranscoderGarlic32, } protoUTP = Protocol{ Name: "utp", Code: P_UTP, VCode: CodeToVarint(P_UTP), } protoUDT = Protocol{ Name: "udt", Code: P_UDT, VCode: CodeToVarint(P_UDT), } protoQUIC = Protocol{ Name: "quic", Code: P_QUIC, VCode: CodeToVarint(P_QUIC), } protoQUICV1 = Protocol{ Name: "quic-v1", Code: P_QUIC_V1, VCode: CodeToVarint(P_QUIC_V1), } protoWEBTRANSPORT = Protocol{ Name: "webtransport", Code: P_WEBTRANSPORT, VCode: CodeToVarint(P_WEBTRANSPORT), } protoCERTHASH = Protocol{ Name: "certhash", Code: P_CERTHASH, VCode: CodeToVarint(P_CERTHASH), Size: LengthPrefixedVarSize, Transcoder: TranscoderCertHash, } protoHTTP = Protocol{ Name: "http", Code: P_HTTP, VCode: CodeToVarint(P_HTTP), } protoHTTPPath = Protocol{ Name: "http-path", Code: P_HTTP_PATH, VCode: CodeToVarint(P_HTTP_PATH), Size: LengthPrefixedVarSize, Transcoder: TranscoderHTTPPath, } protoHTTPS = Protocol{ Name: "https", Code: P_HTTPS, VCode: CodeToVarint(P_HTTPS), } protoP2P = Protocol{ Name: "p2p", Code: P_P2P, VCode: CodeToVarint(P_P2P), Size: LengthPrefixedVarSize, Transcoder: TranscoderP2P, } protoUNIX = Protocol{ Name: "unix", Code: P_UNIX, VCode: CodeToVarint(P_UNIX), Size: LengthPrefixedVarSize, Path: true, Transcoder: TranscoderUnix, } protoP2P_WEBRTC_DIRECT = Protocol{ Name: "p2p-webrtc-direct", Code: P_P2P_WEBRTC_DIRECT, VCode: CodeToVarint(P_P2P_WEBRTC_DIRECT), } protoTLS = Protocol{ Name: "tls", Code: P_TLS, VCode: CodeToVarint(P_TLS), } protoSNI = Protocol{ Name: "sni", Size: LengthPrefixedVarSize, Code: P_SNI, VCode: CodeToVarint(P_SNI), Transcoder: TranscoderDns, } protoNOISE = Protocol{ Name: "noise", Code: P_NOISE, VCode: CodeToVarint(P_NOISE), } protoPlaintextV2 = Protocol{ Name: "plaintextv2", Code: P_PLAINTEXTV2, VCode: CodeToVarint(P_PLAINTEXTV2), } protoWS = Protocol{ Name: "ws", Code: P_WS, VCode: CodeToVarint(P_WS), } protoWSS = Protocol{ Name: "wss", Code: P_WSS, VCode: CodeToVarint(P_WSS), } protoWebRTCDirect = Protocol{ Name: "webrtc-direct", Code: P_WEBRTC_DIRECT, VCode: CodeToVarint(P_WEBRTC_DIRECT), } protoWebRTC = Protocol{ Name: "webrtc", Code: P_WEBRTC, VCode: CodeToVarint(P_WEBRTC), } protoMemory = Protocol{ Name: "memory", Code: P_MEMORY, VCode: CodeToVarint(P_MEMORY), Size: 64, Transcoder: TranscoderMemory, } ) func init() { for _, p := range []Protocol{ protoIP4, protoTCP, protoDNS, protoDNS4, protoDNS6, protoDNSADDR, protoUDP, protoDCCP, protoIP6, protoIP6ZONE, protoIPCIDR, protoSCTP, protoCIRCUIT, protoONION2, protoONION3, protoGARLIC64, protoGARLIC32, protoUTP, protoUDT, protoQUIC, protoQUICV1, protoWEBTRANSPORT, protoCERTHASH, protoHTTP, protoHTTPPath, protoHTTPS, protoP2P, protoUNIX, protoP2P_WEBRTC_DIRECT, protoTLS, protoSNI, protoNOISE, protoWS, protoWSS, protoPlaintextV2, protoWebRTCDirect, protoWebRTC, protoMemory, } { if err := AddProtocol(p); err != nil { panic(err) } } // explicitly set both of these protocolsByName["p2p"] = protoP2P protocolsByName["ipfs"] = protoP2P } go-multiaddr-0.16.1/testdata/000077500000000000000000000000001504514340500160015ustar00rootroot00000000000000go-multiaddr-0.16.1/testdata/fuzz/000077500000000000000000000000001504514340500167775ustar00rootroot00000000000000go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/000077500000000000000000000000001504514340500232645ustar00rootroot00000000000000go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/0487b63847656fd4000066400000000000000000000001151504514340500252230ustar00rootroot00000000000000go test fuzz v1 []byte("\xa5\x03&\x12$000000000000000000000000000000000000") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/04a87ae2740f7195000066400000000000000000000000551504514340500252710ustar00rootroot00000000000000go test fuzz v1 []byte("\x90\x03\x06000000") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/19bd9fb2604afd6f000066400000000000000000000000551504514340500255720ustar00rootroot00000000000000go test fuzz v1 []byte("\x90\x03\x03/00!00") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/239d3594e0ee93bb000066400000000000000000000001161504514340500254320ustar00rootroot00000000000000go test fuzz v1 []byte("\xbd\x0300000000000000000000000000000000000\x00\x00") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/2ef0d600700564d4000066400000000000000000000000771504514340500252570ustar00rootroot00000000000000go test fuzz v1 []byte("\x90\x03\x06000000\x90\x03\x06000000") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/385d14fbb016b8c3000066400000000000000000000001071504514340500254160ustar00rootroot00000000000000go test fuzz v1 []byte("7*000000000000000000000000000000000000000000") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/511b72740453a863000066400000000000000000000000471504514340500251220ustar00rootroot00000000000000go test fuzz v1 []byte("\xd2\x03\x00") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/69ba454c4217999e000066400000000000000000000000401504514340500253000ustar00rootroot00000000000000go test fuzz v1 []byte("7\x00") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/9f0d778549d2b28e000066400000000000000000000000651504514340500253710ustar00rootroot00000000000000go test fuzz v1 []byte("\xbc\x030000000000\x00\x00") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/af9576bc28339a8d000066400000000000000000000000531504514340500254410ustar00rootroot00000000000000go test fuzz v1 []byte("\x84\xe0\xff\x00") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/e9317f1a3c43de50000066400000000000000000000000551504514340500254220ustar00rootroot00000000000000go test fuzz v1 []byte("\x90\x03\x06/0000/") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrBytes/f1ebd17c93085805000066400000000000000000000000551504514340500253510ustar00rootroot00000000000000go test fuzz v1 []byte("\xa5\x03\x030\x010") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/000077500000000000000000000000001504514340500234445ustar00rootroot00000000000000go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/382a5bb1eff47833000066400000000000000000000001341504514340500256060ustar00rootroot00000000000000go test fuzz v1 string("/garlic32/2222222222222222222222222222222222222222222222222222222") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/53eb3b6be337b1d7000066400000000000000000000360001504514340500256610ustar00rootroot00000000000000go test fuzz v1 string("/onion/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\xa0\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7fd\x00-\a\t\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\x04\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\x00\x01\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\n\xec\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\n\xff\v\v\v\v\v\v\v\v\v\v\v\v\v\x80\x00\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\x87نŁ\xe2\xec\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\r\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\xf2\n\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\x1d\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v2222=:") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/63891c9534054d61000066400000000000000000000001411504514340500253110ustar00rootroot00000000000000go test fuzz v1 string("/p2p/BAfZA2jA222222222222222222222222222222222222222222222222222222222") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/95a479f85dc92117000066400000000000000000000001411504514340500254630ustar00rootroot00000000000000go test fuzz v1 string("/p2p/BAfZBAjA222222222222222222222222222222222222222222222222222222222") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/9dba3b166a74fc47000066400000000000000000000010611504514340500256660ustar00rootroot00000000000000go test fuzz v1 string("/garlic64/000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\r\r\r\r\r\r\r\r0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/a2b937de623ded67000066400000000000000000000001401504514340500256670ustar00rootroot00000000000000go test fuzz v1 string("/garlic32/222222222222222222222222222222222222222222222\r\r\r\r\r\r\r") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/bc05ef53a41e422a000066400000000000000000000001051504514340500256430ustar00rootroot00000000000000go test fuzz v1 string("/p2p/Qm11ps1111111111111111111111111111111") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/d857c283ff1b2f2a000066400000000000000000000000461504514340500256700ustar00rootroot00000000000000go test fuzz v1 string("/sni//sni/0") go-multiaddr-0.16.1/testdata/fuzz/FuzzNewMultiaddrString/dffb2baac63c66ae000066400000000000000000000000641504514340500261570ustar00rootroot00000000000000go test fuzz v1 string("/onion/222222222222222=:1") go-multiaddr-0.16.1/transcoders.go000066400000000000000000000332101504514340500170450ustar00rootroot00000000000000package multiaddr import ( "bytes" "encoding/base32" "encoding/base64" "encoding/binary" "errors" "fmt" "net" "net/url" "strconv" "strings" "github.com/ipfs/go-cid" "github.com/multiformats/go-multibase" mh "github.com/multiformats/go-multihash" ) type Transcoder interface { // Validates and encodes to bytes a multiaddr that's in the string representation. StringToBytes(string) ([]byte, error) // Validates and decodes to a string a multiaddr that's in the bytes representation. BytesToString([]byte) (string, error) // Validates bytes when parsing a multiaddr that's already in the bytes representation. ValidateBytes([]byte) error } func NewTranscoderFromFunctions( s2b func(string) ([]byte, error), b2s func([]byte) (string, error), val func([]byte) error, ) Transcoder { return twrp{s2b, b2s, val} } type twrp struct { strtobyte func(string) ([]byte, error) bytetostr func([]byte) (string, error) validbyte func([]byte) 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) } func (t twrp) ValidateBytes(b []byte) error { if t.validbyte == nil { return nil } return t.validbyte(b) } var TranscoderIP4 = NewTranscoderFromFunctions(ip4StB, ip4BtS, nil) var TranscoderIP6 = NewTranscoderFromFunctions(ip6StB, ip6BtS, nil) var TranscoderIP6Zone = NewTranscoderFromFunctions(ip6zoneStB, ip6zoneBtS, ip6zoneVal) var TranscoderIPCIDR = NewTranscoderFromFunctions(ipcidrStB, ipcidrBtS, ipcidrValidate) func ipcidrBtS(b []byte) (string, error) { if err := ipcidrValidate(b); err != nil { return "", err } 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 ipcidrValidate(b []byte) error { if len(b) != 1 { return fmt.Errorf("invalid length (should be == 1)") } return nil } 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 ip6zoneStB(s string) ([]byte, error) { if len(s) == 0 { return nil, fmt.Errorf("empty ip6zone") } if strings.Contains(s, "/") { return nil, fmt.Errorf("IPv6 zone ID contains '/': %s", s) } return []byte(s), nil } func ip6zoneBtS(b []byte) (string, error) { if len(b) == 0 { return "", fmt.Errorf("invalid length (should be > 0)") } return string(b), nil } func ip6zoneVal(b []byte) error { if len(b) == 0 { return fmt.Errorf("invalid length (should be > 0)") } // Not supported as this would break multiaddrs. if bytes.IndexByte(b, '/') >= 0 { return fmt.Errorf("IPv6 zone ID contains '/': %s", string(b)) } return nil } func ip6StB(s string) ([]byte, error) { i := net.ParseIP(s).To16() if i == nil { return nil, fmt.Errorf("failed to parse ip6 addr: %s", s) } return i, nil } func ip6BtS(b []byte) (string, error) { ip := net.IP(b) if ip4 := ip.To4(); ip4 != nil { // Go fails to prepend the `::ffff:` part. return "::ffff:" + ip4.String(), nil } return ip.String(), nil } func ip4BtS(b []byte) (string, error) { return net.IP(b).String(), nil } var TranscoderPort = NewTranscoderFromFunctions(portStB, portBtS, nil) func portStB(s string) ([]byte, error) { i, err := strconv.ParseUint(s, 10, 16) if err != nil { return nil, fmt.Errorf("failed to parse port addr: %s", err) } 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.FormatUint(uint64(i), 10), nil } var TranscoderOnion = NewTranscoderFromFunctions(onionStB, onionBtS, onionValidate) 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) } 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 address without the ".onion" substring are 10 bytes long if len(onionHostBytes) != 10 { return nil, fmt.Errorf("failed to parse onion addr: %s not a Tor onion address", s) } // onion port number i, err := strconv.ParseUint(addr[1], 10, 16) if err != nil { return nil, fmt.Errorf("failed to parse onion addr: %s", err) } if i == 0 { return nil, fmt.Errorf("failed to parse onion addr: %s", "non-zero port") } 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]) if port == 0 { return "", fmt.Errorf("failed to parse onion addr: %s", "non-zero port") } return addr + ":" + strconv.FormatUint(uint64(port), 10), nil } func onionValidate(b []byte) error { if len(b) != 12 { return fmt.Errorf("invalid len for onion addr: got %d expected 12", len(b)) } port := binary.BigEndian.Uint16(b[10:12]) if port == 0 { return fmt.Errorf("invalid port 0 for onion addr") } return nil } var TranscoderOnion3 = NewTranscoderFromFunctions(onion3StB, onion3BtS, onion3Validate) func onion3StB(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]) != 56 { return nil, fmt.Errorf("failed to parse onion addr: %s not a Tor onionv3 address. len == %d", s, len(addr[0])) } 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.ParseUint(addr[1], 10, 16) if err != nil { return nil, fmt.Errorf("failed to parse onion addr: %s", err) } if i == 0 { return nil, fmt.Errorf("failed to parse onion addr: %s", "non-zero port") } onionPortBytes := make([]byte, 2) binary.BigEndian.PutUint16(onionPortBytes, uint16(i)) bytes := []byte{} bytes = append(bytes, onionHostBytes[0:35]...) bytes = append(bytes, onionPortBytes...) return bytes, nil } func onion3BtS(b []byte) (string, error) { addr := strings.ToLower(base32.StdEncoding.EncodeToString(b[0:35])) port := binary.BigEndian.Uint16(b[35:37]) if port < 1 { return "", fmt.Errorf("failed to parse onion addr: %s", "port less than 1") } str := addr + ":" + strconv.FormatUint(uint64(port), 10) return str, nil } func onion3Validate(b []byte) error { if len(b) != 37 { return fmt.Errorf("invalid len for onion addr: got %d expected 37", len(b)) } port := binary.BigEndian.Uint16(b[35:37]) if port == 0 { return fmt.Errorf("invalid port 0 for onion addr") } return nil } var TranscoderGarlic64 = NewTranscoderFromFunctions(garlic64StB, garlic64BtS, garlic64Validate) // i2p uses an alternate character set for base64 addresses. This returns an appropriate encoder. var garlicBase64Encoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~") func garlic64StB(s string) ([]byte, error) { garlicHostBytes, err := garlicBase64Encoding.DecodeString(s) if err != nil { return nil, fmt.Errorf("failed to decode base64 i2p addr: %s %s", s, err) } if err := garlic64Validate(garlicHostBytes); err != nil { return nil, err } return garlicHostBytes, nil } func garlic64BtS(b []byte) (string, error) { if err := garlic64Validate(b); err != nil { return "", err } addr := garlicBase64Encoding.EncodeToString(b) return addr, nil } func garlic64Validate(b []byte) error { // A garlic64 address will always be greater than 386 bytes long when encoded. if len(b) < 386 { return fmt.Errorf("failed to validate garlic addr: %s not an i2p base64 address. len: %d", b, len(b)) } return nil } var TranscoderGarlic32 = NewTranscoderFromFunctions(garlic32StB, garlic32BtS, garlic32Validate) var garlicBase32Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567") func garlic32StB(s string) ([]byte, error) { for len(s)%8 != 0 { s += "=" } garlicHostBytes, err := garlicBase32Encoding.DecodeString(s) if err != nil { return nil, fmt.Errorf("failed to decode base32 garlic addr: %s, err: %v len: %v", s, err, len(s)) } if err := garlic32Validate(garlicHostBytes); err != nil { return nil, err } return garlicHostBytes, nil } func garlic32BtS(b []byte) (string, error) { if err := garlic32Validate(b); err != nil { return "", err } return strings.TrimRight(garlicBase32Encoding.EncodeToString(b), "="), nil } func garlic32Validate(b []byte) error { // an i2p address with encrypted leaseset has len >= 35 bytes // all other addresses will always be exactly 32 bytes // https://geti2p.net/spec/b32encrypted if len(b) < 35 && len(b) != 32 { return fmt.Errorf("failed to validate garlic addr: %s not an i2p base32 address. len: %d", b, len(b)) } return nil } var TranscoderP2P = NewTranscoderFromFunctions(p2pStB, p2pBtS, p2pVal) // The encoded peer ID can either be a CID of a key or a raw multihash (identity // or sha256-256). func p2pStB(s string) ([]byte, error) { // check if the address is a base58 encoded sha256 or identity multihash if strings.HasPrefix(s, "Qm") || strings.HasPrefix(s, "1") { m, err := mh.FromB58String(s) if err != nil { return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err) } if err := p2pVal(m); err != nil { return nil, err } return m, nil } // check if the address is a CID c, err := cid.Decode(s) if err != nil { return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err) } if ty := c.Type(); ty == cid.Libp2pKey { if err := p2pVal(c.Hash()); err != nil { return nil, err } return c.Hash(), nil } else { return nil, fmt.Errorf("failed to parse p2p addr: %s has the invalid codec %d", s, ty) } } func p2pVal(b []byte) error { h, err := mh.Decode([]byte(b)) if err != nil { return fmt.Errorf("invalid multihash: %s", err) } // Peer IDs require either sha256 or identity multihash // https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#peer-ids if h.Code != mh.SHA2_256 && h.Code != mh.IDENTITY { return fmt.Errorf("invalid multihash code %d expected sha-256 or identity", h.Code) } // This check should ideally be in multihash. sha256 digest lengths MUST be 32 if h.Code == mh.SHA2_256 && h.Length != 32 { return fmt.Errorf("invalid digest length %d for sha256 addr: expected 32", h.Length) } return nil } func p2pBtS(b []byte) (string, error) { m, err := mh.Cast(b) if err != nil { return "", err } return m.B58String(), nil } var TranscoderUnix = NewTranscoderFromFunctions(unixStB, unixBtS, unixValidate) func unixStB(s string) ([]byte, error) { return []byte(s), nil } func unixBtS(b []byte) (string, error) { return string(b), nil } func unixValidate(b []byte) error { // The string to bytes parser requires that all Path protocols begin with a '/' // file://./codec.go#L49 if len(b) < 2 { return fmt.Errorf("byte slice too short: %d", len(b)) } if b[0] != '/' { return errors.New("path protocol must begin with '/'") } if b[len(b)-1] == '/' { return errors.New("unix socket path must not end in '/'") } return nil } var TranscoderDns = NewTranscoderFromFunctions(dnsStB, dnsBtS, dnsVal) func dnsVal(b []byte) error { if len(b) == 0 { return fmt.Errorf("empty dns addr") } if bytes.IndexByte(b, '/') >= 0 { return fmt.Errorf("domain name %q contains a slash", string(b)) } return nil } func dnsStB(s string) ([]byte, error) { b := []byte(s) if err := dnsVal(b); err != nil { return nil, err } return b, nil } func dnsBtS(b []byte) (string, error) { return string(b), nil } var TranscoderCertHash = NewTranscoderFromFunctions(certHashStB, certHashBtS, validateCertHash) func certHashStB(s string) ([]byte, error) { _, data, err := multibase.Decode(s) if err != nil { return nil, err } if _, err := mh.Decode(data); err != nil { return nil, err } return data, nil } func certHashBtS(b []byte) (string, error) { return multibase.Encode(multibase.Base64url, b) } func validateCertHash(b []byte) error { _, err := mh.Decode(b) return err } var TranscoderHTTPPath = NewTranscoderFromFunctions(httpPathStB, httpPathBtS, validateHTTPPath) func httpPathStB(s string) ([]byte, error) { unescaped, err := url.QueryUnescape(s) if err != nil { return nil, err } if len(unescaped) == 0 { return nil, fmt.Errorf("empty http path is not allowed") } return []byte(unescaped), err } func httpPathBtS(b []byte) (string, error) { if len(b) == 0 { return "", fmt.Errorf("empty http path is not allowed") } return url.QueryEscape(string(b)), nil } func validateHTTPPath(b []byte) error { if len(b) == 0 { return fmt.Errorf("empty http path is not allowed") } return nil // We can represent any byte slice when we escape it. } var TranscoderMemory = NewTranscoderFromFunctions(memoryStB, memoryBtS, memoryValidate) func memoryStB(s string) ([]byte, error) { z, err := strconv.ParseUint(s, 10, 64) if err != nil { return nil, err } buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, z) return buf, nil } func memoryBtS(b []byte) (string, error) { if len(b) != 8 { return "", fmt.Errorf("expected uint64, only found %d bits", len(b)*8) } z := binary.BigEndian.Uint64(b) return strconv.FormatUint(z, 10), nil } func memoryValidate(b []byte) error { // Ensure the byte array is exactly 8 bytes long for a uint64 in big-endian format if len(b) != 8 { return errors.New("invalid length: must be exactly 8 bytes") } return nil } go-multiaddr-0.16.1/util.go000066400000000000000000000062041504514340500154760ustar00rootroot00000000000000package multiaddr import ( "fmt" "github.com/multiformats/go-multiaddr/x/meg" ) // Split returns the sub-address portions of a multiaddr. func Split(m Multiaddr) []Component { return m } // Join returns a combination of addresses. // Note: This copies all the components from the input Multiaddrs. Depending on // your use case, you may prefer to use `append(leftMA, rightMA...)` instead. func Join(msInterfaces ...Multiaddrer) Multiaddr { ms := make([]Multiaddr, len(msInterfaces)) for i, m := range msInterfaces { if m == nil { continue } ms[i] = m.Multiaddr() } size := 0 for _, m := range ms { size += len(m) } if size == 0 { return nil } out := make([]Component, 0, size) for _, m := range ms { out = append(out, m...) } return out } // Cast re-casts a byte slice as a multiaddr. will panic if it fails to parse. func Cast(b []byte) Multiaddr { m, err := NewMultiaddrBytes(b) if err != nil { panic(fmt.Errorf("multiaddr failed to parse: %s", err)) } return m } // StringCast like Cast, but parses a string. Will also panic if it fails to parse. func StringCast(s string) Multiaddr { m, err := NewMultiaddr(s) if err != nil { panic(fmt.Errorf("multiaddr failed to parse: %s", err)) } return m } // SplitFirst returns the first component and the rest of the multiaddr. func SplitFirst(m Multiaddr) (*Component, Multiaddr) { if len(m) == 0 { return nil, nil } if len(m) == 1 { return &m[0], nil } // defensive copy. Users can avoid by doing the split themselves. copyC := m[0] return ©C, m[1:].copy() } // SplitLast returns the rest of the multiaddr and the last component. func SplitLast(m Multiaddr) (Multiaddr, *Component) { if len(m) == 0 { return nil, nil } if len(m) == 1 { // We want to explicitly return a nil slice if the prefix is now empty. return nil, &m[0] } // defensive copy. Users can avoid by doing the split themselves. copyC := m[len(m)-1] return m[:len(m)-1].copy(), ©C } // SplitFunc splits the multiaddr when the callback first returns true. The // component on which the callback first returns will be included in the // *second* multiaddr. func SplitFunc(m Multiaddr, cb func(Component) bool) (Multiaddr, Multiaddr) { if len(m) == 0 { return nil, nil } idx := len(m) for i, c := range m { if cb(c) { idx = i break } } pre, post := m[:idx], m[idx:] if len(pre) == 0 { pre = nil } if len(post) == 0 { post = nil } // defensive copy. Users can avoid by doing the split themselves. return pre.copy(), post.copy() } // ForEach walks over the multiaddr, component by component. // // This function iterates over components. // Return true to continue iteration, false to stop. // // Prefer a standard for range loop instead // e.g. `for _, c := range m { ... }` func ForEach(m Multiaddr, cb func(c Component) bool) { for _, c := range m { if !cb(c) { return } } } type componentList []Component func (m componentList) Get(i int) meg.Matchable { return &m[i] } func (m componentList) Len() int { return len(m) } func (m Multiaddr) Match(p ...meg.Pattern) (bool, error) { matcher := meg.PatternToMatcher(p...) return meg.Match(matcher, componentList(m)) } go-multiaddr-0.16.1/util_test.go000066400000000000000000000063561504514340500165450ustar00rootroot00000000000000package multiaddr import ( "strings" "testing" ) func TestSplitFirstLast(t *testing.T) { ipStr := "/ip4/0.0.0.0" tcpStr := "/tcp/123" quicStr := "/quic" ipfsStr := "/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7" for _, x := range [][]string{ {ipStr, tcpStr, quicStr, ipfsStr}, {ipStr, tcpStr, ipfsStr}, {ipStr, tcpStr}, {ipStr}, } { addr := StringCast(strings.Join(x, "")) head, tail := SplitFirst(addr) rest, last := SplitLast(addr) if len(x) == 0 { if head != nil { t.Error("expected head to be nil") } if tail != nil { t.Error("expected tail to be nil") } if rest != nil { t.Error("expected rest to be nil") } if last != nil { t.Error("expected last to be nil") } continue } if !head.Multiaddr().Equal(StringCast(x[0])) { t.Errorf("expected %s to be %s", head, x[0]) } if !last.Multiaddr().Equal(StringCast(x[len(x)-1])) { t.Errorf("expected %s to be %s", head, x[len(x)-1]) } if len(x) == 1 { if tail != nil { t.Error("expected tail to be nil") } if rest != nil { t.Error("expected rest to be nil") } continue } tailExp := strings.Join(x[1:], "") if !tail.Equal(StringCast(tailExp)) { t.Errorf("expected %s to be %s", tail, tailExp) } restExp := strings.Join(x[:len(x)-1], "") if !rest.Equal(StringCast(restExp)) { t.Errorf("expected %s to be %s", rest, restExp) } } c, err := NewComponent("ip4", "127.0.0.1") if err != nil { t.Fatal(err) } ci, m := SplitFirst(c.Multiaddr()) if !ci.Equal(c) || m != nil { t.Error("split first on component failed") } m, ci = SplitLast(c.Multiaddr()) if !ci.Equal(c) || m != nil { t.Error("split last on component failed") } cis := Split(c.Multiaddr()) if len(cis) != 1 || !cis[0].Equal(c) { t.Error("split on component failed") } m1, m2 := SplitFunc(c.Multiaddr(), func(c Component) bool { return true }) if m1 != nil || !m2.Equal(c.Multiaddr()) { t.Error("split func(true) on component failed") } m1, m2 = SplitFunc(c.Multiaddr(), func(c Component) bool { return false }) if !m1.Equal(c.Multiaddr()) || m2 != nil { t.Error("split func(false) on component failed") } i := 0 ForEach(c.Multiaddr(), func(ci Component) bool { if i != 0 { t.Error("expected exactly one component") } i++ if !ci.Equal(c) { t.Error("foreach on component failed") } return true }) } func TestSplitFunc(t *testing.T) { ipStr := "/ip4/0.0.0.0" tcpStr := "/tcp/123" quicStr := "/quic" ipfsStr := "/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7" for _, x := range [][]string{ {ipStr, tcpStr, quicStr, ipfsStr}, {ipStr, tcpStr, ipfsStr}, {ipStr, tcpStr}, {ipStr}, } { addr := StringCast(strings.Join(x, "")) for i, cs := range x { target := StringCast(cs) a, b := SplitFunc(addr, func(c Component) bool { return c.Multiaddr().Equal(target) }) if i == 0 { if a != nil { t.Error("expected nil addr") } } else { if !a.Equal(StringCast(strings.Join(x[:i], ""))) { t.Error("split failed") } if !b.Equal(StringCast(strings.Join(x[i:], ""))) { t.Error("split failed") } } } a, b := SplitFunc(addr, func(_ Component) bool { return false }) if !a.Equal(addr) || b != nil { t.Error("should not have split") } } } go-multiaddr-0.16.1/v015-MIGRATION.md000066400000000000000000000026171504514340500165420ustar00rootroot00000000000000## Breaking changes in the large refactor of go-multiaddr v0.15 - There is no `Multiaddr` interface type. - Multiaddr is now a concrete type. Not an interface. - Empty Multiaddrs/Component should generally be checked with `.Empty()`, not `== nil`. This is similar to how slices should be checked with `len(s) == 0` rather than `s == nil`. - Components do not implement `Multiaddr` as there is no `Multiaddr` to implement. - `Multiaddr` can no longer be a key in a Map. If you want unique Multiaddrs, use `Multiaddr.String()` as the key, otherwise you can use the pointer value `*Multiaddr`. ## Callouts - Multiaddr.Bytes() is a `O(n)` operation for n Components, as opposed to a `O(1)` operation. ## Migration tips for v0.15 - If appending a `*Component` to a `Multiaddr`, prefer the `Multiaddr.AppendComponent` method as it will perform a nil pointer check on the `*Component` before appending. If you know a `*Component` is not nil, you may use `append` normally. - the `Multiaddr` type is simply a `[]Component`. - You can use `append` when you have a `Component`. - You can use `for range` loops. - If your use case supports it, prefer `append` or `AppendComponent` to append a Component to a Multiaddr rather than using `Encapsulate` or `Join`. It's much faster as it does not do a defensive copy. - Likewise, to join two Multiaddrs, `append` will perform better than `Encapsulate` or `Join`. go-multiaddr-0.16.1/varint.go000066400000000000000000000010251504514340500160200ustar00rootroot00000000000000package multiaddr import ( "math" "github.com/multiformats/go-varint" ) // CodeToVarint converts an integer to a varint-encoded []byte func CodeToVarint(num int) []byte { if num < 0 || num > math.MaxInt32 { panic("invalid code") } return varint.ToUvarint(uint64(num)) } func ReadVarintCode(b []byte) (int, int, error) { code, n, err := varint.FromUvarint(b) if err != nil { return 0, 0, err } if code > math.MaxInt32 { // we only allow 32bit codes. return 0, 0, varint.ErrOverflow } return int(code), n, err } go-multiaddr-0.16.1/version.json000066400000000000000000000000331504514340500165440ustar00rootroot00000000000000{ "version": "v0.16.1" } go-multiaddr-0.16.1/x/000077500000000000000000000000001504514340500144375ustar00rootroot00000000000000go-multiaddr-0.16.1/x/meg/000077500000000000000000000000001504514340500152075ustar00rootroot00000000000000go-multiaddr-0.16.1/x/meg/bench_test.go000066400000000000000000000261401504514340500176570ustar00rootroot00000000000000package meg_test import ( "testing" "github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr/x/meg" ) type preallocatedCapture struct { certHashes []string matcher meg.Matcher } func preallocateCapture() *preallocatedCapture { p := &preallocatedCapture{} p.matcher = meg.PatternToMatcher( meg.Or( meg.Val(multiaddr.P_IP4), meg.Val(multiaddr.P_IP6), meg.Val(multiaddr.P_DNS), ), meg.Val(multiaddr.P_UDP), meg.Val(multiaddr.P_WEBRTC_DIRECT), meg.CaptureZeroOrMoreStrings(multiaddr.P_CERTHASH, &p.certHashes), ) return p } var webrtcMatchPrealloc *preallocatedCapture type componentList []multiaddr.Component func (m componentList) Get(i int) meg.Matchable { return &m[i] } func (m componentList) Len() int { return len(m) } func (p *preallocatedCapture) IsWebRTCDirectMultiaddr(addr multiaddr.Multiaddr) (bool, int) { found, _ := meg.Match(p.matcher, componentList(addr)) return found, len(p.certHashes) } // IsWebRTCDirectMultiaddr returns whether addr is a /webrtc-direct multiaddr with the count of certhashes // in addr func IsWebRTCDirectMultiaddr(addr multiaddr.Multiaddr) (bool, int) { if webrtcMatchPrealloc == nil { webrtcMatchPrealloc = preallocateCapture() } return webrtcMatchPrealloc.IsWebRTCDirectMultiaddr(addr) } // IsWebRTCDirectMultiaddrLoop returns whether addr is a /webrtc-direct multiaddr with the count of certhashes // in addr func IsWebRTCDirectMultiaddrLoop(addr multiaddr.Multiaddr) (bool, int) { protos := [...]int{multiaddr.P_IP4, multiaddr.P_IP6, multiaddr.P_DNS, multiaddr.P_UDP, multiaddr.P_WEBRTC_DIRECT} matchProtos := [...][]int{protos[:3], {protos[3]}, {protos[4]}} certHashCount := 0 for i, c := range addr { if i >= len(matchProtos) { if c.Code() == multiaddr.P_CERTHASH { certHashCount++ } else { return false, 0 } } else { found := false for _, proto := range matchProtos[i] { if c.Code() == proto { found = true break } } if !found { return false, 0 } } } return true, certHashCount } var wtPrealloc *preallocatedCapture func isWebTransportMultiaddrPrealloc() *preallocatedCapture { if wtPrealloc != nil { return wtPrealloc } p := &preallocatedCapture{} var dnsName string var ip4Addr string var ip6Addr string var udpPort string var sni string p.matcher = meg.PatternToMatcher( meg.Or( meg.CaptureString(multiaddr.P_IP4, &ip4Addr), meg.CaptureString(multiaddr.P_IP6, &ip6Addr), meg.CaptureString(multiaddr.P_DNS4, &dnsName), meg.CaptureString(multiaddr.P_DNS6, &dnsName), meg.CaptureString(multiaddr.P_DNS, &dnsName), ), meg.CaptureString(multiaddr.P_UDP, &udpPort), meg.Val(multiaddr.P_QUIC_V1), meg.Optional( meg.CaptureString(multiaddr.P_SNI, &sni), ), meg.Val(multiaddr.P_WEBTRANSPORT), meg.CaptureZeroOrMoreStrings(multiaddr.P_CERTHASH, &p.certHashes), ) wtPrealloc = p return p } func IsWebTransportMultiaddrPrealloc(m multiaddr.Multiaddr) (bool, int) { p := isWebTransportMultiaddrPrealloc() found, _ := meg.Match(p.matcher, componentList(m)) return found, len(p.certHashes) } func IsWebTransportMultiaddr(m multiaddr.Multiaddr) (bool, int) { var dnsName string var ip4Addr string var ip6Addr string var udpPort string var sni string var certHashesStr []string matched, _ := m.Match( meg.Or( meg.CaptureString(multiaddr.P_IP4, &ip4Addr), meg.CaptureString(multiaddr.P_IP6, &ip6Addr), meg.CaptureString(multiaddr.P_DNS4, &dnsName), meg.CaptureString(multiaddr.P_DNS6, &dnsName), meg.CaptureString(multiaddr.P_DNS, &dnsName), ), meg.CaptureString(multiaddr.P_UDP, &udpPort), meg.Val(multiaddr.P_QUIC_V1), meg.Optional( meg.CaptureString(multiaddr.P_SNI, &sni), ), meg.Val(multiaddr.P_WEBTRANSPORT), meg.CaptureZeroOrMoreStrings(multiaddr.P_CERTHASH, &certHashesStr), ) if !matched { return false, 0 } return true, len(certHashesStr) } func IsWebTransportMultiaddrCaptureBytes(m multiaddr.Multiaddr) (bool, int) { var dnsName []byte var ip4Addr []byte var ip6Addr []byte var udpPort []byte var sni []byte var certHashes [][]byte matched, _ := m.Match( meg.Or( meg.CaptureBytes(multiaddr.P_IP4, &ip4Addr), meg.CaptureBytes(multiaddr.P_IP6, &ip6Addr), meg.CaptureBytes(multiaddr.P_DNS4, &dnsName), meg.CaptureBytes(multiaddr.P_DNS6, &dnsName), meg.CaptureBytes(multiaddr.P_DNS, &dnsName), ), meg.CaptureBytes(multiaddr.P_UDP, &udpPort), meg.Val(multiaddr.P_QUIC_V1), meg.Optional( meg.CaptureBytes(multiaddr.P_SNI, &sni), ), meg.Val(multiaddr.P_WEBTRANSPORT), meg.CaptureZeroOrMoreBytes(multiaddr.P_CERTHASH, &certHashes), ) if !matched { return false, 0 } return true, len(certHashes) } func IsWebTransportMultiaddrNoCapture(m multiaddr.Multiaddr) (bool, int) { matched, _ := m.Match( meg.Or( meg.Val(multiaddr.P_IP4), meg.Val(multiaddr.P_IP6), meg.Val(multiaddr.P_DNS4), meg.Val(multiaddr.P_DNS6), meg.Val(multiaddr.P_DNS), ), meg.Val(multiaddr.P_UDP), meg.Val(multiaddr.P_QUIC_V1), meg.Optional( meg.Val(multiaddr.P_SNI), ), meg.Val(multiaddr.P_WEBTRANSPORT), meg.ZeroOrMore(multiaddr.P_CERTHASH), ) if !matched { return false, 0 } return true, 0 } func IsWebTransportMultiaddrLoop(m multiaddr.Multiaddr) (bool, int) { var ip4Addr string var ip6Addr string var dnsName string var udpPort string var sni string // Expected pattern: // 0: one of: P_IP4, P_IP6, P_DNS4, P_DNS6, P_DNS // 1: P_UDP // 2: P_QUIC_V1 // 3: optional P_SNI (if present) // Next: P_WEBTRANSPORT // Trailing: zero or more P_CERTHASH // Check minimum length (at least without SNI: 4 components) if len(m) < 4 { return false, 0 } idx := 0 // Component 0: Must be one of IP or DNS protocols. switch m[idx].Code() { case multiaddr.P_IP4: ip4Addr = m[idx].String() case multiaddr.P_IP6: ip6Addr = m[idx].String() case multiaddr.P_DNS4, multiaddr.P_DNS6, multiaddr.P_DNS: dnsName = m[idx].String() default: return false, 0 } idx++ // Component 1: Must be UDP. if idx >= len(m) || m[idx].Code() != multiaddr.P_UDP { return false, 0 } udpPort = m[idx].String() idx++ // Component 2: Must be QUIC_V1. if idx >= len(m) || m[idx].Code() != multiaddr.P_QUIC_V1 { return false, 0 } idx++ // Optional component: SNI. if idx < len(m) && m[idx].Code() == multiaddr.P_SNI { sni = m[idx].String() idx++ } // Next component: Must be WEBTRANSPORT. if idx >= len(m) || m[idx].Code() != multiaddr.P_WEBTRANSPORT { return false, 0 } idx++ // All remaining components must be CERTHASH. certHashCount := 0 for ; idx < len(m); idx++ { if m[idx].Code() != multiaddr.P_CERTHASH { return false, 0 } _ = m[idx].String() certHashCount++ } _ = ip4Addr _ = ip6Addr _ = dnsName _ = udpPort _ = sni return true, certHashCount } func IsWebTransportMultiaddrLoopNoCapture(m multiaddr.Multiaddr) (bool, int) { // Expected pattern: // 0: one of: P_IP4, P_IP6, P_DNS4, P_DNS6, P_DNS // 1: P_UDP // 2: P_QUIC_V1 // 3: optional P_SNI (if present) // Next: P_WEBTRANSPORT // Trailing: zero or more P_CERTHASH // Check minimum length (at least without SNI: 4 components) if len(m) < 4 { return false, 0 } idx := 0 // Component 0: Must be one of IP or DNS protocols. switch m[idx].Code() { case multiaddr.P_IP4: case multiaddr.P_IP6: case multiaddr.P_DNS4, multiaddr.P_DNS6, multiaddr.P_DNS: default: return false, 0 } idx++ // Component 1: Must be UDP. if idx >= len(m) || m[idx].Code() != multiaddr.P_UDP { return false, 0 } idx++ // Component 2: Must be QUIC_V1. if idx >= len(m) || m[idx].Code() != multiaddr.P_QUIC_V1 { return false, 0 } idx++ // Optional component: SNI. if idx < len(m) && m[idx].Code() == multiaddr.P_SNI { idx++ } // Next component: Must be WEBTRANSPORT. if idx >= len(m) || m[idx].Code() != multiaddr.P_WEBTRANSPORT { return false, 0 } idx++ // All remaining components must be CERTHASH. for ; idx < len(m); idx++ { if m[idx].Code() != multiaddr.P_CERTHASH { return false, 0 } _ = m[idx].String() } return true, 0 } func BenchmarkIsWebTransportMultiaddrPrealloc(b *testing.B) { addr := multiaddr.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1/sni/example.com/webtransport") b.ResetTimer() for i := 0; i < b.N; i++ { isWT, count := IsWebTransportMultiaddrPrealloc(addr) if !isWT || count != 0 { b.Fatal("unexpected result") } } } func BenchmarkIsWebTransportMultiaddrNoCapturePrealloc(b *testing.B) { addr := multiaddr.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1/sni/example.com/webtransport") wtPreallocNoCapture := meg.PatternToMatcher( meg.Or( meg.Val(multiaddr.P_IP4), meg.Val(multiaddr.P_IP6), meg.Val(multiaddr.P_DNS4), meg.Val(multiaddr.P_DNS6), meg.Val(multiaddr.P_DNS), ), meg.Val(multiaddr.P_UDP), meg.Val(multiaddr.P_QUIC_V1), meg.Optional( meg.Val(multiaddr.P_SNI), ), meg.Val(multiaddr.P_WEBTRANSPORT), meg.ZeroOrMore(multiaddr.P_CERTHASH), ) b.ResetTimer() for i := 0; i < b.N; i++ { isWT, _ := meg.Match(wtPreallocNoCapture, componentList(addr)) if !isWT { b.Fatal("unexpected result") } } } func BenchmarkIsWebTransportMultiaddrNoCapture(b *testing.B) { addr := multiaddr.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1/sni/example.com/webtransport") b.ResetTimer() for i := 0; i < b.N; i++ { isWT, count := IsWebTransportMultiaddrNoCapture(addr) if !isWT || count != 0 { b.Fatal("unexpected result") } } } func BenchmarkIsWebTransportMultiaddrCaptureBytes(b *testing.B) { addr := multiaddr.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1/sni/example.com/webtransport") b.ResetTimer() for i := 0; i < b.N; i++ { isWT, count := IsWebTransportMultiaddrCaptureBytes(addr) if !isWT || count != 0 { b.Fatal("unexpected result") } } } func BenchmarkIsWebTransportMultiaddr(b *testing.B) { addr := multiaddr.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1/sni/example.com/webtransport") b.ResetTimer() for i := 0; i < b.N; i++ { isWT, count := IsWebTransportMultiaddr(addr) if !isWT || count != 0 { b.Fatal("unexpected result") } } } func BenchmarkIsWebTransportMultiaddrLoop(b *testing.B) { addr := multiaddr.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1/sni/example.com/webtransport") b.ResetTimer() for i := 0; i < b.N; i++ { isWT, count := IsWebTransportMultiaddrLoop(addr) if !isWT || count != 0 { b.Fatal("unexpected result") } } } func BenchmarkIsWebTransportMultiaddrLoopNoCapture(b *testing.B) { addr := multiaddr.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1/sni/example.com/webtransport") b.ResetTimer() for i := 0; i < b.N; i++ { isWT, count := IsWebTransportMultiaddrLoopNoCapture(addr) if !isWT || count != 0 { b.Fatal("unexpected result") } } } func BenchmarkIsWebRTCDirectMultiaddr(b *testing.B) { addr := multiaddr.StringCast("/ip4/1.2.3.4/udp/1234/webrtc-direct/") b.ResetTimer() for i := 0; i < b.N; i++ { isWebRTC, count := IsWebRTCDirectMultiaddr(addr) if !isWebRTC || count != 0 { b.Fatal("unexpected result") } } } func BenchmarkIsWebRTCDirectMultiaddrLoop(b *testing.B) { addr := multiaddr.StringCast("/ip4/1.2.3.4/udp/1234/webrtc-direct/") b.ResetTimer() for i := 0; i < b.N; i++ { isWebRTC, count := IsWebRTCDirectMultiaddrLoop(addr) if !isWebRTC || count != 0 { b.Fatal("unexpected result") } } } go-multiaddr-0.16.1/x/meg/meg.go000066400000000000000000000157551504514340500163230ustar00rootroot00000000000000// package meg implements Regular Expressions for multiaddr Components. It's short for "Megular Expressions" package meg // The developer is assumed to be familiar with the Thompson NFA approach to // regex before making changes to this file. Refer to // https://swtch.com/~rsc/regexp/regexp1.html for an introduction. import ( "fmt" ) type stateKind = int const ( matchAny stateKind = (iota * -1) - 1 // done MUST be the last stateKind in this list. // Anything that is less than done is a split index done ) // MatchState is the Thompson NFA for a regular expression. type MatchState struct { capture CaptureFunc // next is is the index of the next state. in the MatchState array. next int // If codeOrKind is negative, it is a kind. // If it is negative, and less than `done`, then it is the index to the next split. // This is done to keep the `MatchState` struct small and cache friendly. codeOrKind int } type CaptureFunc func(Matchable) error // capture is a linked list of capture funcs with values. type capture struct { f CaptureFunc v Matchable prev *capture } type statesAndCaptures struct { states []int captures []*capture } func (s MatchState) String() string { if s.codeOrKind == done { return "done" } if s.codeOrKind < done { return fmt.Sprintf("split{left: %d, right: %d}", s.next, decodeSplitIdx(s.codeOrKind)) } return fmt.Sprintf("match{code: %d, next: %d}", s.codeOrKind, s.next) } // Matchable is an interface for any thing that can be matched against by this // package. In the future, we may use multiaddr.Component types directly. type Matchable interface { Code() int // Value() returns the string representation of the matchable. Value() string // RawValue() returns the byte representation of the Value RawValue() []byte // Bytes() returns the underlying bytes of the matchable. For multiaddr // Components, this includes the protocol code and possibly the varint // encoded size. Bytes() []byte } // ListOfMatchable is anything list-like that contains Matchable items. // This allows us to convert a slice of []T as a []Matchable when *T implements // Matchable. In the future, this may not be required if Go generics allows us // to say S ~[]T, and *T implements Matchable. This may also not be required if // we move this out of its own package and depend on Multiaddr and Components // directly. type ListOfMatchable interface { Get(i int) Matchable Len() int } // Match returns whether the given Components match the Matcher // // Errors are used to communicate capture errors. // If the error is non-nil the returned bool will be false. // // Components must be a ListOfMatchable to allow us to use a slice of []T as a // []Matchable when *T implements Matchable. func Match[L ListOfMatchable](matcher Matcher, components L) (bool, error) { states := matcher.states startStateIdx := matcher.startIdx // Fast case for a small number of states (<128) // Avoids allocation of a slice for the visitedBitSet. stackBitSet := [2]uint64{} visitedBitSet := stackBitSet[:] if len(states) > 128 { visitedBitSet = make([]uint64, (len(states)+63)/64) } currentStates := statesAndCaptures{ states: make([]int, 0, 16), captures: make([]*capture, 0, 16), } nextStates := statesAndCaptures{ states: make([]int, 0, 16), captures: make([]*capture, 0, 16), } currentStates = appendState(currentStates, states, startStateIdx, nil, visitedBitSet) for ic := range components.Len() { clear(visitedBitSet) if len(currentStates.states) == 0 { return false, nil } for i, stateIndex := range currentStates.states { s := &states[stateIndex] cPtr := components.Get(ic) if s.codeOrKind == matchAny || (s.codeOrKind >= 0 && s.codeOrKind == cPtr.Code()) { cm := currentStates.captures[i] if s.capture != nil { next := &capture{ f: s.capture, v: cPtr, } if cm == nil { cm = next } else { next.prev = cm cm = next } currentStates.captures[i] = cm } nextStates = appendState(nextStates, states, s.next, cm, visitedBitSet) } } currentStates, nextStates = nextStates, currentStates nextStates.states = nextStates.states[:0] nextStates.captures = nextStates.captures[:0] } for i, stateIndex := range currentStates.states { s := &states[stateIndex] if s.codeOrKind == done { // We found a complete path. Run the captures now c := currentStates.captures[i] // Flip the order of the captures because we see captures from right // to left, but users expect them left to right. type captureWithVal struct { f CaptureFunc v Matchable } reversedCaptures := make([]captureWithVal, 0, 16) for c != nil { reversedCaptures = append(reversedCaptures, captureWithVal{c.f, c.v}) c = c.prev } for i := len(reversedCaptures) - 1; i >= 0; i-- { if err := reversedCaptures[i].f(reversedCaptures[i].v); err != nil { return false, err } } return true, nil } } return false, nil } // appendState is a non-recursive way of appending states to statesAndCaptures. // If a state is a split, both branches are appended to statesAndCaptures. func appendState(arr statesAndCaptures, states []MatchState, stateIndex int, c *capture, visitedBitSet []uint64) statesAndCaptures { // Local struct to hold state index and the associated capture pointer. type task struct { idx int cap *capture } // Initialize the stack with the starting task. stack := make([]task, 0, 16) stack = append(stack, task{stateIndex, c}) // Process the stack until empty. for len(stack) > 0 { // Pop the last element (LIFO order). n := len(stack) - 1 t := stack[n] stack = stack[:n] // If the state index is out of bounds, skip. if t.idx >= len(states) { continue } s := &states[t.idx] // Check if this state has already been visited. if visitedBitSet[t.idx/64]&(1<<(t.idx%64)) != 0 { continue } // Mark the state as visited. visitedBitSet[t.idx/64] |= 1 << (t.idx % 64) // If it's a split state (the value is less than done) then push both branches. if s.codeOrKind < done { // Get the second branch from the split. splitIdx := decodeSplitIdx(s.codeOrKind) // Check if the next branch is a `matchAny`. If it is, we want to // deprioritize it to allow for less greedy Any behavior. if states[s.next].codeOrKind == matchAny { // We want to process the non-matchAny first, so we push the s.next branch first stack = append(stack, task{s.next, t.cap}) stack = append(stack, task{splitIdx, t.cap}) } else { // To process s.next first, push the split branch first. stack = append(stack, task{splitIdx, t.cap}) stack = append(stack, task{s.next, t.cap}) } } else { // Otherwise, it's a valid final state -- append it. arr.states = append(arr.states, t.idx) arr.captures = append(arr.captures, t.cap) } } return arr } const splitIdxOffset = -(done - 1) func encodeSplitIdx(codeOrKind int) int { return (codeOrKind + splitIdxOffset) * -1 } func decodeSplitIdx(splitIdx int) int { return (splitIdx * -1) - splitIdxOffset } go-multiaddr-0.16.1/x/meg/meg_test.go000066400000000000000000000222571504514340500173550ustar00rootroot00000000000000package meg import ( "regexp" "slices" "testing" "testing/quick" ) type codeAndValue struct { code int val string // Uses the string type to ensure immutability. } // Code implements Matchable. func (c *codeAndValue) Code() int { return c.code } // Value implements Matchable. func (c *codeAndValue) Value() string { return c.val } // Bytes implements Matchable. func (c *codeAndValue) Bytes() []byte { return []byte(c.val) } // RawValue implements Matchable. func (c *codeAndValue) RawValue() []byte { return []byte(c.val) } var _ Matchable = &codeAndValue{} func TestSimple(t *testing.T) { type testCase struct { pattern Matcher skipQuickCheck bool shouldMatch [][]int shouldNotMatch [][]int } testCases := []testCase{ { pattern: PatternToMatcher(Val(Any), Val(1)), shouldMatch: [][]int{ {0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, }, shouldNotMatch: [][]int{ {0}, {0, 0}, {0, 1, 0}, }, skipQuickCheck: true, }, { pattern: PatternToMatcher(Val(0), Val(1)), shouldMatch: [][]int{{0, 1}}, shouldNotMatch: [][]int{ {0}, {0, 0}, {0, 1, 0}, }, }, { pattern: PatternToMatcher(Optional(Val(1))), shouldMatch: [][]int{ {1}, {}, }, shouldNotMatch: [][]int{{0}}, }, { pattern: PatternToMatcher(Val(0), Val(1), Optional(Val(2))), shouldMatch: [][]int{ {0, 1, 2}, {0, 1}, }, shouldNotMatch: [][]int{ {0}, {0, 0}, {0, 1, 0}, {0, 1, 2, 0}, }}, { pattern: PatternToMatcher(Val(0), Val(1), OneOrMore(2)), skipQuickCheck: true, shouldMatch: [][]int{ {0, 1, 2, 2, 2, 2}, {0, 1, 2}, }, shouldNotMatch: [][]int{ {0}, {0, 0}, {0, 1}, {0, 1, 0}, {0, 1, 1, 0}, {0, 1, 2, 0}, }}, { pattern: PatternToMatcher(Cat(Val(0), Val(1)), OneOrMore(2)), skipQuickCheck: true, shouldMatch: [][]int{ {0, 1, 2, 2, 2, 2}, {0, 1, 2}, }, shouldNotMatch: [][]int{ {0}, {0, 0}, {0, 1}, {0, 1, 0}, {0, 1, 1, 0}, {0, 1, 2, 0}, }}, { pattern: PatternToMatcher(Or(Val(0), Val(1)), OneOrMore(2)), skipQuickCheck: true, shouldMatch: [][]int{ {0, 2, 2, 2, 2}, {1, 2, 2, 2, 2}, {0, 2}, {1, 2}, }, shouldNotMatch: [][]int{ {0}, {1}, {0, 0}, {1, 0}, {0, 1}, {1, 1}, {0, 1, 0}, {1, 1, 0}, {0, 1, 1, 0}, {1, 1, 1, 0}, {0, 1, 2, 0}, {1, 1, 2, 0}, }}, { pattern: PatternToMatcher(Val(0), Val(1), OneOrMore(Any)), skipQuickCheck: true, shouldMatch: [][]int{ {0, 1, 2, 2, 2, 2}, {0, 1, 2}, {0, 1, 3, 4}, {0, 1, 0}, {0, 1, 1, 0}, {0, 1, 2, 0}, }, shouldNotMatch: [][]int{ {0}, {0, 0}, {0, 1}, {1, 0}, {1, 1}, }}, } for i, tc := range testCases { for _, m := range tc.shouldMatch { if matches, err := Match(tc.pattern, codesToCodeAndValue(m)); !matches { t.Fatalf("failed to match %v with %v. idx=%d. err=%v", m, tc.pattern, i, err) } } for _, m := range tc.shouldNotMatch { if matches, _ := Match(tc.pattern, codesToCodeAndValue(m)); matches { t.Fatalf("failed to not match %v with %v. idx=%d", m, tc.pattern, i) } } if tc.skipQuickCheck { continue } if err := quick.Check(func(notMatch []int) bool { for _, shouldMatch := range tc.shouldMatch { if slices.Equal(notMatch, shouldMatch) { // The random `notMatch` is actually something that shouldMatch. Skip it. return true } } matches, _ := Match(tc.pattern, codesToCodeAndValue(notMatch)) return !matches }, &quick.Config{}); err != nil { t.Fatal(err) } } } func TestCapture(t *testing.T) { type setupStateAndAssert func() (Matcher, func()) type testCase struct { setup setupStateAndAssert parts []codeAndValue } testCases := []testCase{ { setup: func() (Matcher, func()) { var code0str string return PatternToMatcher(CaptureString(0, &code0str), Val(1)), func() { if code0str != "hello" { panic("unexpected value") } } }, parts: []codeAndValue{{0, "hello"}, {1, "world"}}, }, { setup: func() (Matcher, func()) { var code0strs []string return PatternToMatcher(CaptureOneOrMoreStrings(0, &code0strs), Val(1)), func() { if code0strs[0] != "hello" { panic("unexpected value") } if code0strs[1] != "world" { panic("unexpected value") } } }, parts: []codeAndValue{{0, "hello"}, {0, "world"}, {1, ""}}, }, } _ = testCases for _, tc := range testCases { state, assert := tc.setup() if matches, _ := Match(state, codeAndValueList(tc.parts)); !matches { t.Fatalf("failed to match %v with %v", tc.parts, state) } assert() } } func TestPreferExactOverAny(t *testing.T) { t.Run("Optional", func(t *testing.T) { m := codeAndValueList{ {0, "hello"}, {1, "foo"}, {42, "A"}, {42, "B"}, } var lastParts []string found, _ := Match( PatternToMatcher( Optional(Val(Any)), Optional(Val(Any)), Optional(Val(Any)), CaptureOneOrMoreStrings(42, &lastParts), ), m, ) if !found { t.Fatal("failed to match") } if len(lastParts) != 2 { t.Fatal("Didn't capture all last parts") } }) t.Run("Or", func(t *testing.T) { m := codeAndValueList{ {1, "foo"}, {42, "A"}, {42, "B"}, } var lastParts []string found, _ := Match( PatternToMatcher( Or(Val(Any), Val(42)), Or(Val(Any), Val(42)), CaptureOneOrMoreStrings(42, &lastParts), ), m, ) if !found { t.Fatal("failed to match") } if len(lastParts) != 1 { t.Fatal("Didn't capture all last parts") } }) t.Run("OneOrMore", func(t *testing.T) { m := codeAndValueList{ {1, "foo"}, {42, "A"}, {42, "B"}, } var lastParts []string found, _ := Match( PatternToMatcher( OneOrMore(Any), CaptureOneOrMoreStrings(42, &lastParts), ), m, ) if !found { t.Fatal("failed to match") } if len(lastParts) != 2 { t.Fatal("Didn't capture all last parts") } }) } func TestCaptureWithAny(t *testing.T) { m := codeAndValueList{ {0, "hello"}, {1, "foo"}, {42, "A"}, {42, "B"}, } var lastParts []string found, _ := Match( PatternToMatcher( ZeroOrMore(Any), CaptureOneOrMoreStrings(42, &lastParts), ), m, ) if !found { t.Fatal("failed to match") } if len(lastParts) != 2 { t.Fatal("Didn't capture all last parts") } if lastParts[0] != "A" { t.Fatal("unexpected value. Expected", "A", "but got", lastParts[0]) } if lastParts[1] != "B" { t.Fatal("unexpected value. Expected", "B", "but got", lastParts[1]) } } type codeAndValueList []codeAndValue func (c codeAndValueList) Get(i int) Matchable { return &c[i] } func (c codeAndValueList) Len() int { return len(c) } func codesToCodeAndValue(codes []int) codeAndValueList { out := make([]codeAndValue, len(codes)) for i, c := range codes { out[i] = codeAndValue{code: c} } return out } func bytesToCodeAndValue(codes []byte) codeAndValueList { out := make([]codeAndValue, len(codes)) for i, c := range codes { out[i] = codeAndValue{code: int(c)} } return out } // FuzzMatchesRegexpBehavior fuzz tests the expression matcher by comparing it to the behavior of the regexp package. func FuzzMatchesRegexpBehavior(f *testing.F) { bytesToRegexpAndPattern := func(exp []byte) (string, []Pattern) { if len(exp) < 3 { panic("regexp too short") } pattern := make([]Pattern, 0, len(exp)-2) for i, b := range exp { b = b % 32 if i == 0 { exp[i] = '^' continue } else if i == len(exp)-1 { exp[i] = '$' continue } switch { case b < 26: exp[i] = b + 'a' pattern = append(pattern, Val(int(exp[i]))) case i > 1 && b == 26: exp[i] = '?' pattern = pattern[:len(pattern)-1] pattern = append(pattern, Optional(Val(int(exp[i-1])))) case i > 1 && b == 27: exp[i] = '*' pattern = pattern[:len(pattern)-1] pattern = append(pattern, ZeroOrMore(int(exp[i-1]))) case i > 1 && b == 28: exp[i] = '+' pattern = pattern[:len(pattern)-1] pattern = append(pattern, OneOrMore(int(exp[i-1]))) default: exp[i] = 'a' pattern = append(pattern, Val(int(exp[i]))) } } return string(exp), pattern } simplifyB := func(buf []byte) []byte { for i, b := range buf { buf[i] = (b % 26) + 'a' } return buf } f.Fuzz(func(t *testing.T, expRules []byte, corpus []byte) { if len(expRules) < 3 || len(expRules) > 1024 || len(corpus) > 1024 { return } corpus = simplifyB(corpus) regexpPattern, pattern := bytesToRegexpAndPattern(expRules) matched, err := regexp.Match(string(regexpPattern), corpus) if err != nil { // Malformed regex. Ignore return } p := PatternToMatcher(pattern...) otherMatched, _ := Match(p, bytesToCodeAndValue(corpus)) if otherMatched != matched { t.Log("regexp", string(regexpPattern)) t.Log("corpus", string(corpus)) m2, err2 := regexp.Match(string(regexpPattern), corpus) t.Logf("regexp matched %v. %v. %v, %v. \n%v - \n%v", matched, err, m2, err2, regexpPattern, corpus) t.Logf("pattern %+v", pattern) t.Fatalf("mismatched results: %v %v %v", otherMatched, matched, p) } }) } go-multiaddr-0.16.1/x/meg/sugar.go000066400000000000000000000142621504514340500166640ustar00rootroot00000000000000package meg import ( "errors" "fmt" "strconv" "strings" ) // Pattern is a curried MatchState. Given the slice of current MatchStates and a // handle (int index) to the next MatchState, it returns a (possibly modified) // slice of next MatchStates and handle to the inserted MatchState. type Pattern = func(states []MatchState, nextIdx int) ([]MatchState, int) // Matcher holds a graph of match state nodes. Use PatternToMatcher to create. type Matcher struct { states []MatchState startIdx int } func (s Matcher) String() string { states := make([]string, len(s.states)) for i, state := range s.states { states[i] = state.String() + "@" + strconv.Itoa(i) } return fmt.Sprintf("RootMatchState{states: [%s], startIdx: %d}", strings.Join(states, ", "), s.startIdx) } func PatternToMatcher(patterns ...Pattern) Matcher { // Preallocate a slice to hold the MatchStates. // Avoids small allocations for each pattern. // The number is chosen experimentally. It is subject to change. states := make([]MatchState, 0, len(patterns)*3) // Append the done state. states = append(states, MatchState{codeOrKind: done}) nextIdx := len(states) - 1 // Build the chain by composing patterns from right to left. for i := len(patterns) - 1; i >= 0; i-- { states, nextIdx = patterns[i](states, nextIdx) } return Matcher{states: states, startIdx: nextIdx} } func Cat(patterns ...Pattern) Pattern { switch len(patterns) { case 0: return func(states []MatchState, nextIdx int) ([]MatchState, int) { return states, nextIdx } case 1: return patterns[0] case 2: return func(states []MatchState, nextIdx int) ([]MatchState, int) { left := patterns[0] right := patterns[1] // First run the right pattern, then feed the result into left. states, nextIdx = right(states, nextIdx) return left(states, nextIdx) } default: return Cat( Cat(patterns[:len(patterns)-1]...), patterns[len(patterns)-1], ) } } func Or(p ...Pattern) Pattern { return func(states []MatchState, nextIdx int) ([]MatchState, int) { if len(p) == 0 { return states, nextIdx } // Evaluate the last pattern and use its result as the initial accumulator. states, accum := p[len(p)-1](states, nextIdx) // Iterate backwards from the second-to-last pattern to the first. for i := len(p) - 2; i >= 0; i-- { var leftIdx int states, leftIdx = p[i](states, nextIdx) newState := MatchState{ next: leftIdx, codeOrKind: encodeSplitIdx(accum), } states = append(states, newState) accum = len(states) - 1 } return states, accum } } var errAlreadyCapture = errors.New("already captured") func captureOneBytesOrErr(val *[]byte) CaptureFunc { if val == nil { return nil } var set bool f := func(s Matchable) error { if set { *val = nil return errAlreadyCapture } *val = s.RawValue() return nil } return f } func captureOneStringValueOrErr(val *string) CaptureFunc { if val == nil { return nil } var set bool f := func(s Matchable) error { if set { *val = "" return errAlreadyCapture } *val = s.Value() return nil } return f } func captureManyBytes(vals *[][]byte) CaptureFunc { if vals == nil { return nil } f := func(s Matchable) error { *vals = append(*vals, s.RawValue()) return nil } return f } func captureManyStrings(vals *[]string) CaptureFunc { if vals == nil { return nil } f := func(s Matchable) error { *vals = append(*vals, s.Value()) return nil } return f } func CaptureWithF(code int, f CaptureFunc) Pattern { return func(states []MatchState, nextIdx int) ([]MatchState, int) { newState := MatchState{ capture: f, codeOrKind: code, next: nextIdx, } states = append(states, newState) return states, len(states) - 1 } } func Val(code int) Pattern { return CaptureString(code, nil) } // Any is a special code that matches any value. var Any int = matchAny func CaptureString(code int, val *string) Pattern { return CaptureWithF(code, captureOneStringValueOrErr(val)) } func CaptureBytes(code int, val *[]byte) Pattern { return CaptureWithF(code, captureOneBytesOrErr(val)) } func ZeroOrMore(code int) Pattern { return CaptureZeroOrMoreStrings(code, nil) } func CaptureZeroOrMoreWithF(code int, f CaptureFunc) Pattern { return func(states []MatchState, nextIdx int) ([]MatchState, int) { // Create the match state. matchState := MatchState{ codeOrKind: code, capture: f, } states = append(states, matchState) matchIdx := len(states) - 1 // Create the split state that branches to the match state and to the next state. s := MatchState{ next: matchIdx, codeOrKind: encodeSplitIdx(nextIdx), } states = append(states, s) splitIdx := len(states) - 1 // Close the loop: update the match state's next field. states[matchIdx].next = splitIdx return states, splitIdx } } func CaptureZeroOrMoreBytes(code int, vals *[][]byte) Pattern { return CaptureZeroOrMoreWithF(code, captureManyBytes(vals)) } func CaptureZeroOrMoreStrings(code int, vals *[]string) Pattern { return CaptureZeroOrMoreWithF(code, captureManyStrings(vals)) } func OneOrMore(code int) Pattern { return CaptureOneOrMoreStrings(code, nil) } func CaptureOneOrMoreStrings(code int, vals *[]string) Pattern { f := captureManyStrings(vals) return func(states []MatchState, nextIdx int) ([]MatchState, int) { // First attach the zero-or-more loop. states, zeroOrMoreIdx := CaptureZeroOrMoreWithF(code, f)(states, nextIdx) // Then put the capture state before the loop. return CaptureWithF(code, f)(states, zeroOrMoreIdx) } } func CaptureOneOrMoreBytes(code int, vals *[][]byte) Pattern { f := captureManyBytes(vals) return func(states []MatchState, nextIdx int) ([]MatchState, int) { // First attach the zero-or-more loop. states, zeroOrMoreIdx := CaptureZeroOrMoreWithF(code, f)(states, nextIdx) // Then put the capture state before the loop. return CaptureWithF(code, f)(states, zeroOrMoreIdx) } } func Optional(s Pattern) Pattern { return func(states []MatchState, nextIdx int) ([]MatchState, int) { states, patternIdx := s(states, nextIdx) newState := MatchState{ next: patternIdx, codeOrKind: encodeSplitIdx(nextIdx), } states = append(states, newState) return states, len(states) - 1 } } go-multiaddr-0.16.1/x/meg/testdata/000077500000000000000000000000001504514340500170205ustar00rootroot00000000000000go-multiaddr-0.16.1/x/meg/testdata/fuzz/000077500000000000000000000000001504514340500200165ustar00rootroot00000000000000go-multiaddr-0.16.1/x/meg/testdata/fuzz/FuzzMatchesRegexpBehavior/000077500000000000000000000000001504514340500251145ustar00rootroot00000000000000go-multiaddr-0.16.1/x/meg/testdata/fuzz/FuzzMatchesRegexpBehavior/1e98195527a61d9c000066400000000000000000000000521504514340500271270ustar00rootroot00000000000000go test fuzz v1 []byte("^c?") []byte("o") go-multiaddr-0.16.1/x/meg/testdata/fuzz/FuzzMatchesRegexpBehavior/a92659f6360052e5000066400000000000000000000000471504514340500270450ustar00rootroot00000000000000go test fuzz v1 []byte("") []byte("w") go-multiaddr-0.16.1/x/meg/testdata/fuzz/FuzzMatchesRegexpBehavior/b02eb19d06b02202000066400000000000000000000000531504514340500271430ustar00rootroot00000000000000go test fuzz v1 []byte("^zy") []byte("p ") go-multiaddr-0.16.1/x/meg/testdata/fuzz/FuzzMatchesRegexpBehavior/b3cb6a0a30c58d03000066400000000000000000000000531504514340500273100ustar00rootroot00000000000000go test fuzz v1 []byte("^b?") []byte("pw") go-multiaddr-0.16.1/x/meg/testdata/fuzz/FuzzMatchesRegexpBehavior/b9eb3d27681dd876000066400000000000000000000001001504514340500272630ustar00rootroot00000000000000go test fuzz v1 []byte("^b:") []byte("^b:MMMMMMMMMMMMMMMMMMpw") go-multiaddr-0.16.1/x/meg/testdata/fuzz/FuzzMatchesRegexpBehavior/f8e3578130e7a246000066400000000000000000000002141504514340500271220ustar00rootroot00000000000000go test fuzz v1 []byte("gw\xa6%\xc5\xc7kD\xdf\x14_\xebק\xd8H\xcf0\xcf~/\xf9\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\xd5{1\x98ױ\x841(") []byte("")