-
Notifications
You must be signed in to change notification settings - Fork 0
/
doc.go
157 lines (116 loc) · 6.28 KB
/
doc.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
/*
Package rrl is a stand-alone implementation of “Response Rate Limiting” which helps
protect authoritative DNS servers from being used as a vehicle for amplification
attacks.
In addition to “Response Rate Limiting”, rrl provides a configurable source address rate
limiter.
The rrl package is designed to be very easy to use.
It consists of a configuration mechanism and a single public function to check limits.
That's it; that's the interface.
“Response Rate Limiting“ was original devised by [ISC] and this implementation is
heavily derived from [COREDNSRRL] which mimics the ISC algorithms.
# Usage
The general pattern of use is to create a one-time [RRL] object with [NewRRL] using a
deployment-specific [Config], then call [Debit] prior to sending each response back to a
client.
[Debit] returns one of the following recommended actions: “Send”, “Drop” or “Slip”.
While the meaning of “Send” and “Drop” are self-evident, “Slip” is more complicated.
“Slip” is ISC terminology which means to respond with a BADCOOKIE response or a
truncated response depending on whether the query included a valid client cookie or not.
The goal of a “Slip” response is to give genuine clients a small chance of getting a
response even when their source addresses are in a range being used as part of an
amplification attack.
The “Slip” response is one of a number of differences between a regular rate-limiting
system and the DNS-specific rrl.
Note that requests with valid server cookies are never rate-limited so a BADCOOKIE
response is always valid in the presence of a client cookie.
# Sample Code
The follow example demonstrates the expected pattern of use.
It introduces terms such as “Response Tuple”, “account” and “debit” which are
explained in subsequent sections.
For now, the logic flow is of most relevance.
package main
import "github.com/markdingo/rrl"
func main() {
server:= dnsListenSocket()
db := myDatabase()
cfg := rrl.NewConfig()
cfg.SetValue(...) // Configure limits relevant to our deployment
R := NewRRL(cfg) // Create our `rrl` instance
for {
srcIP, request := server.GetRequest() // Accept a query
response := db.lookupResponse(request) // Create the response
action := rrl.Send // Default to sending response as-is
if !request.validServerCook() { // Only rate-limit if src can be spoofed
tuple := makeTuple(response) // Formulate the "Response Tuple"...
action, _, _ := R.Debit(srcIP, tuple) // ... and debit the corresponding accounts
}
switch action { // Dispatch on the recommended action
case rrl.Drop: // Drop is easy, do nothing
case rrl.Send: // No rate limit applies, ship it!
server.Send(response)
case rrl.Slip:
if request.ValidClientCookie() { // Slip response varies depending on
server.SendBadCookie(response) // whether the client sent a cooke or not
} else {
response.makeTruncatedIfAble() // No valid client cookie means
server.Send(response) // send a truncated response
}
}
}
}
Note that some error responses such as REFUSED and SERVFAIL cannot be replaced with
truncated responses thus the “makeTruncatedIfAble” function needs some intelligence.
# Concurrency
The rrl package is safe for concurrent use by multiple goroutines.
Normally a single [RRL] object is shared amongst all goroutines across the application.
However, if an application does require multiple [RRL] instances, they all operate
completely independently of each other.
# Background
While rate limiting is a common strategy used to limit abusive traffic, “Response Rate
Limiting” is specifically designed for UDP DNS queries (which lack a valid server cookie)
received by authoritative DNS servers.
The original RRL design was promulgated by [ISC] who have published extensive articles on
the subject.
A good place to start is their [ISCINTRO] document.
# Description
[RRL] tracks the query-per-second rate in a unique “account” assigned to each
“Response Tuple“ destined for a particular Client Network.
Each “account” is credited once per second by the configured amount and debited once for
each [Debit] call.
At most an “account” can gain up to one second of credits or up a configurable 15
seconds of debits.
While the “account” is in credit, a call to [Debit] returns a “Send” action. If the
“account” is not in credit, then a “Drop” or “Slip” action is returned depending on
the configured slip ratio.
## Response Tuple
A “Response Tuple” is an “account” key formulated from various features of the
response message depending on the nature of the response (NXDomain, Error, referral, etc).
The intent is for responses indicative of potential abuse to be assigned to a small set of
tuples whereas responses indicative of genuine requests are assigned to a large set of
tuples.
The goal being to cause “accounts” of suspect queries to run out of credits far sooner
than the “accounts” of genuine queries.
The formulation of a “Response Tuple” is somewhat convoluted.
Suffice to say that it varies considerably depending on the nature of the response - a
unique feature or rrl.
The [ResponseTuple] struct describes this formulation in detail.
## Client Network
The Client Network forms the other “account” key.
It is the source address of the request masked by the configured network size.
The default sizes being 24 for ipv4 and 56 for ipv6.
# Genesis
This package is derived from [COREDNSRRL] with the main differences being that all coredns
dependencies and external interfaces have been removed so that this package can be used by
standalone DNS implementations unrelated to coredns.
It goes without saying that this package only exists because of the efforts of the
coredns/rrl authors.
A big “thank you” to them.
The plan is for this project to mirror fixes and improvements to [COREDNSRRL] where
possible.
# References
[COREDNSRRL]: https://github.com/coredns/rrl
[ISC]: https://www.isc.org
[ISCINTRO]: https://kb.isc.org/docs/aa-01000
*/
package rrl