Skip to content

Commit 9a1a816

Browse files
committed
2025-06-22 23:43:55
1 parent 42605cf commit 9a1a816

File tree

8 files changed

+1192
-19
lines changed

8 files changed

+1192
-19
lines changed

cmd/daze/main.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/mohanson/daze"
1515
"github.com/mohanson/daze/lib/doa"
1616
"github.com/mohanson/daze/lib/gracefulexit"
17+
"github.com/mohanson/daze/lib/rate"
1718
"github.com/mohanson/daze/protocol/ashe"
1819
"github.com/mohanson/daze/protocol/baboon"
1920
"github.com/mohanson/daze/protocol/czar"
@@ -68,6 +69,7 @@ func main() {
6869
flDnserv = flag.String("dns", "", "specifies the DNS, DoT or DoH server")
6970
flExtend = flag.String("e", "", "extend data for different protocols")
7071
flGpprof = flag.String("g", "", "specify an address to enable net/http/pprof")
72+
flLimits = flag.String("b", "", "set the maximum bandwidth in bytes per second, for example, 128k or 1.5m")
7173
flCipher = flag.String("k", "daze", "password, should be same with the one specified by client")
7274
flListen = flag.String("l", "0.0.0.0:1081", "listen address")
7375
flProtoc = flag.String("p", "ashe", "protocol {ashe, baboon, czar, dahlia}")
@@ -90,21 +92,37 @@ func main() {
9092
case "ashe":
9193
server := ashe.NewServer(*flListen, *flCipher)
9294
defer server.Close()
95+
if *flLimits != "" {
96+
n := daze.SizeParser(*flLimits)
97+
server.Limits = rate.NewLimiter(rate.Limit(n), 1024*1024)
98+
}
9399
doa.Nil(server.Run())
94100
case "baboon":
95101
server := baboon.NewServer(*flListen, *flCipher)
102+
defer server.Close()
96103
if *flExtend != "" {
97104
server.Masker = *flExtend
98105
}
99-
defer server.Close()
106+
if *flLimits != "" {
107+
n := daze.SizeParser(*flLimits)
108+
server.Limits = rate.NewLimiter(rate.Limit(n), 1024*1024)
109+
}
100110
doa.Nil(server.Run())
101111
case "czar":
102112
server := czar.NewServer(*flListen, *flCipher)
103113
defer server.Close()
114+
if *flLimits != "" {
115+
n := daze.SizeParser(*flLimits)
116+
server.Limits = rate.NewLimiter(rate.Limit(n), 1024*1024)
117+
}
104118
doa.Nil(server.Run())
105119
case "dahlia":
106120
server := dahlia.NewServer(*flListen, *flExtend, *flCipher)
107121
defer server.Close()
122+
if *flLimits != "" {
123+
n := daze.SizeParser(*flLimits)
124+
server.Limits = rate.NewLimiter(rate.Limit(n), 1024*1024)
125+
}
108126
doa.Nil(server.Run())
109127
}
110128
if *flGpprof != "" {

daze.go

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/mohanson/daze/lib/doa"
3131
"github.com/mohanson/daze/lib/lru"
3232
"github.com/mohanson/daze/lib/pretty"
33+
"github.com/mohanson/daze/lib/rate"
3334
)
3435

3536
// ============================================================================
@@ -1042,18 +1043,6 @@ func OpenFile(name string) (io.ReadCloser, error) {
10421043
return os.Open(name)
10431044
}
10441045

1045-
// RandomReader is a simple random number generator. Note that it is not cryptographically secure, but for daze, the
1046-
// randomness it provides is enough.
1047-
type RandomReader struct{}
1048-
1049-
// Read implements io.Reader.
1050-
func (r *RandomReader) Read(p []byte) (int, error) {
1051-
for i := range len(p) {
1052-
p[i] = byte(rand.Uint64())
1053-
}
1054-
return len(p), nil
1055-
}
1056-
10571046
// The PrettyReader struct represents a custom reader that keeps track of read bytes and prints progress.
10581047
type PrettyReader struct {
10591048
E uint64 // Total number of bytes read so far
@@ -1072,12 +1061,66 @@ func (r *PrettyReader) Read(p []byte) (int, error) {
10721061
return n, err
10731062
}
10741063

1064+
// RandomReader is a simple random number generator. Note that it is not cryptographically secure, but for daze, the
1065+
// randomness it provides is enough.
1066+
type RandomReader struct{}
1067+
1068+
// Read implements io.Reader.
1069+
func (r *RandomReader) Read(p []byte) (int, error) {
1070+
for i := range len(p) {
1071+
p[i] = byte(rand.Uint64())
1072+
}
1073+
return len(p), nil
1074+
}
1075+
1076+
// RateConn wraps a net.Conn with a per-conn and a rate limiter.
1077+
type RateConn struct {
1078+
Conn io.ReadWriteCloser
1079+
Rate *rate.Limiter
1080+
}
1081+
1082+
// Close closes the connection.
1083+
func (r *RateConn) Close() error {
1084+
return r.Conn.Close()
1085+
}
1086+
1087+
// Read reads up to len(p) bytes into p.
1088+
func (r *RateConn) Read(p []byte) (int, error) {
1089+
n, err := r.Conn.Read(p)
1090+
r.Rate.WaitN(context.Background(), n)
1091+
return n, err
1092+
}
1093+
1094+
// Write writes len(p) bytes from p to the underlying data stream.
1095+
func (r *RateConn) Write(p []byte) (int, error) {
1096+
n, err := r.Conn.Write(p)
1097+
r.Rate.WaitN(context.Background(), n)
1098+
return n, err
1099+
}
1100+
10751101
// Salt converts the stupid password passed in by the user to 32-sized byte array.
10761102
func Salt(s string) []byte {
10771103
h := sha256.Sum256([]byte(s))
10781104
return h[:]
10791105
}
10801106

1107+
// SizeParser converts a string like "1K", "1M", or "1G" to bytes as uint64. It expects the input string to end with a
1108+
// unit (K, M, or G) and panics if the unit is invalid. The number part can be a float (e.g., "1.5M") and is converted
1109+
// to bytes based on the unit.
1110+
func SizeParser(s string) uint64 {
1111+
f := doa.Try(strconv.ParseFloat(s[:len(s)-1], 64))
1112+
u := strings.ToLower(s[len(s)-1:])
1113+
switch u {
1114+
case "k":
1115+
return uint64(f * 1024)
1116+
case "m":
1117+
return uint64(f * 1024 * 1024)
1118+
case "g":
1119+
return uint64(f * 1024 * 1024 * 1024)
1120+
}
1121+
panic("unreachable")
1122+
}
1123+
10811124
// ============================================================================
10821125
// ___ ___ ___ ___
10831126
// /\ \ /\ \ /\ \ /\ \

0 commit comments

Comments
 (0)