dhcp: support multiple DNS server addresses

Change-Id: I1251a17d83c782a58a7bd1d44a6c5730bf1e84a1
diff --git a/dhcp/dhcp.go b/dhcp/dhcp.go
index 35a7e5d..de0f65f 100644
--- a/dhcp/dhcp.go
+++ b/dhcp/dhcp.go
@@ -16,12 +16,12 @@
 
 // Config is standard DHCP configuration.
 type Config struct {
-	Error            error
-	ServerAddress    tcpip.Address     // address of the server
-	SubnetMask       tcpip.AddressMask // client address subnet mask
-	Gateway          tcpip.Address     // client default gateway
-	DomainNameServer tcpip.Address     // client domain name server
-	LeaseLength      time.Duration     // length of the address lease
+	Error         error
+	ServerAddress tcpip.Address     // address of the server
+	SubnetMask    tcpip.AddressMask // client address subnet mask
+	Gateway       tcpip.Address     // client default gateway
+	DNS           []tcpip.Address   // client domain name servers
+	LeaseLength   time.Duration     // length of the address lease
 }
 
 func (cfg *Config) decode(opts []option) error {
@@ -42,8 +42,12 @@
 		case optDefaultGateway:
 			cfg.Gateway = tcpip.Address(b)
 		case optDomainNameServer:
-			// TODO(crawshaw): handle multiple DNS servers
-			cfg.DomainNameServer = tcpip.Address(b[:4])
+			for ; len(b) > 0; b = b[4:] {
+				if len(b) < 4 {
+					return fmt.Errorf("DNS bad length: %d", len(b))
+				}
+				cfg.DNS = append(cfg.DNS, tcpip.Address(b[:4]))
+			}
 		}
 	}
 	return nil
@@ -59,8 +63,12 @@
 	if cfg.Gateway != "" {
 		opts = append(opts, option{optDefaultGateway, []byte(cfg.Gateway)})
 	}
-	if cfg.DomainNameServer != "" {
-		opts = append(opts, option{optDomainNameServer, []byte(cfg.DomainNameServer)})
+	if len(cfg.DNS) > 0 {
+		dns := make([]byte, 0, 4*len(cfg.DNS))
+		for _, addr := range cfg.DNS {
+			dns = append(dns, addr...)
+		}
+		opts = append(opts, option{optDomainNameServer, dns})
 	}
 	if l := cfg.LeaseLength / time.Second; l != 0 {
 		v := make([]byte, 4)
diff --git a/dhcp/dhcp_test.go b/dhcp/dhcp_test.go
index 9a23f78..92c5c41 100644
--- a/dhcp/dhcp_test.go
+++ b/dhcp/dhcp_test.go
@@ -63,11 +63,13 @@
 	clientAddrs := []tcpip.Address{"\xc0\xa8\x03\x02", "\xc0\xa8\x03\x03"}
 
 	serverCfg := Config{
-		ServerAddress:    serverAddr,
-		SubnetMask:       "\xff\xff\xff\x00",
-		Gateway:          "\xc0\xa8\x03\xF0",
-		DomainNameServer: "\x08\x08\x08\x08",
-		LeaseLength:      24 * time.Hour,
+		ServerAddress: serverAddr,
+		SubnetMask:    "\xff\xff\xff\x00",
+		Gateway:       "\xc0\xa8\x03\xF0",
+		DNS: []tcpip.Address{
+			"\x08\x08\x08\x08", "\x08\x08\x04\x04",
+		},
+		LeaseLength: 24 * time.Hour,
 	}
 	serverCtx, cancel := context.WithCancel(context.Background())
 	defer cancel()
@@ -107,21 +109,36 @@
 		t.Errorf("c.Addr()=%s, want=%s", got, want)
 	}
 
-	if got, want := c0.Config(), serverCfg; got != want {
+	if got, want := c0.Config(), serverCfg; !equalConfig(got, want) {
 		t.Errorf("client config:\n\t%#+v\nwant:\n\t%#+v", got, want)
 	}
 }
 
+func equalConfig(c0, c1 Config) bool {
+	if c0.Error != c1.Error || c0.ServerAddress != c1.ServerAddress || c0.SubnetMask != c1.SubnetMask || c0.Gateway != c1.Gateway || c0.LeaseLength != c1.LeaseLength {
+		return false
+	}
+	if len(c0.DNS) != len(c1.DNS) {
+		return false
+	}
+	for i := 0; i < len(c0.DNS); i++ {
+		if c0.DNS[i] != c1.DNS[i] {
+			return false
+		}
+	}
+	return true
+}
+
 func TestRenew(t *testing.T) {
 	s := createStack(t)
 	clientAddrs := []tcpip.Address{"\xc0\xa8\x03\x02"}
 
 	serverCfg := Config{
-		ServerAddress:    serverAddr,
-		SubnetMask:       "\xff\xff\xff\x00",
-		Gateway:          "\xc0\xa8\x03\xF0",
-		DomainNameServer: "\x08\x08\x08\x08",
-		LeaseLength:      1 * time.Second,
+		ServerAddress: serverAddr,
+		SubnetMask:    "\xff\xff\xff\x00",
+		Gateway:       "\xc0\xa8\x03\xF0",
+		DNS:           []tcpip.Address{"\x08\x08\x08\x08"},
+		LeaseLength:   1 * time.Second,
 	}
 	serverCtx, cancel := context.WithCancel(context.Background())
 	defer cancel()