1 package ratelimits
2
3 import (
4 "fmt"
5 "net"
6 "strconv"
7 "strings"
8
9 "github.com/letsencrypt/boulder/policy"
10 )
11
12
13
14
15
16
17
18 type Name int
19
20 const (
21
22
23 Unknown Name = iota
24
25
26 NewRegistrationsPerIPAddress
27
28
29
30
31
32
33
34
35
36 NewRegistrationsPerIPv6Range
37
38
39 NewOrdersPerAccount
40
41
42
43 FailedAuthorizationsPerAccount
44
45
46
47
48 CertificatesPerDomainPerAccount
49
50
51
52
53 CertificatesPerFQDNSetPerAccount
54 )
55
56
57 func (n Name) isValid() bool {
58 return n > Unknown && n < Name(len(nameToString))
59 }
60
61
62
63 func (n Name) String() string {
64 if !n.isValid() {
65 return nameToString[Unknown]
66 }
67 return nameToString[n]
68 }
69
70
71 var nameToString = map[Name]string{
72 Unknown: "Unknown",
73 NewRegistrationsPerIPAddress: "NewRegistrationsPerIPAddress",
74 NewRegistrationsPerIPv6Range: "NewRegistrationsPerIPv6Range",
75 NewOrdersPerAccount: "NewOrdersPerAccount",
76 FailedAuthorizationsPerAccount: "FailedAuthorizationsPerAccount",
77 CertificatesPerDomainPerAccount: "CertificatesPerDomainPerAccount",
78 CertificatesPerFQDNSetPerAccount: "CertificatesPerFQDNSetPerAccount",
79 }
80
81
82 func validIPAddress(id string) error {
83 ip := net.ParseIP(id)
84 if ip == nil {
85 return fmt.Errorf("invalid IP address, %q must be an IP address", id)
86 }
87 return nil
88 }
89
90
91
92 func validIPv6RangeCIDR(id string) error {
93 _, ipNet, err := net.ParseCIDR(id)
94 if err != nil {
95 return fmt.Errorf(
96 "invalid CIDR, %q must be an IPv6 CIDR range", id)
97 }
98 ones, _ := ipNet.Mask.Size()
99 if ones != 48 {
100
101
102 return fmt.Errorf(
103 "invalid CIDR, %q must be /48", id)
104 }
105 return nil
106 }
107
108
109 func validateRegId(id string) error {
110 _, err := strconv.ParseUint(id, 10, 64)
111 if err != nil {
112 return fmt.Errorf("invalid regId, %q must be an ACME registration Id", id)
113 }
114 return nil
115 }
116
117
118
119
120 func validateRegIdDomain(id string) error {
121 parts := strings.SplitN(id, ":", 2)
122 if len(parts) != 2 {
123 return fmt.Errorf(
124 "invalid regId:domain, %q must be formatted 'regId:domain'", id)
125 }
126 if validateRegId(parts[0]) != nil {
127 return fmt.Errorf(
128 "invalid regId, %q must be formatted 'regId:domain'", id)
129 }
130 if policy.ValidDomain(parts[1]) != nil {
131 return fmt.Errorf(
132 "invalid domain, %q must be formatted 'regId:domain'", id)
133 }
134 return nil
135 }
136
137
138
139
140 func validateRegIdFQDNSet(id string) error {
141 parts := strings.SplitN(id, ":", 2)
142 if len(parts) != 2 {
143 return fmt.Errorf(
144 "invalid regId:fqdnSet, %q must be formatted 'regId:fqdnSet'", id)
145 }
146 if validateRegId(parts[0]) != nil {
147 return fmt.Errorf(
148 "invalid regId, %q must be formatted 'regId:fqdnSet'", id)
149 }
150 domains := strings.Split(parts[1], ",")
151 if len(domains) == 0 {
152 return fmt.Errorf(
153 "invalid fqdnSet, %q must be formatted 'regId:fqdnSet'", id)
154 }
155 for _, domain := range domains {
156 if policy.ValidDomain(domain) != nil {
157 return fmt.Errorf(
158 "invalid domain, %q must be formatted 'regId:fqdnSet'", id)
159 }
160 }
161 return nil
162 }
163
164 func validateIdForName(name Name, id string) error {
165 switch name {
166 case NewRegistrationsPerIPAddress:
167
168 return validIPAddress(id)
169
170 case NewRegistrationsPerIPv6Range:
171
172 return validIPv6RangeCIDR(id)
173
174 case NewOrdersPerAccount, FailedAuthorizationsPerAccount:
175
176 return validateRegId(id)
177
178 case CertificatesPerDomainPerAccount:
179
180 return validateRegIdDomain(id)
181
182 case CertificatesPerFQDNSetPerAccount:
183
184 return validateRegIdFQDNSet(id)
185
186 case Unknown:
187 fallthrough
188
189 default:
190
191 return fmt.Errorf("unknown limit enum %q", name)
192 }
193 }
194
195
196 var stringToName = func() map[string]Name {
197 m := make(map[string]Name, len(nameToString))
198 for k, v := range nameToString {
199 m[v] = k
200 }
201 return m
202 }()
203
204
205 var limitNames = func() []string {
206 names := make([]string, len(nameToString))
207 for _, v := range nameToString {
208 names = append(names, v)
209 }
210 return names
211 }()
212
213
214
215 func nameToEnumString(s Name) string {
216 return strconv.Itoa(int(s))
217 }
218
219
220 func bucketKey(name Name, id string) string {
221 return nameToEnumString(name) + ":" + id
222 }
223
View as plain text