V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
daba
V2EX  ›  Go 编程语言

有没有 Go 的大佬帮忙看一下

  •  
  •   daba · 14 天前 · 868 次点击
    在 parseHeaders 方法中,如果使用下面的方法拿请求头的数据( req, err := http.ReadRequest(reader)),就会导致一直请求中,但是如果把两个变量写死就不会出现问题
    reader := bufio.NewReader(conn)
    req, err := http.ReadRequest(reader)
    if err != nil {
    return "", "", err
    }

    realIP := req.Header.Get("X-Real-IP")
    serverAddr := req.Header.Get("X-Server-Addr")


    PS:透传的 table 、回环啥的都配置好了

    完整代码如下:

    package main

    import (
    "bufio"
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "os"
    "strconv"
    "syscall"
    )

    func main() {
    listen, err := net.Listen("tcp", "0.0.0.0:9920")
    if err != nil {
    log.Fatal(err)
    }
    log.Printf("waiting for incomming connection...")
    defer listen.Close()

    for {
    conn, err := listen.Accept()
    if err != nil {
    log.Println(err)
    continue
    }
    go clientHandler(conn)
    }
    }

    func clientHandler(client net.Conn) {
    log.Printf("proxy %s accepted", client.RemoteAddr().String())
    defer client.Close()

    //获取需要透代的客户端 IP 和服务端 IP
    clientIP, serverAddr, err := parseHeaders(client)
    if err != nil {
    log.Println(err)
    return
    }
    log.Printf("clientIP: %s serverAddr: %s", clientIP, serverAddr)

    //建立透明连接
    server, err := createTransparentSocket(clientIP, serverAddr)
    if err != nil {
    log.Println(err)
    return
    }
    defer server.Close()

    streamCopy := func(dst io.Writer, src io.Reader, direction string) {
    n, _ := read2Write(dst, src)
    log.Printf("%s %d bytes copied", direction, n)
    client.Close()
    server.Close()
    }

    go streamCopy(client, server, "server to client")
    streamCopy(server, client, "client to server")
    }

    func createTransparentSocket(clientIP, serverAddr string) (net.Conn, error) {
    var socketFD int
    var file *os.File
    var server net.Conn
    var errorPrefix string
    var err error

    // Create transparent socket
    if socketFD, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP); err != nil {
    errorPrefix = "syscall.socket()"
    goto ReturnError
    }

    // Set the send timeout, here set to 3 seconds
    if err = syscall.SetsockoptTimeval(socketFD, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &syscall.Timeval{Sec: 3}); err != nil {
    errorPrefix = "syscall.SetsockoptTimeval()"
    goto CloseSocket
    }

    // Set the transparent transmission flag, allowing binding to IP addresses already in use by other processes
    if err = syscall.SetsockoptInt(socketFD, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
    errorPrefix = "syscall.SetsockoptInt()"
    goto CloseSocket
    }

    // Use client's IP address as socket local address
    if err = syscall.Bind(socketFD, parseClientIP(clientIP)); err != nil {
    errorPrefix = "syscall.Bind()"
    goto CloseSocket
    }

    // Connect to server
    if err = syscall.Connect(socketFD, parseServerAddr(serverAddr)); err != nil && err.Error() != "operation now in progress" {
    errorPrefix = "syscall.Connect()"
    goto CloseSocket
    }

    file = os.NewFile(uintptr(socketFD), serverAddr)
    server, err = net.FileConn(file)
    if err == nil {
    // net.FileConn() has already duplicated this file descriptor
    syscall.Close(socketFD)
    return server, nil
    }
    errorPrefix = "net.FileConn()"
    CloseSocket:
    syscall.Close(socketFD)
    ReturnError:
    return nil, fmt.Errorf("%s: %s", errorPrefix, err)
    }

    func read2Write(dst io.Writer, src io.Reader) (written int64, err error) {
    if wt, ok := src.(io.WriterTo); ok {
    return wt.WriteTo(dst)
    }
    if rt, ok := dst.(io.ReaderFrom); ok {
    return rt.ReadFrom(src)
    }
    buf := make([]byte, 4096)
    return io.CopyBuffer(dst, src, buf)
    }

    func parseHeaders(conn net.Conn) (string, string, error) {
    reader := bufio.NewReader(conn)
    req, err := http.ReadRequest(reader)
    if err != nil {
    return "", "", err
    }

    realIP := req.Header.Get("X-Real-IP")
    serverAddr := req.Header.Get("X-Server-Addr")

    //realIP := "192.168.0.126"
    //serverAddr := "192.168.0.135:8000"

    if realIP == "" || serverAddr == "" {
    return "", "", fmt.Errorf("missing required headers")
    }

    return realIP, serverAddr, nil
    }

    func parseClientIP(clientIP string) syscall.Sockaddr {
    ip := net.ParseIP(clientIP).To4()
    return &syscall.SockaddrInet4{
    // 客户端端口随机
    Port: 0,
    Addr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
    }
    }

    func parseServerAddr(serverAddr string) syscall.Sockaddr {
    host, port, _ := net.SplitHostPort(serverAddr)
    ip := net.ParseIP(host).To4()
    destinationPort, _ := strconv.Atoi(port)
    return &syscall.SockaddrInet4{
    Port: destinationPort,
    Addr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
    }
    }
    第 1 条附言  ·  14 天前
    问题已解决
    reader 被重复读取导致 serverAddr 无法收到完整的数据

    clientHandler:
    clientIP, serverAddr, bufferedData, err := parseHeaders(client)
    // 先把缓冲数据发送到服务端
    if len(bufferedData) > 0 {
    server.Write(bufferedData)
    }


    func parseHeaders(conn net.Conn) (string, string, []byte, error) {
    var bufferedData bytes.Buffer
    reader := io.TeeReader(conn, &bufferedData)

    req, err := http.ReadRequest(bufio.NewReader(reader))
    if err != nil {
    return "", "", nil, err
    }

    realIP := req.Header.Get("X-Real-IP")
    serverAddr := req.Header.Get("X-Server-Addr")

    if realIP == "" || serverAddr == "" {
    return "", "", nil, fmt.Errorf("missing required headers")
    }

    return realIP, serverAddr, bufferedData.Bytes(), nil
    }
    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1118 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 18:46 · PVG 02:46 · LAX 11:46 · JFK 14:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.