# 12.5 读取网络接口的配置文件

网络配置有四个核心元素：接口的IP地址、接口的网络掩码、主机的DNS服务器配置以及主机的默认网关或默认路由配置。这里存在一个问题：目前没有原生并可移植Go代码来获取以上信息。这表明在UNIX系统的主机上，没有可移植的代码来查询DNS配置和默认网关信息。

因此在本节中，将介绍如何使用Go代码读取UNIX系统的网络接口配置。为此，我将介绍两个可移植的程序，用于查询有关网络接口的配置。

第一个程序`netConfig.go`的源代码由三部分组成。

以下Go代码是`netConfig.go`的第一部分：

> ```go
> package main
>
> import (
>     "fmt"
>     "net"
> )
>
> func main() {
>     interfaces, err := net.Interfaces()
>     if err != nil {
>         fmt.Println(err)
>         return
>     }
> ```

函数`net.Interfaces()`的作用是将当前计算机的所有接口信息通过一个切片数据结构返回，切片的数据元素类型为`net.Interface`。此切片将用于获取接口的信息。

代码`netConfig.go`的第二个部分包含以下Go代码：

> ```go
>     for _, i := range interfaces {
>         fmt.Printf("Interface: %v\n", i.Name)
>         byName, err := net.InterfaceByName(i.Name)
>         if err != nil {
>             fmt.Println(err)
>         }
> ```

在上面的代码中，使用`net.Interface`类型来访问切片的每个元素，获取所需的信息。

````
> ```go
>         addresses, err := byName.Addrs()
>         for k, v := range addresses {
>             fmt.Printf("Interface Address #%v: %v\n", k, v.String())
>         }
>         fmt.Println()
>     }
> }
>
````

在操作系统为macOS High Sierra的主机上，使用版本为1.10的Go运行环境执行`netConfig.go`会得到以下输出：

> ```
> $ go run netConfig.go
> Interface: lo0
> Interface Address #0: 127.0.0.1/8
> Interface Address #1: ::1/128
> Interface Address #2: fe80::1/64
>
> Interface: gif0
>
> Interface: stf0
>
> Interface: XHC20
>
> Interface: en0
> Interface Address #0: fe80::18fa:901a:ea9:eb5f/64
> Interface Address #1: 192.168.1.200/24
> Interface Address #2: 2a02:587:3006:b800:1cb8:bf1b:b154:4d0c/64
> Interface Address #3: 2a02:587:3006:b800:d84a:f0c:c932:35d1/64
>
> Interface: en1
>
> Interface: p2p0
>
> Interface: awdl0
>
> Interface: en2
>
> Interface: en3
>
> Interface: bridge0
>
> Interface: utun0
> Interface Address #0: fe80::2514:c3a3:ca83:e1c6/64
>
> Interface: utun1
> Interface Address #0: fe80::4e0b:a9a6:9abe:81a4/64
>
> Interface: en5
> Interface Address #0: fe80::1cb4:a29e:97bc:6fb5/64
> Interface Address #1: 169.254.72.59/16
> ```

如上，因为现代计算机配置很多网络接口，同时程序支持IPv4和IPv6协议，`netConfig.go`返回了很多接口和IP地址信息。

在操作系统为Debian Linux的主机上，使用版本为1.7.4的Go运行环境执行`netConfig.go`会得到以下输出：

> ```
> $ go run netConfig.go
> Interface: lo
> Interface Address #0: 127.0.0.1/8
> Interface Address #1: ::1/128
>
> Interface: dummy0
>
> Interface: eth0
> Interface Address #0: 10.74.193.253/24
> Interface Address #1: 2a01:7e00::f03c:91ff:fe69:1381/64
> Interface Address #2: fe80::f03c:91ff:fe69:1381/64
>
> Interface: teql0
>
> Interface: tunl0
>
> Interface: gre0
>
> Interface: gretap0
>
> Interface: erspan0
>
> Interface: ip_vti0
>
> Interface: ip6_vti0
>
> Interface: sit0
>
> Interface: ip6tnl0
>
> Interface: ip6gre0
> ```

可以看到有的网络接口没有显示网络地址，可能的主要原因是接口是关闭的，或者该接口没有进行配置。

> 并非所有列出的网络接口都关联了真正的硬件网络设备。最典型的例子是`lo0`接口，它是环回设备。**环回设备**是一种特殊的虚拟网络接口，主机可以通过该接口与自身通信。

下一个Go程序`netCapabilities.go`的代码也分为三部分。程序`netCapabilities.go`的目的是打印UNIX操作系统的主机上每个网络接口的功能。

程序`netCapabilities.go`使用结构`net.Interface`的字段，定义如下：

> ```go
> type Interface struct {
>     Index int
>     MTU int
>     Name string
>     HardwareAddr HardwareAddr
>     Flags Flags
> }
> ```

Go程序`netCapabilities.go`的第一部分如下：

> ```go
> package main
>
> import (
>     "fmt"
>     "net"
> )
> ```

````
> ```go
> func main() {
>     interfaces, err := net.Interfaces()
> 
>     if err != nil {
>         fmt.Print(err)
>         return
>     }
>
````

````
> ```go
>     for _, i := range interfaces {
>         fmt.Printf("Name: %v\n", i.Name)
>         fmt.Println("Interface Flags:", i.Flags.String())
>         fmt.Println("Interface MTU:", i.MTU)
>         fmt.Println("Interface Hardware Address:", i.HardwareAddr)
>         fmt.Println()
>     }
> }
>
````

在操作系统为macOS High Sierra的主机上运行`netCapabilities.go`生成以下输出：

> ```
> $ go run netCapabilities.go
> Name: lo0
> Interface Flags: up|loopback|multicast
> Interface MTU: 16384
> Interface Hardware Address:
>
> Name: gif0
> Interface Flags: pointtopoint|multicast
> Interface MTU: 1280
> Interface Hardware Address:
>
> Name: stf0
> Interface Flags: 0
> Interface MTU: 1280
> Interface Hardware Address:
>
> Name: XHC20
> Interface Flags: 0
> Interface MTU: 0
> Interface Hardware Address:
>
> Name: en0
> Interface Flags: up|broadcast|multicast
> Interface MTU: 1500
> Interface Hardware Address: 98:5a:eb:d7:84:cd
>
> Name: en1
> Interface Flags: up|broadcast|multicast
> Interface MTU: 1500
> Interface Hardware Address: d0:03:4b:cf:84:d3
>
> Name: p2p0
> Interface Flags: broadcast|multicast
> Interface MTU: 2304
> Interface Hardware Address: 02:03:4b:cf:84:d3
>
> Name: awdl0
> Interface Flags: broadcast|multicast
> Interface MTU: 1484
> Interface Hardware Address: 02:ac:d4:3b:d9:29
>
> Name: en2
> Interface Flags: up|broadcast|multicast
> Interface MTU: 1500
> Interface Hardware Address: 0a:00:00:a5:32:b0
>
> Name: en3
> Interface Flags: up|broadcast|multicast
> Interface MTU: 1500
> Interface Hardware Address: 0a:00:00:a5:32:b1
>
> Name: bridge0
> Interface Flags: up|broadcast|multicast
> Interface MTU: 1500
> Interface Hardware Address: 0a:00:00:a5:32:b0
>
> Name: utun0
> Interface Flags: up|pointtopoint|multicast
> Interface MTU: 2000
> Interface Hardware Address:
>
> Name: utun1
> Interface Flags: up|pointtopoint|multicast
> Interface MTU: 1380
> Interface Hardware Address:
>
> Name: en5
> Interface Flags: up|broadcast|multicast
> Interface MTU: 1500
> Interface Hardware Address: 6e:72:e7:1b:cd:5f
> ```

在Debian Linux操作系统的主机上执行`netCapabilities.go`将输出类似的结果。

最后，如果对查找主机的默认网关感兴趣，可以在`shell`运行环境中执行`netstat -nr`命令查看，或在Go程序中使用`exec.Command()`执行该命令，并通过`pipe`或`exec.CombinedOutput()`以文本的形式获取其输出，并打印。然而，这种方式既不优雅也不完美。
