-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdpithrottle.go
More file actions
166 lines (136 loc) · 3.86 KB
/
Copy pathdpithrottle.go
File metadata and controls
166 lines (136 loc) · 3.86 KB
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
package netem
//
// DPI: rules to throttle flows
//
import (
"time"
"github.com/google/gopacket/layers"
)
// DPIThrottleTrafficForTLSSNI is a [DPIRule] that throttles traffic
// after it sees a given TLS SNI. The zero value is not valid. Make sure
// you initialize all fields marked as MANDATORY.
type DPIThrottleTrafficForTLSSNI struct {
// Delay is the OPTIONAL extra delay to add to the flow.
Delay time.Duration
// Logger is the MANDATORY logger to use.
Logger Logger
// PLR is the OPTIONAL extra packet loss rate to apply to the packet.
PLR float64
// SNI is the OPTIONAL offending SNI
SNI string
// TLSHandshake
TLSHandshake []byte
// TLSHandshakeSize
TlSHandshakeSize uint16
// done
done bool
}
var _ DPIRule = &DPIThrottleTrafficForTLSSNI{}
// Filter implements DPIRule
func (r *DPIThrottleTrafficForTLSSNI) Filter(
direction DPIDirection, packet *DissectedPacket) (*DPIPolicy, bool) {
// short circuit for the return path
if direction != DPIDirectionClientToServer {
return nil, false
}
// short circuit for UDP packets
if packet.TransportProtocol() != layers.IPProtocolTCP {
return nil, false
}
// try to obtain the SNI
tlsHandshakeBytes, length, err := packet.extractTLSHandshake(r.TLSHandshake, r.TlSHandshakeSize)
if err != nil {
return nil, false
}
if r.TlSHandshakeSize == 0 {
r.TlSHandshakeSize = length
}
r.TLSHandshake = tlsHandshakeBytes
if r.done {
return nil, false
}
if len(r.TLSHandshake) == int(r.TlSHandshakeSize) {
sni, err := packet.parseTLSServerName(r.TLSHandshake)
if err != nil {
r.Logger.Warnf(
"netem: dpi: failed to parse TLS server name for %s:%d %s:%d/%s because SNI==%s",
packet.SourceIPAddress(),
packet.SourcePort(),
packet.DestinationIPAddress(),
packet.DestinationPort(),
packet.TransportProtocol(),
sni,
)
r.TLSHandshake = []byte{}
r.TlSHandshakeSize = 0
return nil, false
}
r.TLSHandshake = []byte{}
r.TlSHandshakeSize = 0
r.done = true
// if the packet is not offending, accept it
if sni != r.SNI {
return nil, false
}
r.Logger.Infof(
"netem: dpi: throttling flow %s:%d %s:%d/%s because SNI==%s",
packet.SourceIPAddress(),
packet.SourcePort(),
packet.DestinationIPAddress(),
packet.DestinationPort(),
packet.TransportProtocol(),
sni,
)
policy := &DPIPolicy{
Delay: r.Delay,
Flags: 0,
PLR: r.PLR,
Spoofed: nil,
}
return policy, true
}
return nil, false
}
// DPIThrottleTrafficForTCPEndpoint is a [DPIRule] that throttles traffic
// for a given TCP endpoint. The zero value is not valid. Make sure
// you initialize all fields marked as MANDATORY.
type DPIThrottleTrafficForTCPEndpoint struct {
// Delay is the OPTIONAL extra delay to add to the flow.
Delay time.Duration
// Logger is the MANDATORY logger to use.
Logger Logger
// PLR is the OPTIONAL extra packet loss rate to apply to the packet.
PLR float64
// ServerIPAddress is the MANDATORY server endpoint IP address.
ServerIPAddress string
// ServerPort is the MANDATORY server endpoint port.
ServerPort uint16
}
var _ DPIRule = &DPIThrottleTrafficForTCPEndpoint{}
// Filter implements DPIRule
func (r *DPIThrottleTrafficForTCPEndpoint) Filter(
direction DPIDirection, packet *DissectedPacket) (*DPIPolicy, bool) {
// short circuit for the return path
if direction != DPIDirectionClientToServer {
return nil, false
}
// make sure the packet is TCP and for the proper endpoint
if !packet.MatchesDestination(layers.IPProtocolTCP, r.ServerIPAddress, r.ServerPort) {
return nil, false
}
r.Logger.Infof(
"netem: dpi: throttling flow %s:%d %s:%d/%s because the endpoint is filtered",
packet.SourceIPAddress(),
packet.SourcePort(),
packet.DestinationIPAddress(),
packet.DestinationPort(),
packet.TransportProtocol(),
)
policy := &DPIPolicy{
Delay: r.Delay,
Flags: 0,
PLR: r.PLR,
Spoofed: nil,
}
return policy, true
}