# 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()`以文本的形式获取其输出，并打印。然而，这种方式既不优雅也不完美。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wskdsgcf.gitbook.io/mastering-go-zh-cn/12.0/12.5.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
