2024年6月7日11:21:00 socket5 代理
commit
f79557ae04
|
|
@ -0,0 +1,6 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
const (
|
||||||
|
LOCAL_SOCKET_ADDR = "127.0.0.1"
|
||||||
|
LOCAL_SOCKET_PORT = 1080
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateListen 监听
|
||||||
|
func CreateListen(serverAddr string) (*net.TCPListener, error) {
|
||||||
|
tcpAddr, err := net.ResolveTCPAddr("tcp", serverAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("创建监听出错:" + serverAddr)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tcpListen, err := net.ListenTCP("tcp", tcpAddr)
|
||||||
|
return tcpListen, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateConn 创建连接
|
||||||
|
func CreateConn(serverAddr string) (*net.TCPConn, error) {
|
||||||
|
tcpAddr, err := net.ResolveTCPAddr("tcp", serverAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("创建连接出错:" + serverAddr)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn, err := net.DialTCP("tcp", nil, tcpAddr)
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-socket5-proxy/config"
|
||||||
|
"go-socket5-proxy/socket5"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
server := &socket5.Socket5Server{
|
||||||
|
IP: config.LOCAL_SOCKET_ADDR,
|
||||||
|
Port: config.LOCAL_SOCKET_PORT,
|
||||||
|
}
|
||||||
|
server.Run()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package socket5
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ERROR_SOCKET_VERSION_SUPPORTED = errors.New("不支持该socket版本")
|
||||||
|
ERROR_COMMAND_NOT_SUPPORTED = errors.New("不支持该COMMAND命令")
|
||||||
|
ERRADDRESS_TYPE_NOT_SUPPORTED = errors.New("不支持该地址类型")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SOCKET_5_VERSION = 0x05
|
||||||
|
Method_NO_AUTH = 0x00
|
||||||
|
Method_GSS_API = 0x01
|
||||||
|
Method_PASS_WORD = 0x02
|
||||||
|
Method_NO_ACCEPT_TABLE = 0xff
|
||||||
|
ReservedFild = 0x00
|
||||||
|
)
|
||||||
|
|
||||||
|
type Method = byte
|
||||||
|
|
||||||
|
type ClientAuthMessage struct {
|
||||||
|
Version byte
|
||||||
|
|
||||||
|
NMethods byte
|
||||||
|
|
||||||
|
Methods []Method
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerAuthMessage(conn net.Conn, method Method) error {
|
||||||
|
buf := []byte{SOCKET_5_VERSION, method}
|
||||||
|
_, err := conn.Write(buf)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClientAuthMessage(conn net.Conn) (*ClientAuthMessage, error) {
|
||||||
|
|
||||||
|
//读取socket版本
|
||||||
|
buf := make([]byte, 2)
|
||||||
|
_, err := io.ReadFull(conn, buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//校验socket 版本
|
||||||
|
if buf[0] != SOCKET_5_VERSION {
|
||||||
|
return nil, ERROR_SOCKET_VERSION_SUPPORTED
|
||||||
|
}
|
||||||
|
|
||||||
|
//读取method
|
||||||
|
nmethos := buf[1]
|
||||||
|
|
||||||
|
buf = make([]byte, nmethos)
|
||||||
|
_, err = io.ReadFull(conn, buf)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ClientAuthMessage{
|
||||||
|
Version: SOCKET_5_VERSION,
|
||||||
|
NMethods: nmethos,
|
||||||
|
Methods: buf,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
package socket5
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClientRequestMessage struct {
|
||||||
|
CMD Command
|
||||||
|
Address string
|
||||||
|
Port uint16
|
||||||
|
AddressType Command
|
||||||
|
}
|
||||||
|
|
||||||
|
type Command = byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
IPV4_LENGHT = 4
|
||||||
|
IPV6_LENGHT = 6
|
||||||
|
PORT_LENGHT = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CmdConnect Command = 0x01
|
||||||
|
CmdBind Command = 0x02
|
||||||
|
CmdUDP Command = 0x03
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddressType = byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeIPV4 AddressType = 0x01
|
||||||
|
TypeDoMain AddressType = 0x03
|
||||||
|
TypeIPV6 AddressType = 0x04
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewClientRequestMessage(conn net.Conn) (*ClientRequestMessage, error) {
|
||||||
|
// 版本 命令 reseved 地址类型
|
||||||
|
buf := make([]byte, 4)
|
||||||
|
if _, err := io.ReadFull(conn, buf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
version, command, reserved, addType := buf[0], buf[1], buf[2], buf[3]
|
||||||
|
if version != SOCKET_5_VERSION {
|
||||||
|
return nil, ERROR_SOCKET_VERSION_SUPPORTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if command != CmdConnect && command != CmdBind && command != CmdUDP {
|
||||||
|
return nil, ERROR_COMMAND_NOT_SUPPORTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if reserved != ReservedFild {
|
||||||
|
return nil, ERROR_SOCKET_VERSION_SUPPORTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if addType == TypeIPV4 || addType == TypeDoMain {
|
||||||
|
var message ClientRequestMessage
|
||||||
|
message.CMD = command
|
||||||
|
message.AddressType = addType
|
||||||
|
|
||||||
|
//fmt.Printf("请求地址类型为:%v\n", addType)
|
||||||
|
|
||||||
|
switch addType {
|
||||||
|
|
||||||
|
case TypeIPV6:
|
||||||
|
buf = make([]byte, IPV6_LENGHT)
|
||||||
|
if _, err := io.ReadFull(conn, buf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ip := net.ParseIP(string(buf))
|
||||||
|
message.Address = ip.String()
|
||||||
|
//fmt.Println("TypeIPV6 地址为:" + ip.String())
|
||||||
|
case TypeIPV4:
|
||||||
|
buf = make([]byte, IPV4_LENGHT)
|
||||||
|
if _, err := io.ReadFull(conn, buf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ip := net.IP(buf)
|
||||||
|
message.Address = ip.String()
|
||||||
|
//fmt.Println("TypeIPV4 地址为:" + ip.String())
|
||||||
|
case TypeDoMain:
|
||||||
|
|
||||||
|
if _, err := io.ReadFull(conn, buf[:1]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
domain_length := buf[0]
|
||||||
|
if domain_length > IPV4_LENGHT {
|
||||||
|
buf = make([]byte, domain_length)
|
||||||
|
}
|
||||||
|
if _, err := io.ReadFull(conn, buf[:domain_length]); err != nil {
|
||||||
|
message.Address = string(buf[:domain_length])
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Println("TypeDoMain 地址为:" + message.Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
//读取 端口
|
||||||
|
if _, err := io.ReadFull(conn, buf[:PORT_LENGHT]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
message.Port = (uint16(buf[0]) << 8) + uint16(buf[1])
|
||||||
|
return &message, nil
|
||||||
|
} else {
|
||||||
|
return nil, ERRADDRESS_TYPE_NOT_SUPPORTED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReplyType = byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
ReplySuccess ReplyType = iota
|
||||||
|
ReplyServerFailure
|
||||||
|
ReplyConnectionNotAllowed
|
||||||
|
ReplyNetworkUnreachable
|
||||||
|
ReplyHostUnreachable
|
||||||
|
ReplyConnectionRefused
|
||||||
|
ReplyTTLExpired
|
||||||
|
ReplyCommandNotSupported
|
||||||
|
ReplyAddressTypeNotSupported
|
||||||
|
)
|
||||||
|
|
||||||
|
func WriteRequestSuccessMessage(conn net.Conn, ip net.IP, port uint16) error {
|
||||||
|
|
||||||
|
addressType := TypeIPV4
|
||||||
|
if len(ip) == IPV6_LENGHT {
|
||||||
|
addressType = TypeIPV6
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write version, reply success, reserved, address type
|
||||||
|
_, err := conn.Write([]byte{SOCKET_5_VERSION, ReplySuccess, ReservedFild, addressType})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write bind IP(IPV4/IPV6)
|
||||||
|
if _, err := conn.Write(ip); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// write bind port
|
||||||
|
buf := make([]byte, 2)
|
||||||
|
buf[0] = byte(port >> 8)
|
||||||
|
buf[1] = byte(port - uint16(buf[0]))
|
||||||
|
_, err = conn.Write(buf)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteRequestFailureMessage(conn net.Conn, replyType ReplyType) error {
|
||||||
|
_, err := conn.Write([]byte{SOCKET_5_VERSION, replyType, ReservedFild, TypeIPV4, 0, 0, 0, 0, 0, 0})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
package socket5
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"go-socket5-proxy/helper"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server interface {
|
||||||
|
Run() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Socket5Server struct {
|
||||||
|
Port int64
|
||||||
|
IP string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socket5Server) Run() error {
|
||||||
|
address := fmt.Sprintf("%s:%d", s.IP, s.Port)
|
||||||
|
fmt.Printf("%s:%d \n", s.IP, s.Port)
|
||||||
|
listen, err := helper.CreateListen(address)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := listen.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("连接失败:%s: %s", conn.RemoteAddr(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer conn.Close()
|
||||||
|
err = handleConnection(conn)
|
||||||
|
if err != nil {
|
||||||
|
//log.Printf("处理连接 handleConnection %s: %s", conn.RemoteAddr(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理连接 handleConnection
|
||||||
|
func handleConnection(conn net.Conn) error {
|
||||||
|
|
||||||
|
//协商过程
|
||||||
|
if err := auth(conn); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//请求过程
|
||||||
|
targetConn, err := request(conn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if targetConn == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
//转发过程
|
||||||
|
return forward(conn, targetConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func forward(conn net.Conn, targetConn net.Conn) error {
|
||||||
|
defer targetConn.Close()
|
||||||
|
go io.Copy(targetConn, conn)
|
||||||
|
_, err := io.Copy(conn, targetConn)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func request(conn net.Conn) (net.Conn, error) {
|
||||||
|
message, err := NewClientRequestMessage(conn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//检查命令是否支持
|
||||||
|
if message.CMD != CmdConnect {
|
||||||
|
return nil, WriteRequestFailureMessage(conn, ReplyCommandNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
//ipv6
|
||||||
|
if message.AddressType == TypeIPV6 {
|
||||||
|
return nil, WriteRequestFailureMessage(conn, ReplyAddressTypeNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
//请求访问目标服务器
|
||||||
|
addres := fmt.Sprintf("%s:%d", message.Address, message.Port)
|
||||||
|
//fmt.Printf("请求访问目标服务器:%v\n", message.AddressType)
|
||||||
|
targetConn, err := net.Dial("tcp", addres)
|
||||||
|
if err != nil {
|
||||||
|
return nil, WriteRequestFailureMessage(conn, ReplyConnectionRefused)
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送成功
|
||||||
|
addrValue := targetConn.LocalAddr()
|
||||||
|
addr := addrValue.(*net.TCPAddr)
|
||||||
|
|
||||||
|
if targetConn == nil {
|
||||||
|
fmt.Printf("targetConn is nil :" + addr.IP.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetConn, WriteRequestSuccessMessage(conn, addr.IP, uint16(addr.Port))
|
||||||
|
}
|
||||||
|
|
||||||
|
func auth(conn net.Conn) error {
|
||||||
|
client, err := NewClientAuthMessage(conn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//log.Println(client.Version, client.NMethods, client.Methods)
|
||||||
|
|
||||||
|
// 是否支持 no-auth
|
||||||
|
var accept_table bool
|
||||||
|
for _, method := range client.Methods {
|
||||||
|
if method == Method_NO_AUTH {
|
||||||
|
accept_table = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !accept_table {
|
||||||
|
NewServerAuthMessage(conn, Method_NO_ACCEPT_TABLE)
|
||||||
|
return errors.New("方法不支持 not auth")
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewServerAuthMessage(conn, Method_NO_AUTH)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue