Golang中如何访问IP层
Golang中如何访问IP层 大家好,
请问有谁能告诉我IP层是在哪里处理的吗?具体在“go/src/net/”目录下的哪个文件中?
我希望能够访问诸如ip.length、ip.flags和ip.ttl这样的属性。
期待您的回复!
一个小观察……在网络栈的低层工作可能需要特权权限才能执行(例如,Linux 系统上的 root 权限)。请注意这一点,否则许多操作将无法进行。
更多关于Golang中如何访问IP层的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
TTL等概念确实是IP层面的概念,而HTTP请求是通过TCP传输的。TCP的套接字API不暴露TTL,因为在那里它没有意义——你的HTTP请求可能是由许多具有不同TTL值的IP数据包组装而成的。
IP 是在操作系统中实现的。不过,你可以使用例如 x/net/ipv4 来访问一些较低层级的选项。
你无法做到,因为Go自身使用的API(TCP套接字)不暴露此信息。TCP套接字没有TTL信息。这类似于你也无法获取IP包长度或源MAC地址。这完全是来自协议栈错误层级的信息。
// 代码示例:TCP套接字操作
func handleConnection(conn net.Conn) {
defer conn.Close()
// 这里无法获取TTL信息
}
非常感谢你的帮助 @calmh!
IP 层是无法触及的。
那么,是否有可能访问 TCP 层呢?例如,从 TCP SYN 数据包中提取 tcp.options 或 tcp.window_size?
或者说,在 Go 中(至少在使用 src/net 时),TCP 套接字是原样接收的,唯一可访问的“低层”属性只有 tcp.src_ip 和 tcp.src_port?
感谢大家的回复。
为了确保我的提问方式是正确的:我有一个HTTP服务器,它导入了(以及其他内容)https://golang.org/src/net/。 我想打印例如传入请求的TTL。
数据必须从IP层传递到TCP层,最终到达应用层,因为请求的源IP地址也是从IP层获取的,并且在不同库的代码中的多个位置都可以访问。所以像(源请求的)TTL这样的值也应该可以访问。
因此我假设它会在某个文件中,比如 ipsock.go,但在那里没有找到。
在Go标准库中,IP层处理主要在go/src/net/ipraw.go和go/src/net/ip.go文件中。要访问IP头部字段,需要使用golang.org/x/net/ipv4或golang.org/x/net/ipv6扩展包。
以下是访问IP头部字段的示例:
package main
import (
"fmt"
"golang.org/x/net/ipv4"
"net"
)
func main() {
// 创建原始套接字
conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
if err != nil {
panic(err)
}
defer conn.Close()
// 包装为ipv4.RawConn
rawConn, err := ipv4.NewRawConn(conn)
if err != nil {
panic(err)
}
// 读取IP数据包
buf := make([]byte, 1500)
hdr, payload, _, err := rawConn.ReadFrom(buf)
if err != nil {
panic(err)
}
// 访问IP头部字段
fmt.Printf("Total Length: %d\n", hdr.TotalLen)
fmt.Printf("TTL: %d\n", hdr.TTL)
fmt.Printf("Flags: %v\n", hdr.Flags)
fmt.Printf("Protocol: %d\n", hdr.Protocol)
fmt.Printf("Src: %s\n", hdr.Src.String())
fmt.Printf("Dst: %s\n", hdr.Dst.String())
// 处理payload
_ = payload
}
对于IPv6,使用golang.org/x/net/ipv6:
package main
import (
"fmt"
"golang.org/x/net/ipv6"
"net"
)
func main() {
conn, err := net.ListenPacket("ip6:tcp", "::")
if err != nil {
panic(err)
}
defer conn.Close()
rawConn, err := ipv6.NewPacketConn(conn)
if err != nil {
panic(err)
}
buf := make([]byte, 1500)
hdr, payload, _, err := rawConn.ReadFrom(buf)
if err != nil {
panic(err)
}
fmt.Printf("Payload Length: %d\n", hdr.PayloadLen)
fmt.Printf("Hop Limit: %d\n", hdr.HopLimit)
fmt.Printf("Next Header: %d\n", hdr.NextHeader)
fmt.Printf("Src: %s\n", hdr.Src.String())
fmt.Printf("Dst: %s\n", hdr.Dst.String())
_ = payload
}
如果需要手动解析IP数据包,可以直接读取原始数据:
package main
import (
"encoding/binary"
"fmt"
"net"
)
func parseIPv4Header(data []byte) {
if len(data) < 20 {
return
}
// 解析IPv4头部
version := data[0] >> 4
ihl := data[0] & 0x0F
totalLength := binary.BigEndian.Uint16(data[2:4])
ttl := data[8]
protocol := data[9]
fmt.Printf("IPv4 Header:\n")
fmt.Printf(" Version: %d\n", version)
fmt.Printf(" IHL: %d (header length: %d bytes)\n", ihl, ihl*4)
fmt.Printf(" Total Length: %d\n", totalLength)
fmt.Printf(" TTL: %d\n", ttl)
fmt.Printf(" Protocol: %d\n", protocol)
}
func main() {
conn, err := net.ListenIP("ip4:tcp", &net.IPAddr{IP: net.IPv4zero})
if err != nil {
panic(err)
}
defer conn.Close()
buf := make([]byte, 1500)
n, _, err := conn.ReadFrom(buf)
if err != nil {
panic(err)
}
parseIPv4Header(buf[:n])
}
注意:原始套接字操作通常需要管理员/root权限。


