summaryrefslogtreecommitdiffhomepage
path: root/net/packet/header.go
blob: 44b99e520d71785d5e40355459725740f279a678 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause

package packet

import (
	"errors"
	"math"
)

const igmpHeaderLength = 8
const tcpHeaderLength = 20
const sctpHeaderLength = 12

// maxPacketLength is the largest length that all headers support.
// IPv4 headers using uint16 for this forces an upper bound of 64KB.
const maxPacketLength = math.MaxUint16

var (
	// errSmallBuffer is returned when Marshal receives a buffer
	// too small to contain the header to marshal.
	errSmallBuffer = errors.New("buffer too small")
	// errLargePacket is returned when Marshal receives a payload
	// larger than the maximum representable size in header
	// fields.
	errLargePacket = errors.New("packet too large")
)

// Header is a packet header capable of marshaling itself into a byte
// buffer.
type Header interface {
	// Len returns the length of the marshaled packet.
	Len() int
	// Marshal serializes the header into buf, which must be at
	// least Len() bytes long. Implementations of Marshal assume
	// that bytes after the first Len() are payload bytes for the
	// purpose of computing length and checksum fields. Marshal
	// implementations must not allocate memory.
	Marshal(buf []byte) error
}

// HeaderChecksummer is implemented by Header implementations that
// need to do a checksum over their payloads.
type HeaderChecksummer interface {
	Header

	// WriteCheck writes the correct checksum into buf, which should
	// be be the already-marshalled header and payload.
	WriteChecksum(buf []byte)
}

// Generate generates a new packet with the given Header and
// payload. This function allocates memory, see Header.Marshal for an
// allocation-free option.
func Generate(h Header, payload []byte) []byte {
	hlen := h.Len()
	buf := make([]byte, hlen+len(payload))

	copy(buf[hlen:], payload)
	h.Marshal(buf)

	if hc, ok := h.(HeaderChecksummer); ok {
		hc.WriteChecksum(buf)
	}

	return buf
}