如何监听L3网络层?

how to listen on L3 network layer?

我正在创建一个聊天应用程序后端,想考虑可扩展性。

我想创建一个负载均衡器,但不是在 HTTP 所在的 L7 层上,而是在 IP 网络所在的 L3 层上,以直接连接到特定服务器,然后我可以在这些服务器上创建 TCP .

net.ListenIP 是用来监听 IP 层数据包的正确函数吗?

是否与较高的 Listen("tcp") 相同?这是我需要实现负载均衡器的正确方法吗?

是否有关于数据包结构的参考,以便我能够从中获取源和目标 IP 以转发它们?

如果没有告诉我在L3网络层使用哪个函数监听来平衡其他服务器的负载。

reading the Docs之后,是的,这个功能将帮助您接收IP数据包。

ListenIP acts like ListenPacket for IP networks.

ListenIP is similar to ListenPacket("tcp") 但对于 IP 数据包。

至于 IP 数据包的结构,以及如何使用它们,net 包似乎没有。

还有另一个包 gopacket 看起来可以帮助您从任何层读取和修改数据包。

gopacket中有一个Packet类型,它允许与网络层一起工作。

Packet.NetworkLayer().LayerContent()Packet.NetworkLayer().LayerPayload() 将各自 return byte[] ,您可以通过预期的 structure of an IP packet.

来解释

注意既然我已经写完了这整件事,我不得不想象有人写了一个很好的 overlay/wrapper 来制作这个更轻松。这只是我谷歌搜索 10 分钟的结果。也许其他人会回答得更好 tool/method

就个人而言,我使用 gopacket 来捕获多个网络层,这个库非常令人印象深刻。

当您使用 gopacket 时,您可以通过指定它们来捕获多个网络层,例如 Ipv4TCPEthernet... 有关详细信息,请参阅 layers packet

然后,您将能够使用 packet.Data() 来分析您的层,packet.Data() 是构成整个数据包的一组字节,然后切换数据包类型以执行一些操作。

例如,在 eth0 上捕获多个网络层:

package main

import (
    "fmt"
    "github.com/google/gopacket"
    "github.com/google/gopacket/layers"
    "github.com/google/gopacket/pcap"
    "time"
)

//Layers we want to decode
var (
    ip4 layers.IPv4
    eth layers.Ethernet
    tcp layers.TCP
)

func main() {

    //Array to store decoded layers
    decodedLayers := []gopacket.LayerType{}

    //Create parser
    parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &ip4, &tcp)

    //Here we use pcap to capture packet on eth0 interface, we can also use afpacket for example, which is more efficient
    handle, err := pcap.OpenLive("eth0", 65536, true, pcap.BlockForever)
    if err != nil {
        panic("Error opening pcap: " + err.Error())
    }

    datasource := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet)

    //packets will be a channel of packets
    packets := datasource.Packets()

    for {
        select {
        case packet := <-packets:
            //We are decoding layers, and switching on the layer type
            err := parser.DecodeLayers(packet.Data(), &decodedLayers)
            for _, typ := range decodedLayers {
                switch typ {
                case layers.LayerTypeIPv4:
                    fmt.Printf("Source ip = %s - Destination ip = %s \n", ip4.SrcIP.String(), ip4.DstIP.String())
                case layers.LayerTypeTCP:
                    //Here, we can access tcp packet properties
                    fmt.Println("Capture tcp traffic")
                }
                //etc ....
            }
            if len(decodedLayers) == 0 {
                fmt.Println("Packet truncated")
            }

            //If the DecodeLayers is unable to decode the next layer type
            if err != nil {
                //fmt.Printf("Layer not found : %s", err)
            }
        }
    }

}