github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/wire/netaddress.go (about)

     1  // Copyright (c) 2013-2015 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wire
     6  
     7  import (
     8  	"encoding/binary"
     9  	"errors"
    10  	"io"
    11  	"net"
    12  	"time"
    13  )
    14  
    15  // ErrInvalidNetAddr describes an error that indicates the caller didn't specify
    16  // a TCP address as required.
    17  var ErrInvalidNetAddr = errors.New("provided net.Addr is not a net.TCPAddr")
    18  
    19  // maxNetAddressPayload returns the max payload size for a bitcoin NetAddress
    20  // based on the protocol version.
    21  func maxNetAddressPayload(pver uint32) uint32 {
    22  	// Services 8 bytes + ip 16 bytes + port 2 bytes.
    23  	plen := uint32(26)
    24  
    25  	// NetAddressTimeVersion added a timestamp field.
    26  	if pver >= NetAddressTimeVersion {
    27  		// Timestamp 4 bytes.
    28  		plen += 4
    29  	}
    30  
    31  	return plen
    32  }
    33  
    34  // NetAddress defines information about a peer on the network including the time
    35  // it was last seen, the services it supports, its IP address, and port.
    36  type NetAddress struct {
    37  	// Last time the address was seen.  This is, unfortunately, encoded as a
    38  	// uint32 on the wire and therefore is limited to 2106.  This field is
    39  	// not present in the bitcoin version message (MsgVersion) nor was it
    40  	// added until protocol version >= NetAddressTimeVersion.
    41  	Timestamp time.Time
    42  
    43  	// Bitfield which identifies the services supported by the address.
    44  	Services ServiceFlag
    45  
    46  	// IP address of the peer.
    47  	IP net.IP
    48  
    49  	// Port the peer is using.  This is encoded in big endian on the wire
    50  	// which differs from most everything else.
    51  	Port uint16
    52  }
    53  
    54  // HasService returns whether the specified service is supported by the address.
    55  func (na *NetAddress) HasService(service ServiceFlag) bool {
    56  	if na.Services&service == service {
    57  		return true
    58  	}
    59  	return false
    60  }
    61  
    62  // AddService adds service as a supported service by the peer generating the
    63  // message.
    64  func (na *NetAddress) AddService(service ServiceFlag) {
    65  	na.Services |= service
    66  }
    67  
    68  // SetAddress is a convenience function to set the IP address and port in one
    69  // call.
    70  func (na *NetAddress) SetAddress(ip net.IP, port uint16) {
    71  	na.IP = ip
    72  	na.Port = port
    73  }
    74  
    75  // NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and
    76  // supported services with defaults for the remaining fields.
    77  func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress {
    78  	// Limit the timestamp to one second precision since the protocol
    79  	// doesn't support better.
    80  	na := NetAddress{
    81  		Timestamp: time.Unix(time.Now().Unix(), 0),
    82  		Services:  services,
    83  		IP:        ip,
    84  		Port:      port,
    85  	}
    86  	return &na
    87  }
    88  
    89  // NewNetAddress returns a new NetAddress using the provided TCP address and
    90  // supported services with defaults for the remaining fields.
    91  //
    92  // Note that addr must be a net.TCPAddr.  An ErrInvalidNetAddr is returned
    93  // if it is not.
    94  func NewNetAddress(addr net.Addr, services ServiceFlag) (*NetAddress, error) {
    95  	tcpAddr, ok := addr.(*net.TCPAddr)
    96  	if !ok {
    97  		return nil, ErrInvalidNetAddr
    98  	}
    99  
   100  	na := NewNetAddressIPPort(tcpAddr.IP, uint16(tcpAddr.Port), services)
   101  	return na, nil
   102  }
   103  
   104  // readNetAddress reads an encoded NetAddress from r depending on the protocol
   105  // version and whether or not the timestamp is included per ts.  Some messages
   106  // like version do not include the timestamp.
   107  func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error {
   108  	var services ServiceFlag
   109  	var ip [16]byte
   110  
   111  	// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
   112  	// stop working somewhere around 2106.  Also timestamp wasn't added until
   113  	// protocol version >= NetAddressTimeVersion
   114  	if ts && pver >= NetAddressTimeVersion {
   115  		err := readElement(r, (*uint32Time)(&na.Timestamp))
   116  		if err != nil {
   117  			return err
   118  		}
   119  	}
   120  
   121  	err := readElements(r, &services, &ip)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	// Sigh.  Bitcoin protocol mixes little and big endian.
   126  	port, err := binarySerializer.Uint16(r, bigEndian)
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	na.Services = services
   132  	na.SetAddress(net.IP(ip[:]), port)
   133  	return nil
   134  }
   135  
   136  // writeNetAddress serializes a NetAddress to w depending on the protocol
   137  // version and whether or not the timestamp is included per ts.  Some messages
   138  // like version do not include the timestamp.
   139  func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error {
   140  	// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
   141  	// stop working somewhere around 2106.  Also timestamp wasn't added until
   142  	// until protocol version >= NetAddressTimeVersion.
   143  	if ts && pver >= NetAddressTimeVersion {
   144  		err := writeElement(w, uint32(na.Timestamp.Unix()))
   145  		if err != nil {
   146  			return err
   147  		}
   148  	}
   149  
   150  	// Ensure to always write 16 bytes even if the ip is nil.
   151  	var ip [16]byte
   152  	if na.IP != nil {
   153  		copy(ip[:], na.IP.To16())
   154  	}
   155  	err := writeElements(w, na.Services, ip)
   156  	if err != nil {
   157  		return err
   158  	}
   159  
   160  	// Sigh.  Bitcoin protocol mixes little and big endian.
   161  	err = binary.Write(w, bigEndian, na.Port)
   162  	if err != nil {
   163  		return err
   164  	}
   165  
   166  	return nil
   167  }