Skip to content

Commit 8e6badd

Browse files
committed
Support for dynamically addition of DNS records
Signed-off-by: Balaji Vijayakumar <[email protected]>
1 parent 477ce36 commit 8e6badd

File tree

4 files changed

+135
-5
lines changed

4 files changed

+135
-5
lines changed

pkg/client/client.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,40 @@ func (c *Client) Unexpose(req *types.UnexposeRequest) error {
8080
}
8181
return nil
8282
}
83+
84+
func (c *Client) ListDNS() ([]types.Zone, error) {
85+
res, err := c.client.Get(fmt.Sprintf("%s%s", c.base, "/services/dns/all"))
86+
if err != nil {
87+
return nil, err
88+
}
89+
defer res.Body.Close()
90+
if res.StatusCode != http.StatusOK {
91+
return nil, fmt.Errorf("unexpected status: %d", res.StatusCode)
92+
}
93+
dec := json.NewDecoder(res.Body)
94+
var dnsZone []types.Zone
95+
if err := dec.Decode(&dnsZone); err != nil {
96+
return nil, err
97+
}
98+
return dnsZone, nil
99+
}
100+
101+
func (c *Client) AddDNS(req *types.Zone) error {
102+
bin, err := json.Marshal(req)
103+
if err != nil {
104+
return err
105+
}
106+
res, err := c.client.Post(fmt.Sprintf("%s%s", c.base, "/services/dns/add"), "application/json", bytes.NewReader(bin))
107+
if err != nil {
108+
return err
109+
}
110+
defer res.Body.Close()
111+
if res.StatusCode != http.StatusOK {
112+
err, readErr := io.ReadAll(res.Body)
113+
if readErr != nil {
114+
return fmt.Errorf("error while reading error message: %v", readErr)
115+
}
116+
return errors.New(strings.TrimSpace(string(err)))
117+
}
118+
return nil
119+
}

pkg/services/dns/dns.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package dns
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"net"
8+
"net/http"
79
"strings"
810
"sync"
911

@@ -134,3 +136,30 @@ func (s *Server) Serve() error {
134136
}
135137
return srv.ActivateAndServe()
136138
}
139+
140+
func (s *Server) Mux() http.Handler {
141+
mux := http.NewServeMux()
142+
mux.HandleFunc("/all", func(w http.ResponseWriter, r *http.Request) {
143+
s.handler.zonesLock.RLock()
144+
_ = json.NewEncoder(w).Encode(s.handler.zones)
145+
s.handler.zonesLock.RUnlock()
146+
})
147+
148+
mux.HandleFunc("/add", func(w http.ResponseWriter, r *http.Request) {
149+
if r.Method != http.MethodPost {
150+
http.Error(w, "post only", http.StatusBadRequest)
151+
return
152+
}
153+
var req types.Zone
154+
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
155+
http.Error(w, err.Error(), http.StatusBadRequest)
156+
return
157+
}
158+
159+
s.handler.zonesLock.Lock()
160+
s.handler.zones = append([]types.Zone{req}, s.handler.zones...)
161+
s.handler.zonesLock.Unlock()
162+
w.WriteHeader(http.StatusOK)
163+
})
164+
return mux
165+
}

pkg/virtualnetwork/services.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ func addServices(configuration *types.Configuration, s *stack.Stack, ipPool *tap
2929
udpForwarder := forwarder.UDP(s, translation, &natLock)
3030
s.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)
3131

32-
if err := dnsServer(configuration, s); err != nil {
32+
dnsMux, err := dnsServer(configuration, s)
33+
if err != nil {
3334
return nil, err
3435
}
3536

@@ -45,6 +46,7 @@ func addServices(configuration *types.Configuration, s *stack.Stack, ipPool *tap
4546
mux := http.NewServeMux()
4647
mux.Handle("/forwarder/", http.StripPrefix("/forwarder", forwarderMux))
4748
mux.Handle("/dhcp/", http.StripPrefix("/dhcp", dhcpMux))
49+
mux.Handle("/dns/", http.StripPrefix("/dns", dnsMux))
4850
return mux, nil
4951
}
5052

@@ -56,24 +58,24 @@ func parseNATTable(configuration *types.Configuration) map[tcpip.Address]tcpip.A
5658
return translation
5759
}
5860

59-
func dnsServer(configuration *types.Configuration, s *stack.Stack) error {
61+
func dnsServer(configuration *types.Configuration, s *stack.Stack) (http.Handler, error) {
6062
udpConn, err := gonet.DialUDP(s, &tcpip.FullAddress{
6163
NIC: 1,
6264
Addr: tcpip.Address(net.ParseIP(configuration.GatewayIP).To4()),
6365
Port: uint16(53),
6466
}, nil, ipv4.ProtocolNumber)
6567
if err != nil {
66-
return err
68+
return nil, err
6769
}
6870
server, err := dns.New(udpConn, configuration.DNS)
6971
if err != nil {
70-
return err
72+
return nil, err
7173
}
7274

7375
go func() {
7476
log.Error(server.Serve())
7577
}()
76-
return nil
78+
return server.Mux(), nil
7779
}
7880

7981
func dhcpServer(configuration *types.Configuration, s *stack.Stack, ipPool *tap.IPPool) (http.Handler, error) {

test/basic_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package e2e
22

33
import (
4+
"context"
5+
"net"
6+
"net/http"
7+
8+
gvproxyclient "github.com/containers/gvisor-tap-vsock/pkg/client"
9+
"github.com/containers/gvisor-tap-vsock/pkg/types"
410
. "github.com/onsi/ginkgo"
511
. "github.com/onsi/gomega"
612
)
@@ -58,4 +64,60 @@ var _ = Describe("dns", func() {
5864
Expect(err).ShouldNot(HaveOccurred())
5965
Expect(string(out)).To(ContainSubstring("Address: 192.168.127.254"))
6066
})
67+
68+
It("should resolve dynamically added dns entry test.dynamic.internal", func() {
69+
client := gvproxyclient.New(&http.Client{
70+
Transport: &http.Transport{
71+
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
72+
return net.Dial("unix", sock)
73+
},
74+
},
75+
}, "http://base")
76+
err := client.AddDNS(&types.Zone{
77+
Name: "dynamic.internal.",
78+
Records: []types.Record{
79+
{
80+
Name: "test",
81+
IP: net.ParseIP("192.168.127.254"),
82+
},
83+
},
84+
})
85+
Expect(err).ShouldNot(HaveOccurred())
86+
87+
out, err := sshExec("nslookup test.dynamic.internal")
88+
89+
Expect(err).ShouldNot(HaveOccurred())
90+
Expect(string(out)).To(ContainSubstring("Address: 192.168.127.254"))
91+
})
92+
93+
It("should resolve recently added dns entry test.dynamic.internal", func() {
94+
client := gvproxyclient.New(&http.Client{
95+
Transport: &http.Transport{
96+
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
97+
return net.Dial("unix", sock)
98+
},
99+
},
100+
}, "http://base")
101+
err := client.AddDNS(&types.Zone{
102+
Name: "dynamic.internal.",
103+
Records: []types.Record{
104+
{
105+
Name: "test",
106+
IP: net.ParseIP("192.168.127.254"),
107+
},
108+
},
109+
})
110+
Expect(err).ShouldNot(HaveOccurred())
111+
112+
err = client.AddDNS(&types.Zone{
113+
Name: "dynamic.internal.",
114+
DefaultIP: net.ParseIP("192.168.127.253"),
115+
})
116+
Expect(err).ShouldNot(HaveOccurred())
117+
118+
out, err := sshExec("nslookup test.dynamic.internal")
119+
120+
Expect(err).ShouldNot(HaveOccurred())
121+
Expect(string(out)).To(ContainSubstring("Address: 192.168.127.253"))
122+
})
61123
})

0 commit comments

Comments
 (0)