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