github.com/sagernet/quic-go@v0.43.1-beta.1/internal/protocol/connection_id.go (about)

     1  package protocol
     2  
     3  import (
     4  	"crypto/rand"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  )
     9  
    10  var ErrInvalidConnectionIDLen = errors.New("invalid Connection ID length")
    11  
    12  // An ArbitraryLenConnectionID is a QUIC Connection ID able to represent Connection IDs according to RFC 8999.
    13  // Future QUIC versions might allow connection ID lengths up to 255 bytes, while QUIC v1
    14  // restricts the length to 20 bytes.
    15  type ArbitraryLenConnectionID []byte
    16  
    17  func (c ArbitraryLenConnectionID) Len() int {
    18  	return len(c)
    19  }
    20  
    21  func (c ArbitraryLenConnectionID) Bytes() []byte {
    22  	return c
    23  }
    24  
    25  func (c ArbitraryLenConnectionID) String() string {
    26  	if c.Len() == 0 {
    27  		return "(empty)"
    28  	}
    29  	return fmt.Sprintf("%x", c.Bytes())
    30  }
    31  
    32  const maxConnectionIDLen = 20
    33  
    34  // A ConnectionID in QUIC
    35  type ConnectionID struct {
    36  	b [20]byte
    37  	l uint8
    38  }
    39  
    40  // GenerateConnectionID generates a connection ID using cryptographic random
    41  func GenerateConnectionID(l int) (ConnectionID, error) {
    42  	var c ConnectionID
    43  	c.l = uint8(l)
    44  	_, err := rand.Read(c.b[:l])
    45  	return c, err
    46  }
    47  
    48  // ParseConnectionID interprets b as a Connection ID.
    49  // It panics if b is longer than 20 bytes.
    50  func ParseConnectionID(b []byte) ConnectionID {
    51  	if len(b) > maxConnectionIDLen {
    52  		panic("invalid conn id length")
    53  	}
    54  	var c ConnectionID
    55  	c.l = uint8(len(b))
    56  	copy(c.b[:c.l], b)
    57  	return c
    58  }
    59  
    60  // GenerateConnectionIDForInitial generates a connection ID for the Initial packet.
    61  // It uses a length randomly chosen between 8 and 20 bytes.
    62  func GenerateConnectionIDForInitial() (ConnectionID, error) {
    63  	r := make([]byte, 1)
    64  	if _, err := rand.Read(r); err != nil {
    65  		return ConnectionID{}, err
    66  	}
    67  	l := MinConnectionIDLenInitial + int(r[0])%(maxConnectionIDLen-MinConnectionIDLenInitial+1)
    68  	return GenerateConnectionID(l)
    69  }
    70  
    71  // ReadConnectionID reads a connection ID of length len from the given io.Reader.
    72  // It returns io.EOF if there are not enough bytes to read.
    73  func ReadConnectionID(r io.Reader, l int) (ConnectionID, error) {
    74  	var c ConnectionID
    75  	if l == 0 {
    76  		return c, nil
    77  	}
    78  	if l > maxConnectionIDLen {
    79  		return c, ErrInvalidConnectionIDLen
    80  	}
    81  	c.l = uint8(l)
    82  	_, err := io.ReadFull(r, c.b[:l])
    83  	if err == io.ErrUnexpectedEOF {
    84  		return c, io.EOF
    85  	}
    86  	return c, err
    87  }
    88  
    89  // Len returns the length of the connection ID in bytes
    90  func (c ConnectionID) Len() int {
    91  	return int(c.l)
    92  }
    93  
    94  // Bytes returns the byte representation
    95  func (c ConnectionID) Bytes() []byte {
    96  	return c.b[:c.l]
    97  }
    98  
    99  func (c ConnectionID) String() string {
   100  	if c.Len() == 0 {
   101  		return "(empty)"
   102  	}
   103  	return fmt.Sprintf("%x", c.Bytes())
   104  }
   105  
   106  type DefaultConnectionIDGenerator struct {
   107  	ConnLen int
   108  }
   109  
   110  func (d *DefaultConnectionIDGenerator) GenerateConnectionID() (ConnectionID, error) {
   111  	return GenerateConnectionID(d.ConnLen)
   112  }
   113  
   114  func (d *DefaultConnectionIDGenerator) ConnectionIDLen() int {
   115  	return d.ConnLen
   116  }