13.8 底层网络编程
虽然 http.Transport 结构允许您修改网络连接的底层参数,但您可以编写允许您读取网络包原始数据的 Go 代码。这有两个棘手的问题:
  • 网络包采用二进制格式,这要求您查找特定类型的网络数据包,而不仅仅是任何类型的网络数据包。
  • 为了发送一个网络数据包,您必须自己构建。
接下来要展示的是 lowLevel.go,并把它分为三个部分。注意 lowLevel.go 捕获 ICMP 数据包,使用 IPv4 协议并打印包的内容。另外,由于安全原因操作原始网络数据需求 root 权限。
lowLevel.go 的第一段如下:
1
package main
2
3
import(
4
"fmt"
5
"net"
6
)
Copied!
lowLevel.go 的第二段代码如下:
1
func main() {
2
netaddr, err := net.ResolveIPAddr("ip4", "127.0.0.1")
3
if err != nil {
4
fmt.Println(err)
5
return
6
}
7
8
conn, err := net.ListenIP("ip4:icmp", netaddr)
9
if err != nil {
10
fmt.Println(err)
11
return
12
}
Copied!
ICMP 协协议被定义在 net.ListenIP() 函数的第一个参数的第二部分。此外,ip4 部分告诉程序只捕获 IPv4 流量。
lowLevel.go 的其余 Go 代码如下:
1
buffer := make([]byte, 1024)
2
n, _, err := conn.ReadFrom(buffer)
3
if err != nil {
4
fmt.Println(err)
5
return
6
}
7
fmt.Printf("% X\n", buffer[0:n])
8
}
Copied!
上面这段代码告诉 lowLevel.go 只读取一个网络包,因为没有 for 循环。
ICMP 协议由 ping(1)traceroute(1) 命令使用,所以为了产生 ICMP 流量,可以使用它们中的任何一个。当 lowLevel.go 已经运行后,在所有的 Unix 机器上使用如下命令就会产生 ICMP 网络流量。
1
$ ping -c 5 localhost
2
PING localhost (127.0.0.1): 56 data bytes
3
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.037 ms
4
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.038 ms
5
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.117 ms
6
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.052 ms
7
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.049 ms
8
9
--- localhost ping statistics ---
10
5 packets transmitted, 5 packets received, 0.0% packet loss
11
round-trip min/avg/max/stddev = 0.037/0.059/0.117/0.030 ms
12
$ traceroute localhost
13
traceroute to localhost (127.0.0.1), 64 hops max, 52 byte packets
14
1 localhost(127.0.0.1) 0.255 ms 0.048 ms 0.067 ms
Copied!
在 macOS High Sierra 机器上用 root 权限执行 lowLevel.go 将产生如下输出:
1
$ sudo go run lowlevel.go
2
03 03 CD DA 00 00 00 00 45 00 34 00 B4 0F 00 00 01 00 00 7F 00 00 01 7F 00 00 01 B4 0E 82 9B 00 20 00 00
3
$ sudo go run lowLevel.go
4
00 00 0B 3B 20 34 00 00 5A CB 5C 15 00 04 32 A9 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37
Copied!
第一个输出的例子是 ping(1) 命令产生的,第二个是 traceroute(1) 命令产生的。
在 Debian Linux 机器上运行 lowLevel.go 将产生如下输出:
1
$ uname -a
2
Linux mail 4.14.12-x86_64-linode92 #1 SMP Fri Jan 5 15:34:44 UTC 2018 x86_64 GNU/Linux
3
# go run lowLevel.go
4
08 00 61 DD 3F BA 00 01 9A 5D CB 5A 00 00 00 00 26 DC 0B 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37
5
# go run lowLevel.go
6
03 03 BB B8 00 00 00 00 45 00 00 3C CD 8D 00 00 01 11 EE 21 7F 00 00 01 7F 00 00 01 CB 40 82 9A 00 28 FE 3B 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
Copied!
uname(1) 命令打印出 Linux 系统的有用信息。注意,在当前的 Linux 机器上,您应该在执行 ping(1) 命令时使用 -4 标志来告诉它使用 IPv4 协议。
Last modified 2yr ago
Copy link