go-multiaddr

repository·master·Indexed 43 days ago

https://github.com/multiformats/go-multiaddr

A Go implementation of the multiaddr standard providing a self-describing, binary-packed, and string-representable way to encode network addresses and protocols. It supports protocol encapsulation, decapsulation, and IP address filtering via the Filters struct and Action enum.

Tokens
7.3K
Snippets
27
Records
43
Agent score
55%

What's inside go-multiaddr

  1. Encapsulate and Decapsulate Multiaddr protocols

    master

    Multiaddr supports nesting protocols through encapsulation and stripping them through decapsulation:

    • Encapsulate: Use m.Encapsulate(subaddr) to append a sub-address to the existing address, effectively wrapping the original address in a new protocol layer.
    • Decapsulate: Use m.Decapsulate(subaddr) to remove a specific protocol layer. This removes the specified sub-address and any subsequent protocols in the chain.
    import ma "github.com/multiformats/go-multiaddr"
    
    m, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
    
    sctpMA, err := ma.NewMultiaddr("/sctp/5678")
    
    // Encapsulate: adds /sctp/5678 to the end
    m.Encapsulate(sctpMA)
    // Result: <Multiaddr /ip4/127.0.0.1/udp/1234/sctp/5678>
    
    udpMA, err := ma.NewMultiaddr("/udp/1234")
    
    // Decapsulate: removes /udp/1234 and everything after it
    m.Decapsulate(udpMA) 
    // Result: <Multiaddr /ip4/127.0.0.1>
  2. Optimize Multiaddr manipulation in v0.15

    master

    To improve performance and safety when working with Multiaddr in v0.15, follow these patterns:

    • Appending Components:
      • Use Multiaddr.AppendComponent(*Component) when appending a component. This method performs a nil pointer check on the component before appending.
      • If you are certain the *Component is not nil, you can use the standard Go append function directly.
    • Joining Multiaddrs: To join two Multiaddr instances, use the standard Go append function. This is significantly faster than Encapsulate or Join because it avoids defensive copying.
    • Iteration: Since Multiaddr is a slice of Component, you can use standard Go for range loops to iterate over its elements.

    Performance Note: Be aware that Multiaddr.Bytes() is now an O(n) operation (where n is the number of components), whereas it was previously O(1).

  3. Migrate to go-multiaddr v0.15

    master

    The v0.15 refactor introduces several breaking changes due to Multiaddr changing from an interface to a concrete type. Key changes include:

    • Type Change: Multiaddr is now a concrete type (specifically a []Component), not an interface. Consequently, there is no Multiaddr interface type, and Components no longer implement a Multiaddr interface.
    • Nil Checks: Instead of checking for nil (e.g., addr == nil), use the .Empty() method to check if a Multiaddr or Component is empty. This follows the pattern of checking slice length rather than nil status.
    • Map Keys: Multiaddr can no longer be used directly as a key in a Map. To use a Multiaddr as a key for uniqueness, use its string representation via .String(). Alternatively, you can use the pointer value *Multiaddr as a key.
  4. Use the Transcoder interface to convert multiaddr components

    master

    The Transcoder interface provides a standard way to convert between the string representation and the byte representation of specific multiaddr components (like IP addresses, ports, or onion addresses). This is useful when parsing or constructing multiaddrs where individual protocol parameters need to be serialized or deserialized.

    It defines three methods:

    • StringToBytes(string) ([]byte, error): Validates and encodes a string into its byte representation.
    • BytesToString([]byte) (string, error): Validates and decodes bytes into their string representation.
    • ValidateBytes([]byte) error: Validates that a byte slice is a correct representation for that component.
    type Transcoder interface {
    	StringToBytes(string) ([]byte, error)
    	BytesToString([]byte) (string, error)
    	ValidateBytes([]byte) error
    }
  5. Create and compare Multiaddr instances

    master

    You can create a Multiaddr from a string representation using ma.NewMultiaddr or from raw bytes using ma.NewMultiaddrBytes. Both methods return an error if the input is invalid. To compare two Multiaddr instances, use the .Equal() method or compare their string/byte representations.

    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())
    
    // Comparison
    m1.Equal(m2)
  6. Express network tunneling with Multiaddr

    master

    Multiaddr can represent complex tunneling scenarios by encapsulating a target address within a proxy address. This allows you to express that a connection to a specific endpoint is being routed through a proxy.

    // Target: printer at 192.168.0.13:80
    printer, _ := ma.NewMultiaddr("/ip4/192.168.0.13/tcp/80")
    
    // Proxy: proxy at 10.20.30.40:443
    proxy, _ := ma.NewMultiaddr("/ip4/10.20.30.40/tcp/443")
    
    // Tunnel: printer over proxy
    printerOverProxy := proxy.Encapsulate(printer)
    // Result: /ip4/10.20.30.40/tcp/443/ip4/192.168.0.13/tcp/80
    
    // Recover original target by decapsulating the printer protocol
    proxyAgain := printerOverProxy.Decapsulate(printer)
    // Result: /ip4/10.20.30.40/tcp/443
  7. Inspect Multiaddr protocols

    master

    Use the .Protocols() method to retrieve a list of Protocol description objects contained within a Multiaddr. Each Protocol object includes the protocol's Code, Name, and Size.

    // get the multiaddr protocol description objects
    m1.Protocols()
    // Returns: []Protocol{
    //   Protocol{ Code: 4, Name: "ip4", Size: 32},
    //   Protocol{ Code: 17, Name: "udp", Size: 16},
    // }
  8. Transcode Tor Onion v3 addresses

    master

    The TranscoderOnion3 handles Tor Onion v3 addresses. It expects a string in the format address:port (where address is the 56-character base32 encoded onion name). The resulting byte slice is 37 bytes long: 35 bytes for the host and 2 bytes for the big-endian port.

    // Example usage of TranscoderOnion3
    // Note: This is a conceptual usage based on the API
    bytes, err := multiaddr.TranscoderOnion3.StringToBytes("v2c7...onion:8080")
    str, err := multiaddr.TranscoderOnion3.BytesToString(bytes)
  9. Access Component data and properties

    master

    The Component type provides several methods to inspect its contents:

    • Code() int: Returns the integer protocol code.
    • Protocol() Protocol: Returns the Protocol object associated with this component.
    • Value() string: Returns the string representation of the component's value (e.g., "127.0.0.1" for an ip4 component).
    • RawValue() []byte: Returns the raw bytes of the component's value.
    • Bytes() []byte: Returns the full raw bytes of the component, including the protocol code and value.
    • String() string: Returns the string representation of the component (e.g., "/ip4/127.0.0.1").
    • Protocols() []Protocol: Returns a slice containing the single Protocol used by this component.
  10. Compare Components

    master

    To check if two Component instances are identical, use the Equal or Compare methods:

    • Equal(o *Component) bool: Returns true if both components are identical (including nil checks).
    • Compare(o *Component) int: Returns 0 if equal, -1 if the receiver is nil, 1 if the argument is nil, or uses string comparison on the underlying bytes for other cases.