You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
3.4 KiB
174 lines
3.4 KiB
2 years ago
|
package service
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"log"
|
||
|
"net"
|
||
|
"os"
|
||
|
"sync"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
func RunServe(port string) {
|
||
|
server, err := net.Listen("tcp", ":"+port)
|
||
|
if err != nil {
|
||
|
log.Printf("Listen failed: %v\n", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
client, err := server.Accept()
|
||
|
if err != nil {
|
||
|
log.Printf("Accept failed: %v", err)
|
||
|
continue
|
||
|
}
|
||
|
go process(client)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func process(client net.Conn) {
|
||
|
if err := Socks5Auth(client); err != nil {
|
||
|
log.Println("auth error:", err)
|
||
|
client.Close()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
target, err := Socks5Connect(client)
|
||
|
if err != nil {
|
||
|
log.Println("connect error:", err)
|
||
|
client.Close()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
Socks5Forward(client, target)
|
||
|
}
|
||
|
|
||
|
func Socks5Auth(client net.Conn) (err error) {
|
||
|
buf := make([]byte, 256)
|
||
|
|
||
|
// 读取 VER 和 NMETHODS
|
||
|
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")
|
||
|
}
|
||
|
|
||
|
// 读取 METHODS 列表
|
||
|
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())
|
||
|
}
|
||
|
|
||
|
_, 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)
|
||
|
// }
|
||
|
func Socks5Forward(left, right net.Conn) error {
|
||
|
var err, err1 error
|
||
|
var wg sync.WaitGroup
|
||
|
var wait = 5 * time.Second
|
||
|
wg.Add(1)
|
||
|
go func() {
|
||
|
defer wg.Done()
|
||
|
_, err1 = io.Copy(right, left)
|
||
|
right.SetReadDeadline(time.Now().Add(wait))
|
||
|
}()
|
||
|
_, err = io.Copy(left, right)
|
||
|
left.SetReadDeadline(time.Now().Add(wait))
|
||
|
wg.Wait()
|
||
|
|
||
|
if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) {
|
||
|
return err1
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|