go-socket5-proxy/socket5/socket5.go

132 lines
2.6 KiB
Go

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)
}