forked from Psiphon-Labs/psiphon-tunnel-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
trafficRules.go
772 lines (632 loc) · 25.5 KB
/
trafficRules.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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
/*
* Copyright (c) 2016, Psiphon Inc.
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package server
import (
"encoding/json"
"errors"
"fmt"
"net"
"time"
"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
)
const (
DEFAULT_IDLE_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS = 30000
DEFAULT_IDLE_UDP_PORT_FORWARD_TIMEOUT_MILLISECONDS = 30000
DEFAULT_DIAL_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS = 10000
DEFAULT_MAX_TCP_DIALING_PORT_FORWARD_COUNT = 64
DEFAULT_MAX_TCP_PORT_FORWARD_COUNT = 512
DEFAULT_MAX_UDP_PORT_FORWARD_COUNT = 32
DEFAULT_MEEK_RATE_LIMITER_GARBAGE_COLLECTOR_TRIGGER_COUNT = 5000
DEFAULT_MEEK_RATE_LIMITER_REAP_HISTORY_FREQUENCY_SECONDS = 600
)
// TrafficRulesSet represents the various traffic rules to
// apply to Psiphon client tunnels. The Reload function supports
// hot reloading of rules data while the server is running.
//
// For a given client, the traffic rules are determined by starting
// with DefaultRules, then finding the first (if any)
// FilteredTrafficRules match and overriding the defaults with fields
// set in the selected FilteredTrafficRules.
type TrafficRulesSet struct {
common.ReloadableFile
// DefaultRules are the base values to use as defaults for all
// clients.
DefaultRules TrafficRules
// FilteredTrafficRules is an ordered list of filter/rules pairs.
// For each client, the first matching Filter in FilteredTrafficRules
// determines the additional Rules that are selected and applied
// on top of DefaultRules.
FilteredRules []struct {
Filter TrafficRulesFilter
Rules TrafficRules
}
// MeekRateLimiterHistorySize enables the late-stage meek rate limiter and
// sets its history size. The late-stage meek rate limiter acts on client
// IPs relayed in MeekProxyForwardedForHeaders, and so it must wait for
// the HTTP headers to be read. This rate limiter immediately terminates
// any client endpoint request or any request to create a new session, but
// not any meek request for an existing session, if the
// MeekRateLimiterHistorySize requests occur in
// MeekRateLimiterThresholdSeconds. The scope of rate limiting may be
// limited using LimitMeekRateLimiterRegions and LimitMeekRateLimiterISPs.
//
// Hot reloading a new history size will result in existing history being
// truncated.
MeekRateLimiterHistorySize int
// MeekRateLimiterThresholdSeconds is part of the meek rate limiter
// specification and must be set when MeekRateLimiterHistorySize is set.
MeekRateLimiterThresholdSeconds int
// MeekRateLimiterRegions, if set, limits application of the meek
// late-stage rate limiter to clients in the specified list of GeoIP
// countries. When omitted or empty, meek rate limiting, if configured,
// is applied to all client countries.
MeekRateLimiterRegions []string
// MeekRateLimiterISPs, if set, limits application of the meek
// late-stage rate limiter to clients in the specified list of GeoIP
// ISPs. When omitted or empty, meek rate limiting, if configured,
// is applied to all client ISPs.
MeekRateLimiterISPs []string
// MeekRateLimiterGarbageCollectionTriggerCount specifies the number of
// rate limit events after which garbage collection is manually triggered
// in order to reclaim memory used by rate limited and other rejected
// requests.
// A default of 5000 is used when
// MeekRateLimiterGarbageCollectionTriggerCount is 0.
MeekRateLimiterGarbageCollectionTriggerCount int
// MeekRateLimiterReapHistoryFrequencySeconds specifies a schedule for
// reaping old records from the rate limit history.
// A default of 600 is used when
// MeekRateLimiterReapHistoryFrequencySeconds is 0.
MeekRateLimiterReapHistoryFrequencySeconds int
}
// TrafficRulesFilter defines a filter to match against client attributes.
type TrafficRulesFilter struct {
// TunnelProtocols is a list of client tunnel protocols that must be
// in use to match this filter. When omitted or empty, any protocol
// matches.
TunnelProtocols []string
// Regions is a list of countries that the client must geolocate to in
// order to match this filter. When omitted or empty, any client country
// matches.
Regions []string
// ISPs is a list of ISPs that the client must geolocate to in order to
// match this filter. When omitted or empty, any client ISP matches.
ISPs []string
// APIProtocol specifies whether the client must use the SSH
// API protocol (when "ssh") or the web API protocol (when "web").
// When omitted or blank, any API protocol matches.
APIProtocol string
// HandshakeParameters specifies handshake API parameter names and
// a list of values, one of which must be specified to match this
// filter. Only scalar string API parameters may be filtered.
// Values may be patterns containing the '*' wildcard.
HandshakeParameters map[string][]string
// AuthorizedAccessTypes specifies a list of access types, at least
// one of which the client must have presented an active authorization
// for and which must not be revoked.
// AuthorizedAccessTypes is ignored when AuthorizationsRevoked is true.
AuthorizedAccessTypes []string
// AuthorizationsRevoked indicates whether the client's authorizations
// must have been revoked. When true, authorizations must have been
// revoked. When omitted or false, this field is ignored.
AuthorizationsRevoked bool
regionLookup map[string]bool
ispLookup map[string]bool
}
// TrafficRules specify the limits placed on client traffic.
type TrafficRules struct {
// RateLimits specifies data transfer rate limits for the
// client traffic.
RateLimits RateLimits
// DialTCPPortForwardTimeoutMilliseconds is the timeout period
// for dialing TCP port forwards. A value of 0 specifies no timeout.
// When omitted in DefaultRules,
// DEFAULT_TCP_PORT_FORWARD_DIAL_TIMEOUT_MILLISECONDS is used.
DialTCPPortForwardTimeoutMilliseconds *int
// IdleTCPPortForwardTimeoutMilliseconds is the timeout period
// after which idle (no bytes flowing in either direction)
// client TCP port forwards are preemptively closed.
// A value of 0 specifies no idle timeout. When omitted in
// DefaultRules, DEFAULT_IDLE_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS
// is used.
IdleTCPPortForwardTimeoutMilliseconds *int
// IdleUDPPortForwardTimeoutMilliseconds is the timeout period
// after which idle (no bytes flowing in either direction)
// client UDP port forwards are preemptively closed.
// A value of 0 specifies no idle timeout. When omitted in
// DefaultRules, DEFAULT_IDLE_UDP_PORT_FORWARD_TIMEOUT_MILLISECONDS
// is used.
IdleUDPPortForwardTimeoutMilliseconds *int
// MaxTCPDialingPortForwardCount is the maximum number of dialing
// TCP port forwards each client may have open concurrently. When
// persistently at the limit, new TCP port forwards are rejected.
// A value of 0 specifies no maximum. When omitted in
// DefaultRules, DEFAULT_MAX_TCP_DIALING_PORT_FORWARD_COUNT is used.
MaxTCPDialingPortForwardCount *int
// MaxTCPPortForwardCount is the maximum number of established TCP
// port forwards each client may have open concurrently. If at the
// limit when a new TCP port forward is established, the LRU
// established TCP port forward is closed.
// A value of 0 specifies no maximum. When omitted in
// DefaultRules, DEFAULT_MAX_TCP_PORT_FORWARD_COUNT is used.
MaxTCPPortForwardCount *int
// MaxUDPPortForwardCount is the maximum number of UDP port
// forwards each client may have open concurrently. If at the
// limit when a new UDP port forward is created, the LRU
// UDP port forward is closed.
// A value of 0 specifies no maximum. When omitted in
// DefaultRules, DEFAULT_MAX_UDP_PORT_FORWARD_COUNT is used.
MaxUDPPortForwardCount *int
// AllowTCPPorts specifies a whitelist of TCP ports that
// are permitted for port forwarding. When set, only ports
// in the list are accessible to clients.
AllowTCPPorts []int
// AllowUDPPorts specifies a whitelist of UDP ports that
// are permitted for port forwarding. When set, only ports
// in the list are accessible to clients.
AllowUDPPorts []int
// AllowSubnets specifies a list of IP address subnets for
// which all TCP and UDP ports are allowed. This list is
// consulted if a port is disallowed by the AllowTCPPorts
// or AllowUDPPorts configuration. Each entry is a IP subnet
// in CIDR notation.
// Limitation: currently, AllowSubnets only matches port
// forwards where the client sends an IP address. Domain
// names are not resolved before checking AllowSubnets.
AllowSubnets []string
allowTCPPortsLookup map[int]bool
allowUDPPortsLookup map[int]bool
}
// RateLimits is a clone of common.RateLimits with pointers
// to fields to enable distinguishing between zero values and
// omitted values in JSON serialized traffic rules.
// See common.RateLimits for field descriptions.
type RateLimits struct {
ReadUnthrottledBytes *int64
ReadBytesPerSecond *int64
WriteUnthrottledBytes *int64
WriteBytesPerSecond *int64
CloseAfterExhausted *bool
// UnthrottleFirstTunnelOnly specifies whether any
// ReadUnthrottledBytes/WriteUnthrottledBytes apply
// only to the first tunnel in a session.
UnthrottleFirstTunnelOnly *bool
}
// CommonRateLimits converts a RateLimits to a common.RateLimits.
func (rateLimits *RateLimits) CommonRateLimits() common.RateLimits {
return common.RateLimits{
ReadUnthrottledBytes: *rateLimits.ReadUnthrottledBytes,
ReadBytesPerSecond: *rateLimits.ReadBytesPerSecond,
WriteUnthrottledBytes: *rateLimits.WriteUnthrottledBytes,
WriteBytesPerSecond: *rateLimits.WriteBytesPerSecond,
CloseAfterExhausted: *rateLimits.CloseAfterExhausted,
}
}
// NewTrafficRulesSet initializes a TrafficRulesSet with
// the rules data in the specified config file.
func NewTrafficRulesSet(filename string) (*TrafficRulesSet, error) {
set := &TrafficRulesSet{}
set.ReloadableFile = common.NewReloadableFile(
filename,
true,
func(fileContent []byte, _ time.Time) error {
var newSet TrafficRulesSet
err := json.Unmarshal(fileContent, &newSet)
if err != nil {
return common.ContextError(err)
}
err = newSet.Validate()
if err != nil {
return common.ContextError(err)
}
// Modify actual traffic rules only after validation
set.MeekRateLimiterHistorySize = newSet.MeekRateLimiterHistorySize
set.MeekRateLimiterThresholdSeconds = newSet.MeekRateLimiterThresholdSeconds
set.MeekRateLimiterRegions = newSet.MeekRateLimiterRegions
set.MeekRateLimiterISPs = newSet.MeekRateLimiterISPs
set.MeekRateLimiterGarbageCollectionTriggerCount = newSet.MeekRateLimiterGarbageCollectionTriggerCount
set.MeekRateLimiterReapHistoryFrequencySeconds = newSet.MeekRateLimiterReapHistoryFrequencySeconds
set.DefaultRules = newSet.DefaultRules
set.FilteredRules = newSet.FilteredRules
set.initLookups()
return nil
})
_, err := set.Reload()
if err != nil {
return nil, common.ContextError(err)
}
return set, nil
}
// Validate checks for correct input formats in a TrafficRulesSet.
func (set *TrafficRulesSet) Validate() error {
if set.MeekRateLimiterHistorySize < 0 ||
set.MeekRateLimiterThresholdSeconds < 0 ||
set.MeekRateLimiterGarbageCollectionTriggerCount < 0 ||
set.MeekRateLimiterReapHistoryFrequencySeconds < 0 {
return common.ContextError(
errors.New("MeekRateLimiter values must be >= 0"))
}
if set.MeekRateLimiterHistorySize > 0 {
if set.MeekRateLimiterThresholdSeconds <= 0 {
return common.ContextError(
errors.New("MeekRateLimiterThresholdSeconds must be > 0"))
}
}
validateTrafficRules := func(rules *TrafficRules) error {
if (rules.RateLimits.ReadUnthrottledBytes != nil && *rules.RateLimits.ReadUnthrottledBytes < 0) ||
(rules.RateLimits.ReadBytesPerSecond != nil && *rules.RateLimits.ReadBytesPerSecond < 0) ||
(rules.RateLimits.WriteUnthrottledBytes != nil && *rules.RateLimits.WriteUnthrottledBytes < 0) ||
(rules.RateLimits.WriteBytesPerSecond != nil && *rules.RateLimits.WriteBytesPerSecond < 0) ||
(rules.DialTCPPortForwardTimeoutMilliseconds != nil && *rules.DialTCPPortForwardTimeoutMilliseconds < 0) ||
(rules.IdleTCPPortForwardTimeoutMilliseconds != nil && *rules.IdleTCPPortForwardTimeoutMilliseconds < 0) ||
(rules.IdleUDPPortForwardTimeoutMilliseconds != nil && *rules.IdleUDPPortForwardTimeoutMilliseconds < 0) ||
(rules.MaxTCPDialingPortForwardCount != nil && *rules.MaxTCPDialingPortForwardCount < 0) ||
(rules.MaxTCPPortForwardCount != nil && *rules.MaxTCPPortForwardCount < 0) ||
(rules.MaxUDPPortForwardCount != nil && *rules.MaxUDPPortForwardCount < 0) {
return common.ContextError(
errors.New("TrafficRules values must be >= 0"))
}
for _, subnet := range rules.AllowSubnets {
_, _, err := net.ParseCIDR(subnet)
if err != nil {
return common.ContextError(
fmt.Errorf("invalid subnet: %s %s", subnet, err))
}
}
return nil
}
err := validateTrafficRules(&set.DefaultRules)
if err != nil {
return common.ContextError(err)
}
for _, filteredRule := range set.FilteredRules {
for paramName := range filteredRule.Filter.HandshakeParameters {
validParamName := false
for _, paramSpec := range baseRequestParams {
if paramSpec.name == paramName {
validParamName = true
break
}
}
if !validParamName {
return common.ContextError(
fmt.Errorf("invalid parameter name: %s", paramName))
}
}
err := validateTrafficRules(&filteredRule.Rules)
if err != nil {
return common.ContextError(err)
}
}
return nil
}
const stringLookupThreshold = 5
const intLookupThreshold = 10
// initLookups creates map lookups for filters where the number of string/int
// values to compare against exceeds a threshold where benchmarks show maps
// are faster than looping through a string/int slice.
func (set *TrafficRulesSet) initLookups() {
initTrafficRulesLookups := func(rules *TrafficRules) {
if len(rules.AllowTCPPorts) >= intLookupThreshold {
rules.allowTCPPortsLookup = make(map[int]bool)
for _, port := range rules.AllowTCPPorts {
rules.allowTCPPortsLookup[port] = true
}
}
if len(rules.AllowUDPPorts) >= intLookupThreshold {
rules.allowUDPPortsLookup = make(map[int]bool)
for _, port := range rules.AllowUDPPorts {
rules.allowUDPPortsLookup[port] = true
}
}
}
initTrafficRulesFilterLookups := func(filter *TrafficRulesFilter) {
if len(filter.Regions) >= stringLookupThreshold {
filter.regionLookup = make(map[string]bool)
for _, region := range filter.Regions {
filter.regionLookup[region] = true
}
}
if len(filter.ISPs) >= stringLookupThreshold {
filter.ispLookup = make(map[string]bool)
for _, ISP := range filter.ISPs {
filter.ispLookup[ISP] = true
}
}
}
initTrafficRulesLookups(&set.DefaultRules)
for i, _ := range set.FilteredRules {
initTrafficRulesFilterLookups(&set.FilteredRules[i].Filter)
initTrafficRulesLookups(&set.FilteredRules[i].Rules)
}
// TODO: add lookups for MeekRateLimiter?
}
// GetTrafficRules determines the traffic rules for a client based on its attributes.
// For the return value TrafficRules, all pointer and slice fields are initialized,
// so nil checks are not required. The caller must not modify the returned TrafficRules.
func (set *TrafficRulesSet) GetTrafficRules(
isFirstTunnelInSession bool,
tunnelProtocol string,
geoIPData GeoIPData,
state handshakeState) TrafficRules {
set.ReloadableFile.RLock()
defer set.ReloadableFile.RUnlock()
// Start with a copy of the DefaultRules, and then select the first
// matching Rules from FilteredTrafficRules, taking only the explicitly
// specified fields from that Rules.
//
// Notes:
// - Scalar pointers are used in TrafficRules and RateLimits to distinguish between
// omitted fields (in serialized JSON) and default values. For example, if a filtered
// Rules specifies a field value of 0, this will override the default; but if the
// serialized filtered rule omits the field, the default is to be retained.
// - We use shallow copies and slices and scalar pointers are shared between the
// return value TrafficRules, so callers must treat the return value as immutable.
// This also means that these slices and pointers can remain referenced in memory even
// after a hot reload.
trafficRules := set.DefaultRules
// Populate defaults for omitted DefaultRules fields
if trafficRules.RateLimits.ReadUnthrottledBytes == nil {
trafficRules.RateLimits.ReadUnthrottledBytes = new(int64)
}
if trafficRules.RateLimits.ReadBytesPerSecond == nil {
trafficRules.RateLimits.ReadBytesPerSecond = new(int64)
}
if trafficRules.RateLimits.WriteUnthrottledBytes == nil {
trafficRules.RateLimits.WriteUnthrottledBytes = new(int64)
}
if trafficRules.RateLimits.WriteBytesPerSecond == nil {
trafficRules.RateLimits.WriteBytesPerSecond = new(int64)
}
if trafficRules.RateLimits.CloseAfterExhausted == nil {
trafficRules.RateLimits.CloseAfterExhausted = new(bool)
}
if trafficRules.RateLimits.UnthrottleFirstTunnelOnly == nil {
trafficRules.RateLimits.UnthrottleFirstTunnelOnly = new(bool)
}
intPtr := func(i int) *int {
return &i
}
if trafficRules.DialTCPPortForwardTimeoutMilliseconds == nil {
trafficRules.DialTCPPortForwardTimeoutMilliseconds =
intPtr(DEFAULT_DIAL_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS)
}
if trafficRules.IdleTCPPortForwardTimeoutMilliseconds == nil {
trafficRules.IdleTCPPortForwardTimeoutMilliseconds =
intPtr(DEFAULT_IDLE_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS)
}
if trafficRules.IdleUDPPortForwardTimeoutMilliseconds == nil {
trafficRules.IdleUDPPortForwardTimeoutMilliseconds =
intPtr(DEFAULT_IDLE_UDP_PORT_FORWARD_TIMEOUT_MILLISECONDS)
}
if trafficRules.MaxTCPDialingPortForwardCount == nil {
trafficRules.MaxTCPDialingPortForwardCount =
intPtr(DEFAULT_MAX_TCP_DIALING_PORT_FORWARD_COUNT)
}
if trafficRules.MaxTCPPortForwardCount == nil {
trafficRules.MaxTCPPortForwardCount =
intPtr(DEFAULT_MAX_TCP_PORT_FORWARD_COUNT)
}
if trafficRules.MaxUDPPortForwardCount == nil {
trafficRules.MaxUDPPortForwardCount =
intPtr(DEFAULT_MAX_UDP_PORT_FORWARD_COUNT)
}
if trafficRules.AllowTCPPorts == nil {
trafficRules.AllowTCPPorts = make([]int, 0)
}
if trafficRules.AllowUDPPorts == nil {
trafficRules.AllowUDPPorts = make([]int, 0)
}
if trafficRules.AllowSubnets == nil {
trafficRules.AllowSubnets = make([]string, 0)
}
// TODO: faster lookup?
for _, filteredRules := range set.FilteredRules {
log.WithContextFields(LogFields{"filter": filteredRules.Filter}).Debug("filter check")
if len(filteredRules.Filter.TunnelProtocols) > 0 {
if !common.Contains(filteredRules.Filter.TunnelProtocols, tunnelProtocol) {
continue
}
}
if len(filteredRules.Filter.Regions) > 0 {
if filteredRules.Filter.regionLookup != nil {
if !filteredRules.Filter.regionLookup[geoIPData.Country] {
continue
}
} else {
if !common.Contains(filteredRules.Filter.Regions, geoIPData.Country) {
continue
}
}
}
if len(filteredRules.Filter.ISPs) > 0 {
if filteredRules.Filter.ispLookup != nil {
if !filteredRules.Filter.ispLookup[geoIPData.ISP] {
continue
}
} else {
if !common.Contains(filteredRules.Filter.ISPs, geoIPData.ISP) {
continue
}
}
}
if filteredRules.Filter.APIProtocol != "" {
if !state.completed {
continue
}
if state.apiProtocol != filteredRules.Filter.APIProtocol {
continue
}
}
if filteredRules.Filter.HandshakeParameters != nil {
if !state.completed {
continue
}
mismatch := false
for name, values := range filteredRules.Filter.HandshakeParameters {
clientValue, err := getStringRequestParam(state.apiParams, name)
if err != nil || !common.ContainsWildcard(values, clientValue) {
mismatch = true
break
}
}
if mismatch {
continue
}
}
if filteredRules.Filter.AuthorizationsRevoked {
if !state.completed {
continue
}
if !state.authorizationsRevoked {
continue
}
} else if len(filteredRules.Filter.AuthorizedAccessTypes) > 0 {
if !state.completed {
continue
}
if state.authorizationsRevoked {
continue
}
if !common.ContainsAny(filteredRules.Filter.AuthorizedAccessTypes, state.authorizedAccessTypes) {
continue
}
}
log.WithContextFields(LogFields{"filter": filteredRules.Filter}).Debug("filter match")
// This is the first match. Override defaults using provided fields from selected rules, and return result.
if filteredRules.Rules.RateLimits.ReadUnthrottledBytes != nil {
trafficRules.RateLimits.ReadUnthrottledBytes = filteredRules.Rules.RateLimits.ReadUnthrottledBytes
}
if filteredRules.Rules.RateLimits.ReadBytesPerSecond != nil {
trafficRules.RateLimits.ReadBytesPerSecond = filteredRules.Rules.RateLimits.ReadBytesPerSecond
}
if filteredRules.Rules.RateLimits.WriteUnthrottledBytes != nil {
trafficRules.RateLimits.WriteUnthrottledBytes = filteredRules.Rules.RateLimits.WriteUnthrottledBytes
}
if filteredRules.Rules.RateLimits.WriteBytesPerSecond != nil {
trafficRules.RateLimits.WriteBytesPerSecond = filteredRules.Rules.RateLimits.WriteBytesPerSecond
}
if filteredRules.Rules.RateLimits.CloseAfterExhausted != nil {
trafficRules.RateLimits.CloseAfterExhausted = filteredRules.Rules.RateLimits.CloseAfterExhausted
}
if filteredRules.Rules.RateLimits.UnthrottleFirstTunnelOnly != nil {
trafficRules.RateLimits.UnthrottleFirstTunnelOnly = filteredRules.Rules.RateLimits.UnthrottleFirstTunnelOnly
}
if filteredRules.Rules.DialTCPPortForwardTimeoutMilliseconds != nil {
trafficRules.DialTCPPortForwardTimeoutMilliseconds = filteredRules.Rules.DialTCPPortForwardTimeoutMilliseconds
}
if filteredRules.Rules.IdleTCPPortForwardTimeoutMilliseconds != nil {
trafficRules.IdleTCPPortForwardTimeoutMilliseconds = filteredRules.Rules.IdleTCPPortForwardTimeoutMilliseconds
}
if filteredRules.Rules.IdleUDPPortForwardTimeoutMilliseconds != nil {
trafficRules.IdleUDPPortForwardTimeoutMilliseconds = filteredRules.Rules.IdleUDPPortForwardTimeoutMilliseconds
}
if filteredRules.Rules.MaxTCPDialingPortForwardCount != nil {
trafficRules.MaxTCPDialingPortForwardCount = filteredRules.Rules.MaxTCPDialingPortForwardCount
}
if filteredRules.Rules.MaxTCPPortForwardCount != nil {
trafficRules.MaxTCPPortForwardCount = filteredRules.Rules.MaxTCPPortForwardCount
}
if filteredRules.Rules.MaxUDPPortForwardCount != nil {
trafficRules.MaxUDPPortForwardCount = filteredRules.Rules.MaxUDPPortForwardCount
}
if filteredRules.Rules.AllowTCPPorts != nil {
trafficRules.AllowTCPPorts = filteredRules.Rules.AllowTCPPorts
trafficRules.allowTCPPortsLookup = filteredRules.Rules.allowTCPPortsLookup
}
if filteredRules.Rules.AllowUDPPorts != nil {
trafficRules.AllowUDPPorts = filteredRules.Rules.AllowUDPPorts
trafficRules.allowUDPPortsLookup = filteredRules.Rules.allowUDPPortsLookup
}
if filteredRules.Rules.AllowSubnets != nil {
trafficRules.AllowSubnets = filteredRules.Rules.AllowSubnets
}
break
}
if *trafficRules.RateLimits.UnthrottleFirstTunnelOnly && !isFirstTunnelInSession {
trafficRules.RateLimits.ReadUnthrottledBytes = new(int64)
trafficRules.RateLimits.WriteUnthrottledBytes = new(int64)
}
log.WithContextFields(LogFields{"trafficRules": trafficRules}).Debug("selected traffic rules")
return trafficRules
}
func (rules *TrafficRules) AllowTCPPort(remoteIP net.IP, port int) bool {
if len(rules.AllowTCPPorts) == 0 {
return true
}
if rules.allowTCPPortsLookup != nil {
if rules.allowTCPPortsLookup[port] == true {
return true
}
} else {
for _, allowPort := range rules.AllowTCPPorts {
if port == allowPort {
return true
}
}
}
return rules.allowSubnet(remoteIP)
}
func (rules *TrafficRules) AllowUDPPort(remoteIP net.IP, port int) bool {
if len(rules.AllowUDPPorts) == 0 {
return true
}
if rules.allowUDPPortsLookup != nil {
if rules.allowUDPPortsLookup[port] == true {
return true
}
} else {
for _, allowPort := range rules.AllowUDPPorts {
if port == allowPort {
return true
}
}
}
return rules.allowSubnet(remoteIP)
}
func (rules *TrafficRules) allowSubnet(remoteIP net.IP) bool {
for _, subnet := range rules.AllowSubnets {
// Note: ignoring error as config has been validated
_, network, _ := net.ParseCIDR(subnet)
if network.Contains(remoteIP) {
return true
}
}
return false
}
// GetMeekRateLimiterConfig gets a snapshot of the meek rate limiter
// configuration values.
func (set *TrafficRulesSet) GetMeekRateLimiterConfig() (int, int, []string, []string, int, int) {
set.ReloadableFile.RLock()
defer set.ReloadableFile.RUnlock()
GCTriggerCount := set.MeekRateLimiterGarbageCollectionTriggerCount
if GCTriggerCount <= 0 {
GCTriggerCount = DEFAULT_MEEK_RATE_LIMITER_GARBAGE_COLLECTOR_TRIGGER_COUNT
}
reapFrequencySeconds := set.MeekRateLimiterReapHistoryFrequencySeconds
if reapFrequencySeconds <= 0 {
reapFrequencySeconds = DEFAULT_MEEK_RATE_LIMITER_REAP_HISTORY_FREQUENCY_SECONDS
}
return set.MeekRateLimiterHistorySize,
set.MeekRateLimiterThresholdSeconds,
set.MeekRateLimiterRegions,
set.MeekRateLimiterISPs,
GCTriggerCount,
reapFrequencySeconds
}