proxy-service.zip

package main

import (
    "fmt"
    "io"
    "log"
    "net"
    "os"
    // "strconv"
    "sync"
)

var localIP = ""
var domainsMap sync.Map

// 域名解析
func DomainResolution(domain string) (string, error) {
    if domain, ok := domainsMap.Load(domain); ok {
        return domain.(string), nil
    }
    ips, err := net.LookupIP(domain)
    if err != nil {
        return "", fmt.Errorf("无法解析域名: %w", err)
    }
    var addr string
    for _, ip := range ips {
        if ip.To4() != nil {
            addr = ip.String()
            break
        }
    }

    domainsMap.Store(domain, addr)
    return "", fmt.Errorf("无法解析域名: %w", err)
}

// 如果接口不存在或没有IPv4地址,则返回空字符串。
func Init(interfaceName string) {
    interfaces, err := net.Interfaces()
    if err != nil {
        log.Println("获取网络接口列表失败:", err)
        os.Exit(0)
    }

    for _, iface := range interfaces {
        if iface.Name == interfaceName {
            addrs, err := iface.Addrs()
            if err != nil {
                log.Println("获取接口地址失败:", err)
                os.Exit(0)
            }
            for _, addr := range addrs {
                // 检查是否为IPv4地址
                ipNet, ok := addr.(*net.IPNet)
                if ok && ipNet.IP.To4() != nil {
                    localIP = ipNet.IP.String()
                    log.Println("获取网卡IP:", localIP)
                    return
                }
            }
            log.Println("获取网络接口列表失败:", err)
            os.Exit(0)
        }
    }
    log.Println("指定网卡%s不存在", interfaceName)
    os.Exit(0)
}

// 指定网卡链接
func dialWithSpecificLocalAddr(remoteAddr, localIP string, remotePort int) (net.Conn, error) {
    // 创建一个TCP地址用于绑定本地端点
    localAddr := net.TCPAddr{
        IP:   net.ParseIP(localIP),
        Port: 0, // 使用0可以让系统自动选择一个可用端口
    }

    // 连接到远程地址
    conn, err := net.DialTCP("tcp", &localAddr, &net.TCPAddr{
        IP:   net.ParseIP(remoteAddr),
        Port: remotePort,
    })

    if err != nil {
        return nil, err
    }

    return conn, nil
}

// 获取ip,端口
func getTargetIpPort(conn net.Conn) (string, int, error) {
    // 读取目标服务器地址
    var addr string
    atyp, err := readByte(conn)
    if err != nil {
        return "", 0, fmt.Errorf("读取地址类型失败:", err)
    }
    switch atyp {
    case 0x01: // IPv4
        ip := make([]byte, 4)
        if _, err := io.ReadFull(conn, ip); err != nil {
            err = fmt.Errorf("读取IPv4地址失败:", err)
        }
        addr = net.IP(ip).String()
    case 0x03: // 域名
        len, err := readByte(conn)
        if err != nil {
            err = fmt.Errorf("读取域名长度失败:", err)

        }
        domain := make([]byte, len)
        if _, err := io.ReadFull(conn, domain); err != nil {
            err = fmt.Errorf("读取域名失败:", err)

        }
        addr = string(domain)
        addr, err = DomainResolution(addr)
    case 0x04: // IPv6
        ip := make([]byte, 16)
        if _, err := io.ReadFull(conn, ip); err != nil {
            err = fmt.Errorf("读取IPv6地址失败:", err)
        }
        addr = net.IP(ip).String()
    default:
        err = fmt.Errorf("不支持的地址类型:", atyp)
    }
    if err != nil {
        return "", 0, err
    }
    // 读取端口
    portBytes := make([]byte, 2)
    if _, err := io.ReadFull(conn, portBytes); err != nil {
        return "", 0, fmt.Errorf("读取端口失败:", err)
    }
    destPort := uint16(portBytes[0])<<8 + uint16(portBytes[1])
    return addr, int(destPort), nil
}

// 检查版本
func checkVersion(conn net.Conn) error {
    // 读取SOCKS5代理协议的版本号
    version, err := readByte(conn)
    if err != nil {
        return fmt.Errorf("读取版本号失败:%v", err)
    }

    // 只支持SOCKS5
    if version != 0x05 {
        return fmt.Errorf("不支持的SOCKS版本:", version)
    }
    return nil
}

// 认证
func auth(conn net.Conn) error {
    // 读取客户端支持的认证方法数量
    nmethods, err := readByte(conn)
    if err != nil {
        return fmt.Errorf("读取认证方法数量失败:", err)
    }

    // 跳过客户端支持的认证方法列表
    _, err = io.CopyN(io.Discard, conn, int64(nmethods))
    if err != nil {
        return fmt.Errorf("跳过认证方法列表失败:", err)
    }

    // 选择无需认证(0x00)
    if _, err := conn.Write([]byte{0x05, 0x00}); err != nil {
        return fmt.Errorf("发送无需认证的响应失败:", err)
    }
    return nil
}

// readByte 从conn中读取单个字节,返回读取的字节和可能发生的错误。
func readByte(conn net.Conn) (byte, error) {
    b := make([]byte, 1)
    _, err := io.ReadFull(conn, b)
    return b[0], err
}

// handleClient 处理来自客户端的连接。
func handleClient(conn net.Conn) {
    defer conn.Close()

    err := checkVersion(conn)
    if err != nil {
        log.Println(err)
        return
    }

    err = auth(conn)
    if err != nil {
        log.Println(err)
        return
    }

    err = checkVersion(conn)
    if err != nil {
        log.Println(err)
        return
    }

    // 读取保留字段和地址类型
    _, err = io.CopyN(io.Discard, conn, 2)
    if err != nil {
        log.Println("读取保留字段和地址类型失败:", err)
        return
    }

    addr, port, err := getTargetIpPort(conn)
    if err != nil{
        log.Println(err)
        return
    }
    if addr == ""{
        return
    }
    // 连接目标服务器
    server, err := dialWithSpecificLocalAddr(addr, localIP, port)
    if err != nil {
        log.Println("连接目标服务器失败:", err)
        if _, err := conn.Write([]byte{0x05, 0x01, 0x00, 0x01, 0, 0, 0, 0, 0, 0}); err != nil {
            log.Println("发送连接失败响应失败:", err)
        }
        return
    }
    defer server.Close()

    // 发送成功响应
    if _, err := conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0}); err != nil {
        log.Println("发送成功响应失败:", err)
        return
    }

    // 数据转发
    go io.Copy(conn, server)
    io.Copy(server, conn)
    
}

func main() {
    Init(os.Args[1])
    // 监听本地1080端口
    listener, err := net.Listen("tcp", ":1080")
    if err != nil {
        log.Fatal("监听端口失败:", err)
    }
    defer listener.Close()

    log.Println("SOCKS5代理服务器正在监听1080端口...")
    for {
        // 接受客户端连接
        client, err := listener.Accept()
        if err != nil {
            log.Println("接受客户端连接失败:", err)
            continue
        }
        // 处理客户端连接
        go handleClient(client)
    }
}

标签: none

评论已关闭