-
Notifications
You must be signed in to change notification settings - Fork 1
/
model.go
205 lines (167 loc) · 6.4 KB
/
model.go
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package netem
//
// Data model
//
import (
"context"
"crypto/tls"
"crypto/x509"
"net"
"syscall"
"time"
)
const (
// FrameFlagSpoof tells the router it should send the
// spoofed frames inside the [Frame] Spoofed field.
FrameFlagSpoof = 1 << iota
// FrameFlagDrop tells the link that the frame should be
// dropped rather than forwarded, to emulate a loss occurring
// on the link while the frame was in flight.
FrameFlagDrop
)
// CertificationAuthority is a TLS certification authority.
type CertificationAuthority interface {
// CACert returns the CA certificate used by the server, which
// allows you to add to an existing [*x509.CertPool].
CACert() *x509.Certificate
// DefaultCertPool returns the default cert pool to use.
DefaultCertPool() *x509.CertPool
// MustNewServerTLSConfig constructs a server certificate for
// the given common name and extra names, all of which could be
// either IPv4/IPv6 addresses or domain names.
MustNewServerTLSConfig(commonName string, extraNames ...string) *tls.Config
// MustNewTLSCertificate constructs a TLS certificate for
// the given common name and extra names, all of which could be
// either IPv4/IPv6 addresses or domain names.
MustNewTLSCertificate(commonName string, extraNames ...string) *tls.Certificate
// MustNewTLSCertificateWithTimeNow is like MustNewTLSCertificate
// but takes as input an explicit [time.Now] like func.
MustNewTLSCertificateWithTimeNow(timeNow func() time.Time,
commonName string, extraNames ...string) *tls.Certificate
}
// Frame contains an IPv4 or IPv6 packet.
type Frame struct {
// Deadline is the time when this frame should be delivered.
Deadline time.Time
// Flags contains additional flags that [Router] will interpret
// when processing this [Frame].
Flags int64
// Payload contains the packet payload.
Payload []byte
// Spoofed contains zero or more packets that the router should
// spoof when processing this packet. We honor this field iff the
// FrameFlagSpoof flag is set in the Flags field.
Spoofed [][]byte
}
// NewFrame constructs a [Frame] for the given [Payload].
func NewFrame(payload []byte) *Frame {
return &Frame{
Deadline: time.Now(),
Flags: 0,
Payload: payload,
Spoofed: nil,
}
}
// ShallowCopy creates a shallow copy of the [Frame] allowing
// us to modify its [Deadline] without data races risks.
func (f *Frame) ShallowCopy() *Frame {
return &Frame{
Deadline: f.Deadline,
Flags: f.Flags,
Payload: f.Payload,
Spoofed: f.Spoofed,
}
}
// FrameReader allows one to read incoming frames.
type FrameReader interface {
// FrameAvailable returns a channel that becomes readable
// when a new frame has arrived.
FrameAvailable() <-chan any
// ReadFrameNonblocking reads an incoming frame. You should only call
// this function after FrameAvailable has been readable. This function
// returns one of the following errors:
//
// - ErrStackClosed if the underlying stack has been closed;
//
// - ErrNoPacket if no packet is available.
//
// Callers should ignore ErrNoPacket and try reading again later.
ReadFrameNonblocking() (*Frame, error)
// StackClosed returns a channel that becomes readable when the
// userspace network stack has been closed.
StackClosed() <-chan any
}
// Logger is the logger we're using.
type Logger interface {
// Debugf formats and emits a debug message.
Debugf(format string, v ...any)
// Debug emits a debug message.
Debug(message string)
// Infof formats and emits an informational message.
Infof(format string, v ...any)
// Info emits an informational message.
Info(message string)
// Warnf formats and emits a warning message.
Warnf(format string, v ...any)
// Warn emits a warning message.
Warn(message string)
}
// NIC is a network interface card with which you can send and receive [Frame]s.
type NIC interface {
// A NIC implements FrameReader
FrameReader
// Close closes this network interface.
Close() error
// IPAddress returns the IP address assigned to the NIC.
IPAddress() string
// InterfaceName returns the name of the NIC.
InterfaceName() string
// WriteFrame writes a frame or returns an error. This function
// returns ErrStackClosed when the underlying stack has been closed.
WriteFrame(frame *Frame) error
}
// UDPLikeConn is a net.PacketConn with some extra functions
// required to convince the QUIC library (lucas-clemente/quic-go)
// to inflate the receive buffer of the connection.
//
// The QUIC library will treat this connection as a "dumb"
// net.PacketConn, calling its ReadFrom and WriteTo methods
// as opposed to more efficient methods that are available
// under Linux and (maybe?) FreeBSD.
//
// It seems fine to avoid performance optimizations, because
// they would complicate the implementation on our side and
// our use cases (blocking and heavy throttling) do not seem
// to require such optimizations.
//
// See https://github.com/ooni/probe/issues/1754 for a more
// comprehensive discussion of UDPLikeConn.
type UDPLikeConn interface {
// An UDPLikeConn is a net.PacketConn conn.
net.PacketConn
// SetReadBuffer allows setting the read buffer.
SetReadBuffer(bytes int) error
// SyscallConn returns a conn suitable for calling syscalls,
// which is also instrumental to setting the read buffer.
SyscallConn() (syscall.RawConn, error)
}
// UnderlyingNetwork replaces for functions in the [net] package.
type UnderlyingNetwork interface {
// CertificationAuthority allows accessing the certification authority
// associated with this host or set of hosts.
CertificationAuthority
// DialContext dials a TCP or UDP connection. Unlike [net.DialContext], this
// function does not implement dialing when address contains a domain.
DialContext(ctx context.Context, network, address string) (net.Conn, error)
// GetaddrinfoLookupANY is like [net.Resolver.LookupHost] except that it
// also returns to the caller the CNAME when it is available.
GetaddrinfoLookupANY(ctx context.Context, domain string) ([]string, string, error)
// GetaddrinfoResolverNetwork returns the resolver network.
GetaddrinfoResolverNetwork() string
// ListenTCP creates a new listening TCP socket.
ListenTCP(network string, addr *net.TCPAddr) (net.Listener, error)
// ListenUDP creates a new listening UDP socket. The [UDPLikeConn] returned
// by this function is a best effort attempt to emulate a [net.UDPConn] that
// works with the github.com/lucas-clemente/quic-go library.
ListenUDP(network string, addr *net.UDPAddr) (UDPLikeConn, error)
}