● 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)
Code 174 Commits 1
contraband / pkg / common / units.go
← Back to directory
183 lines · 4.9 KB
Raw
1package common
2
3import (
4 "errors"
5 "fmt"
6 "math"
7 "strconv"
8 "strings"
9 "time"
10 "unicode"
11)
12
13const (
14 Byte int64 = 1
15 Kilobyte = 1024 * Byte
16 Megabyte = 1024 * Kilobyte
17 Gigabyte = 1024 * Megabyte
18 Terabyte = 1024 * Gigabyte
19)
20
21// ParseBytes converts human strings like "100KB", "50MB", "2GB", "1.5MB", "512B", "1024" into int64 bytes.
22func ParseBytes(s string) (int64, error) {
23 // Reject any string containing control characters, newlines, or non-space whitespace
24 for _, r := range s {
25 if unicode.IsSpace(r) && r != ' ' {
26 return 0, fmt.Errorf("invalid byte size string %q: contains invalid whitespace or newline", s)
27 }
28 }
29
30 s = strings.TrimSpace(s)
31 if s == "" {
32 return 0, errors.New("empty byte size string")
33 }
34
35 // Find boundary between numeric value and unit suffix
36 idx := 0
37 hasDot := false
38 for i, r := range s {
39 if unicode.IsDigit(r) {
40 idx = i + 1
41 } else if r == '.' && !hasDot {
42 hasDot = true
43 idx = i + 1
44 } else {
45 break
46 }
47 }
48
49 if idx == 0 {
50 return 0, fmt.Errorf("invalid byte size prefix: %q", s)
51 }
52
53 numStr := s[:idx]
54 unitStr := strings.ToUpper(strings.Trim(s[idx:], " "))
55
56 var multiplier int64
57 switch unitStr {
58 case "", "B":
59 multiplier = Byte
60 case "K", "KB", "KIB":
61 multiplier = Kilobyte
62 case "M", "MB", "MIB":
63 multiplier = Megabyte
64 case "G", "GB", "GIB":
65 multiplier = Gigabyte
66 case "T", "TB", "TIB":
67 multiplier = Terabyte
68 default:
69 return 0, fmt.Errorf("unrecognized byte size unit: %q", unitStr)
70 }
71
72 // If numeric part is an integer, perform exact integer arithmetic with overflow check
73 if !strings.Contains(numStr, ".") {
74 val, err := strconv.ParseUint(numStr, 10, 64)
75 if err != nil {
76 return 0, fmt.Errorf("byte size %q exceeds maximum allowable value: %w", s, err)
77 }
78 if val > uint64(math.MaxInt64)/uint64(multiplier) {
79 return 0, fmt.Errorf("byte size %q exceeds maximum allowable value (integer overflow)", s)
80 }
81 return int64(val * uint64(multiplier)), nil
82 }
83
84 // Floating point path for decimal values like "1.5MB"
85 num, err := strconv.ParseFloat(numStr, 64)
86 if err != nil {
87 return 0, fmt.Errorf("failed to parse numeric value %q: %w", numStr, err)
88 }
89 if num < 0 {
90 return 0, fmt.Errorf("negative byte size not allowed: %f", num)
91 }
92 if math.IsNaN(num) || math.IsInf(num, 0) {
93 return 0, fmt.Errorf("invalid numeric value %q", numStr)
94 }
95
96 f := num * float64(multiplier)
97 if math.IsNaN(f) || math.IsInf(f, 0) || f >= float64(math.MaxInt64) {
98 return 0, fmt.Errorf("byte size %q exceeds maximum allowable value", s)
99 }
100
101 total := int64(f)
102 if total < 0 {
103 return 0, fmt.Errorf("byte size %q caused integer overflow", s)
104 }
105 return total, nil
106}
107
108// FormatBytes converts raw bytes into a human-readable string (e.g. "50.00 MB", "1.50 GB").
109func FormatBytes(b int64) string {
110 if b < 0 {
111 return fmt.Sprintf("%d B", b)
112 }
113 switch {
114 case b >= Terabyte:
115 return fmt.Sprintf("%.2f TB", float64(b)/float64(Terabyte))
116 case b >= Gigabyte:
117 return fmt.Sprintf("%.2f GB", float64(b)/float64(Gigabyte))
118 case b >= Megabyte:
119 return fmt.Sprintf("%.2f MB", float64(b)/float64(Megabyte))
120 case b >= Kilobyte:
121 return fmt.Sprintf("%.2f KB", float64(b)/float64(Kilobyte))
122 default:
123 return fmt.Sprintf("%d B", b)
124 }
125}
126
127// ParseBandwidthRate converts rate strings like "100KB/s", "5MB/sec", "unlimited", "0", "none" into bytes per second.
128// Returns 0.0 for unlimited bandwidth.
129func ParseBandwidthRate(s string) (float64, error) {
130 for _, r := range s {
131 if unicode.IsSpace(r) && r != ' ' {
132 return 0.0, fmt.Errorf("invalid bandwidth rate %q: contains invalid whitespace or newline", s)
133 }
134 }
135
136 s = strings.TrimSpace(s)
137 lower := strings.ToLower(s)
138 if lower == "" || lower == "unlimited" || lower == "0" || lower == "none" || lower == "0/s" {
139 return 0.0, nil
140 }
141
142 // Strip trailing /s or /sec if present
143 clean := s
144 if strings.HasSuffix(lower, "/sec") {
145 clean = s[:len(s)-4]
146 } else if strings.HasSuffix(lower, "/s") {
147 clean = s[:len(s)-2]
148 }
149
150 bytes, err := ParseBytes(clean)
151 if err != nil {
152 return 0.0, fmt.Errorf("invalid bandwidth rate %q: %w", s, err)
153 }
154 if bytes < 0 {
155 return 0.0, fmt.Errorf("bandwidth rate cannot be negative: %q", s)
156 }
157
158 return float64(bytes), nil
159}
160
161// FormatBandwidthRate converts bytes per second into human-readable rate string (e.g. "5.00 MB/s", "unlimited").
162func FormatBandwidthRate(bytesPerSec float64) string {
163 if bytesPerSec <= 0 || math.IsNaN(bytesPerSec) {
164 return "unlimited"
165 }
166 if math.IsInf(bytesPerSec, 0) || bytesPerSec >= float64(math.MaxInt64) {
167 return "unlimited"
168 }
169 return fmt.Sprintf("%s/s", FormatBytes(int64(bytesPerSec)))
170}
171
172// ParseDuration parses strings like "500ms", "1.5s", "10s", "1m".
173func ParseDuration(s string) (time.Duration, error) {
174 s = strings.TrimSpace(s)
175 if s == "" {
176 return 0, errors.New("empty duration string")
177 }
178 // If bare integer is provided, treat as seconds
179 if val, err := strconv.Atoi(s); err == nil {
180 return time.Duration(val) * time.Second, nil
181 }
182 return time.ParseDuration(s)
183}