DNS全称Domain Name System(域名系统),它的作用是将IP地址转换为类似packt.com
的域名,或者将域名转换为IP地址。本节中开发的DNS.go
程序的处理逻辑非常简单:如果程序执行时的命令行参数是一个有效的IP地址,则程序将查询该IP地址对应的主机名;其他情况下,程序将假定它处理的是一个主机名,并将其转换成一个或多个IP地址。
程序DNS.go
的代码将分三部分介绍。第一部分程序包含以下Go代码:
package main import ( "fmt" "net" "os" ) func lookIP(address string) ([]string, error) { hosts, err := net.LookupAddr(address) if err != nil { return nil, err } return hosts, nil } func lookHostname(hostname string) ([]string, error) { IPs, err := net.LookupHost(hostname) if err != nil { return nil, err } return IPs, nil }
函数lookIP()
将一个IP地址作为输入,然后返回与该IP地址匹配的主机列表,这个功能通过函数net.LookupAddr()
的帮助来实现。
而函数lookHostname()
将主机名作为输入,使用net.LookupHost()
函数进行处理,返回一个相关IP地址的列表。
程序DNS.go
的第二部分是以下Go代码:
func main() { arguments := os.Args if len(arguments) == 1 { fmt.Println("Please provide an argument!") return } input := arguments[1] IPaddress := net.ParseIP(input)
函数net.ParseIP()
可以将输入字符串解析为IPv4或IPv6地址。如果输入一个非法的IP地址,函数net.ParseIP()
将返回nil
。
程序DNS.go
的剩余Go代码如下:
if IPaddress == nil { IPs, err := lookHostname(input) if err == nil { for _, singleIP := range IPs { fmt.Println(singleIP) } } } else { hosts, err := lookIP(input) if err == nil { for _, hostname := range hosts { fmt.Println(hostname) } } } }
执行DNS.go
程序,并携带不同的输入参数,将生成以下输出:
$ go run DNS.go 127.0.0.1 localhost $ go run DNS.go 192.168.1.1 cisco $ go run DNS.go packtpub.com 83.166.169.231 $ go run DNS.go google.com 2a00:1450:4001:816::200e 216.58.210.14 $ go run DNS.go www.google.com 2a00:1450:4001:816::2004 216.58.214.36 $ go run DNS.go cnn.com 2a04:4e42::323 2a04:4e42:600::323 2a04:4e42:400::323 2a04:4e42:200::323 151.101.193.67 151.101.1.67 151.101.129.67 151.101.65.67
可以看到go run DNS.go 192.168.1.1
命令的输出来自/etc/hosts
文件,因为在/etc/hosts
文件中配置了IP地址192.168.1.1
的别名cisco
。
最后一个命令的输出演示了域名(cnn.com
)可能有多个公网IP地址映射。请特别注意公网这个词,尽管www.google.com
有多个IP地址,但是只有地址(216.58.214.36
)是公网IP地址。