The first socks5 proxy with traffic limit, the next socks5 proxy without any limit.
Use curl download something like:
curl -x socks5://127.0.0.1:10801 -O https://mirrors.xxxx.iso
At first, curl downloads fine, the traffic limit is working, but after while curl speed becomes 0.
package main
import (
"fmt"
"github.com/juju/ratelimit"
"io"
"net"
)
var nextProxy = "127.0.0.1:10802"
func main() {
server, err := net.Listen("tcp", ":10801")
if err != nil {
fmt.Printf("Listen failed: %v\n", err)
return
}
for {
client, err := server.Accept()
if err != nil {
fmt.Printf("Accept failed: %v", err)
continue
}
go handle(client)
}
}
func handle(conn net.Conn) {
// add close
defer conn.Close()
// next socks5 proxy
nextConn, err := net.Dial("tcp", nextProxy)
if err != nil {
fmt.Println("Failed to connect to next proxy:", err)
conn.Close()
return
}
defer nextConn.Close()
go func() {
_, err := Copy(nextConn, conn)
if err != nil {
fmt.Println("Error copying data to next proxy:", err)
conn.Close()
}
}()
_, err = Copy(conn, nextConn)
if err != nil {
fmt.Println("Error copying data from next proxy:", err)
conn.Close()
}
}
func Copy(left io.Writer, right io.Reader) (int64, error) {
right = ratelimit.Reader(right, ratelimit.NewBucketWithRate(102400, 102400))
return io.Copy(left, right)
}
I've tried another Copy
like:
func copyWithRateLimit(dst io.Writer, src io.Reader, limiter *ratelimit.Bucket) {
// buffer
buf := make([]byte, 32*1024) // 32KB buffer
for {
n, err := src.Read(buf)
if err != nil {
if err == io.EOF {
return
}
fmt.Println("Error reading from source:", err)
return
}
// Rate limit the data
if limit := limiter.WaitMaxDuration(int64(n), time.Second); !limit {
fmt.Println("Error rate limiting:", err)
return
}
if _, err := dst.Write(buf[:n]); err != nil {
fmt.Println("Error writing to destination:", err)
return
}
}
}
Even if you increase the buffer to 64*1024, the speed still goes to 0 and eventually it doesn't work.
There is the next socks5 proxy without traffic limit like:
package main
import (
"encoding/binary"
"errors"
"fmt"
"io"
"net"
)
func main() {
server, err := net.Listen("tcp", ":10802")
if err != nil {
fmt.Printf("Listen failed: %v\n", err)
return
}
for {
client, err := server.Accept()
if err != nil {
fmt.Printf("Accept failed: %v", err)
continue
}
go process(client)
}
}
func process(client net.Conn) {
if err := Socks5Auth(client); err != nil {
fmt.Println("auth error:", err)
client.Close()
return
}
target, err := Socks5Connect(client)
if err != nil {
fmt.Println("connect error:", err)
client.Close()
return
}
Socks5Forward(client, target)
}
func Socks5Auth(client net.Conn) (err error) {
buf := make([]byte, 256)
n, err := io.ReadFull(client, buf[:2])
if n != 2 {
return errors.New("reading header: " + err.Error())
}
ver, nMethods := int(buf[0]), int(buf[1])
if ver != 5 {
return errors.New("invalid version")
}
n, err = io.ReadFull(client, buf[:nMethods])
if n != nMethods {
return errors.New("reading methods: " + err.Error())
}
n, err = client.Write([]byte{0x05, 0x00})
if n != 2 || err != nil {
return errors.New("write rsp: " + err.Error())
}
return nil
}
func Socks5Connect(client net.Conn) (net.Conn, error) {
buf := make([]byte, 256)
n, err := io.ReadFull(client, buf[:4])
if n != 4 {
return nil, errors.New("read header: " + err.Error())
}
ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3]
if ver != 5 || cmd != 1 {
return nil, errors.New("invalid ver/cmd")
}
addr := ""
switch atyp {
case 1:
n, err = io.ReadFull(client, buf[:4])
if n != 4 {
return nil, errors.New("invalid IPv4: " + err.Error())
}
addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
case 3:
n, err = io.ReadFull(client, buf[:1])
if n != 1 {
return nil, errors.New("invalid hostname: " + err.Error())
}
addrLen := int(buf[0])
n, err = io.ReadFull(client, buf[:addrLen])
if n != addrLen {
return nil, errors.New("invalid hostname: " + err.Error())
}
addr = string(buf[:addrLen])
case 4:
return nil, errors.New("IPv6: no supported yet")
default:
return nil, errors.New("invalid atyp")
}
n, err = io.ReadFull(client, buf[:2])
if n != 2 {
return nil, errors.New("read port: " + err.Error())
}
port := binary.BigEndian.Uint16(buf[:2])
destAddrPort := fmt.Sprintf("%s:%d", addr, port)
dest, err := net.Dial("tcp", destAddrPort)
if err != nil {
return nil, errors.New("dial dst: " + err.Error())
}
n, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
if err != nil {
dest.Close()
return nil, errors.New("write rsp: " + err.Error())
}
return dest, nil
}
func Socks5Forward(client, target net.Conn) {
forward := func(src, dest net.Conn) {
defer src.Close()
defer dest.Close()
io.Copy(src, dest)
}
go forward(client, target)
go forward(target, client)
}
Launching both programs on the same machine and curl downloading the file gives the following result:
Did a few tests.
curl
downloads the file normally.curl
downloads only through the second socks5 proxy, and set a speed limit on the second socks5 proxy, curl
downloads the file normally.curl
downloads the file is ok!!!I checked the below things. I think there is no problem in your code itself. So I decided your environment can be one of the possible causes.
(1) Copy
function itself works well. I checked it by using this code. https://go.dev/play/p/5a-T4tIaEFC
(2) Using your added code for sock5 proxy, I checked it works well too.