如何在golang中net/rpc中获取客户端真实IP

问题描述 投票:0回答:1

我有一个需求,需要rpc服务器获取客户端的真实IP和当前连接

net.Conn

我以前是通过下面的示例方法获取的

// example_server.go
type MathService struct{}
type Args struct {
    A, B int
}
type Reply struct {
    Result int
}
func (m *MathService) Multiply(args *Args, reply *Reply) error {
    reply.Result = args.A * args.B
    return nil
}
func main() {
    // Create an instance of the MathService
    mathService := new(MathService)
    // Register MathService for RPC
    rpc.Register(mathService)
    // Create a TCP listener
    listener, err := net.Listen("tcp", "0.0.0.0:1234")
    if err != nil {
        fmt.Println("Error starting server:", err)
        return
    }
    defer listener.Close()
    fmt.Println("Server listening on :1234")
    for {
        // Accept incoming connections
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("Error accepting connection:", err)
            continue
        }
        fmt.Printf("remote ip addr: %s\n", conn.RemoteAddr().String())
        // Serve the connection in a new goroutine
        go rpc.ServeConn(conn)
    }
}

// example_client.go
type Args struct {
    A, B int
}
type Reply struct {
    Result int
}
func main() {
    // Connect to the server
    client, err := rpc.Dial("tcp", "127.0.0.1:1234")
    if err != nil {
        fmt.Println("Error connecting to server:", err)
        return
    }
    defer client.Close()
    // Prepare the arguments for the RPC call
    args := &Args{A: 5, B: 3}
    // Call the Multiply method remotely
    var reply Reply
    err = client.Call("MathService.Multiply", args, &reply)
    if err != nil {
        fmt.Println("Error calling Multiply:", err)
        return
    }
    // Print the result
    fmt.Printf("Result: %d\n", reply.Result)
}

但是

RemoteAddr
方法获取到的不一定是客户端的真实IP

因此,我希望手动调用

ReportRealIP
函数来报告真实IP,但是在rpc函数中无法获取到
当前
连接的net.Conn

但是我查了一些资料,没有找到办法实现我的需求。有没有办法获得我想要的两个变量?期待您的回复

需要真实IP

net.Conn
的原因大致是为了双向通信。我希望能够向特定IP的客户端发送RPC请求来执行某些操作。例如,向某些Agent服务发出RPC命令来执行某个脚本。

其他信息
我预期结果的伪代码

// client.go
rpc.Call("Server.ReportRealIP","1,2,3,4", resp)



// server.go
var globalMap map[string]net.Conn
func (m *Server) ReportRealIP(args *string, reply *Reply) error {
    clientRealIP := args
    // get current call net.Conn
    
    globalMap[clientRealIP] = current net.Conn
    return nil
}
go rpc
1个回答
0
投票

在Go的标准库中,rpc包并没有提供直接获取底层net.Conn或者客户端真实IP地址的方法。但是,您可以通过为 net.Conn 创建包装器并实现包含您需要的信息的自定义编解码器来实现您的目标

package main

import (
    "fmt"
    "net"
    "net/rpc"
    "net/rpc/jsonrpc"
)

type MathService struct{}

type Args struct {
    A, B int
}

type Reply struct {
    Result int
}

func (m *MathService) Multiply(args *Args, reply *Reply) error {
    reply.Result = args.A * args.B
    return nil
}

// Custom codec that includes Conn and RemoteAddr
type customCodec struct {
    innerCodec rpc.ServerCodec
    conn       net.Conn
}

func (c *customCodec) ReadRequestHeader(r *rpc.Request) error {
    return c.innerCodec.ReadRequestHeader(r)
}

func (c *customCodec) ReadRequestBody(body interface{}) error {
    return c.innerCodec.ReadRequestBody(body)
}

func (c *customCodec) WriteResponse(r *rpc.Response, body interface{}) error {
    return c.innerCodec.WriteResponse(r, body)
}

func (c *customCodec) Close() error {
    return c.innerCodec.Close()
}

func (c *customCodec) Conn() net.Conn {
    return c.conn
}

// Custom listener that returns a customConn
type customListener struct {
    net.Listener
}

func (l *customListener) Accept() (net.Conn, error) {
    conn, err := l.Listener.Accept()
    if err != nil {
        return nil, err
    }
    return &customConn{Conn: conn}, nil
}

// Custom connection that embeds net.Conn
type customConn struct {
    net.Conn
}

func (c *customConn) RemoteAddr() net.Addr {
    return c.Conn.RemoteAddr()
}

// ReportRealIP is a function to report the real IP of the client
func ReportRealIP(conn net.Conn) {
    fmt.Printf("Real IP: %s\n", conn.RemoteAddr().String())
    // Perform additional operations with the real IP, if needed
}

func main() {
    // Create an instance of the MathService
    mathService := new(MathService)
    // Register MathService for RPC
    rpc.Register(mathService)
    // Create a TCP listener
    listener, err := net.Listen("tcp", "0.0.0.0:1234")
    if err != nil {
        fmt.Println("Error starting server:", err)
        return
    }
    defer listener.Close()
    fmt.Println("Server listening on :1234")
    for {
        // Accept incoming connections
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("Error accepting connection:", err)
            continue
        }
        // Wrap the connection with customConn
        customConn := &customConn{Conn: conn}
        // Report real IP
        ReportRealIP(customConn)

        // Create a customCodec with the wrapped connection
        codec := &customCodec{innerCodec: jsonrpc.NewServerCodec(customConn), conn: customConn}
        // Serve the connection with the customCodec in a new goroutine
        go rpc.ServeCodec(codec)
    }
}

在此示例中,我创建了一个名为 customCodec 的自定义 ServerCodec,它嵌入原始 ServerCodec 并在其实现中包含 net.Conn。此外,我还创建了一个返回自定义连接 (customConn) 的自定义侦听器 (customListener)。然后可以使用自定义连接调用ReportRealIP函数来获取真实IP。

© www.soinside.com 2019 - 2024. All rights reserved.