[SHEHZADE//ABDULLAH ANSARI]
Red Team Consultant @ Google | MS in Cybersecurity @ NYU
● Notice //GitHub (@shehzade) is temporarily suspended pending an automated false-positive review. All tools are hosted on this Code Mirror and available on request (contact); GitHub links will return once reinstated.
PUBLIC MIRRORGo v1.0
Multi-protocol network egress assessment and DLP verification framework featuring automated L4 sweeps, corporate proxy traversal, and covert protocol smuggling across 20+ channels.
$
git clone https://shehzade.io/repos/contraband.git
Copy
Source ZIP (1.93 MB)
130 lines · 2.4 KB
| 1 | package sweep |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "crypto/rand" |
| 6 | "math/big" |
| 7 | "sync" |
| 8 | "time" |
| 9 | ) |
| 10 | |
| 11 | // TokenBucket implements a pure Go thread-safe token bucket rate limiter. |
| 12 | type TokenBucket struct { |
| 13 | mu sync.Mutex |
| 14 | capacity float64 |
| 15 | tokens float64 |
| 16 | rate float64 // tokens per second |
| 17 | lastRefill time.Time |
| 18 | } |
| 19 | |
| 20 | // NewTokenBucket creates a token bucket with capacity and refill rate in tokens/sec. |
| 21 | func NewTokenBucket(rate, capacity int) *TokenBucket { |
| 22 | if rate < 1 { |
| 23 | rate = 1 |
| 24 | } |
| 25 | if capacity < 1 { |
| 26 | capacity = 1 |
| 27 | } |
| 28 | now := time.Now() |
| 29 | return &TokenBucket{ |
| 30 | capacity: float64(capacity), |
| 31 | tokens: float64(capacity), |
| 32 | rate: float64(rate), |
| 33 | lastRefill: now, |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | // Wait blocks until a token is available or ctx is canceled. |
| 38 | func (tb *TokenBucket) Wait(ctx context.Context) error { |
| 39 | for { |
| 40 | select { |
| 41 | case <-ctx.Done(): |
| 42 | return ctx.Err() |
| 43 | default: |
| 44 | } |
| 45 | |
| 46 | tb.mu.Lock() |
| 47 | now := time.Now() |
| 48 | elapsed := now.Sub(tb.lastRefill).Seconds() |
| 49 | if elapsed > 0 { |
| 50 | tb.tokens += elapsed * tb.rate |
| 51 | if tb.tokens > tb.capacity { |
| 52 | tb.tokens = tb.capacity |
| 53 | } |
| 54 | tb.lastRefill = now |
| 55 | } |
| 56 | |
| 57 | if tb.tokens >= 1.0 { |
| 58 | tb.tokens -= 1.0 |
| 59 | tb.mu.Unlock() |
| 60 | return nil |
| 61 | } |
| 62 | |
| 63 | // Calculate sleep time until 1 token is available |
| 64 | missing := 1.0 - tb.tokens |
| 65 | sleepSec := missing / tb.rate |
| 66 | sleepDur := time.Duration(sleepSec * float64(time.Second)) |
| 67 | if sleepDur < time.Microsecond { |
| 68 | sleepDur = time.Microsecond |
| 69 | } |
| 70 | tb.mu.Unlock() |
| 71 | |
| 72 | timer := time.NewTimer(sleepDur) |
| 73 | select { |
| 74 | case <-ctx.Done(): |
| 75 | if !timer.Stop() { |
| 76 | select { |
| 77 | case <-timer.C: |
| 78 | default: |
| 79 | } |
| 80 | } |
| 81 | return ctx.Err() |
| 82 | case <-timer.C: |
| 83 | } |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | // ApplyJitter sleeps for a random duration between min and max, respecting ctx. |
| 88 | func ApplyJitter(ctx context.Context, min, max time.Duration) error { |
| 89 | if max <= 0 || min >= max { |
| 90 | if min > 0 { |
| 91 | timer := time.NewTimer(min) |
| 92 | select { |
| 93 | case <-ctx.Done(): |
| 94 | if !timer.Stop() { |
| 95 | select { |
| 96 | case <-timer.C: |
| 97 | default: |
| 98 | } |
| 99 | } |
| 100 | return ctx.Err() |
| 101 | case <-timer.C: |
| 102 | return nil |
| 103 | } |
| 104 | } |
| 105 | return nil |
| 106 | } |
| 107 | |
| 108 | diff := max - min |
| 109 | n, err := rand.Int(rand.Reader, big.NewInt(int64(diff))) |
| 110 | var jitterDur time.Duration |
| 111 | if err == nil { |
| 112 | jitterDur = min + time.Duration(n.Int64()) |
| 113 | } else { |
| 114 | jitterDur = min |
| 115 | } |
| 116 | |
| 117 | timer := time.NewTimer(jitterDur) |
| 118 | select { |
| 119 | case <-ctx.Done(): |
| 120 | if !timer.Stop() { |
| 121 | select { |
| 122 | case <-timer.C: |
| 123 | default: |
| 124 | } |
| 125 | } |
| 126 | return ctx.Err() |
| 127 | case <-timer.C: |
| 128 | return nil |
| 129 | } |
| 130 | } |