cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2018.9.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

tunneldns/tunnel.go

148lines · modecode

1package tunneldns
2
3import (
4 "net"
5 "os"
6 "os/signal"
7 "strconv"
8 "sync"
9 "syscall"
10
11 "github.com/cloudflare/cloudflared/log"
12 "github.com/cloudflare/cloudflared/metrics"
13
14 "github.com/coredns/coredns/core/dnsserver"
15 "github.com/coredns/coredns/plugin"
16 "github.com/coredns/coredns/plugin/cache"
17 "github.com/pkg/errors"
18 "gopkg.in/urfave/cli.v2"
19)
20
21var logger = log.CreateLogger()
22
23// Listener is an adapter between CoreDNS server and Warp runnable
24type Listener struct {
25 server *dnsserver.Server
26 wg sync.WaitGroup
27}
28
29// Run implements a foreground runner
30func Run(c *cli.Context) error {
31 metricsListener, err := net.Listen("tcp", c.String("metrics"))
32 if err != nil {
33 logger.WithError(err).Fatal("Failed to open the metrics listener")
34 }
35
36 go metrics.ServeMetrics(metricsListener, nil, logger)
37
38 listener, err := CreateListener(c.String("address"), uint16(c.Uint("port")), c.StringSlice("upstream"))
39 if err != nil {
40 logger.WithError(err).Errorf("Failed to create the listeners")
41 return err
42 }
43
44 // Try to start the server
45 readySignal := make(chan struct{})
46 err = listener.Start(readySignal)
47 if err != nil {
48 logger.WithError(err).Errorf("Failed to start the listeners")
49 return listener.Stop()
50 }
51 <-readySignal
52
53 // Wait for signal
54 signals := make(chan os.Signal, 10)
55 signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
56 defer signal.Stop(signals)
57 <-signals
58
59 // Shut down server
60 err = listener.Stop()
61 if err != nil {
62 logger.WithError(err).Errorf("failed to stop")
63 }
64 return err
65}
66
67// Create a CoreDNS server plugin from configuration
68func createConfig(address string, port uint16, p plugin.Handler) *dnsserver.Config {
69 c := &dnsserver.Config{
70 Zone: ".",
71 Transport: "dns",
72 ListenHosts: []string{address},
73 Port: strconv.FormatUint(uint64(port), 10),
74 }
75
76 c.AddPlugin(func(next plugin.Handler) plugin.Handler { return p })
77 return c
78}
79
80// Start blocks for serving requests
81func (l *Listener) Start(readySignal chan struct{}) error {
82 defer close(readySignal)
83 logger.WithField("addr", l.server.Address()).Infof("Starting DNS over HTTPS proxy server")
84
85 // Start UDP listener
86 if udp, err := l.server.ListenPacket(); err == nil {
87 l.wg.Add(1)
88 go func() {
89 l.server.ServePacket(udp)
90 l.wg.Done()
91 }()
92 } else {
93 return errors.Wrap(err, "failed to create a UDP listener")
94 }
95
96 // Start TCP listener
97 tcp, err := l.server.Listen()
98 if err == nil {
99 l.wg.Add(1)
100 go func() {
101 l.server.Serve(tcp)
102 l.wg.Done()
103 }()
104 }
105
106 return errors.Wrap(err, "failed to create a TCP listener")
107}
108
109// Stop signals server shutdown and blocks until completed
110func (l *Listener) Stop() error {
111 if err := l.server.Stop(); err != nil {
112 return err
113 }
114
115 l.wg.Wait()
116 return nil
117}
118
119// CreateListener configures the server and bound sockets
120func CreateListener(address string, port uint16, upstreams []string) (*Listener, error) {
121 // Build the list of upstreams
122 upstreamList := make([]Upstream, 0)
123 for _, url := range upstreams {
124 logger.WithField("url", url).Infof("Adding DNS upstream")
125 upstream, err := NewUpstreamHTTPS(url)
126 if err != nil {
127 return nil, errors.Wrap(err, "failed to create HTTPS upstream")
128 }
129 upstreamList = append(upstreamList, upstream)
130 }
131
132 // Create a local cache with HTTPS proxy plugin
133 chain := cache.New()
134 chain.Next = ProxyPlugin{
135 Upstreams: upstreamList,
136 }
137
138 // Format an endpoint
139 endpoint := "dns://" + net.JoinHostPort(address, strconv.FormatUint(uint64(port), 10))
140
141 // Create the actual middleware server
142 server, err := dnsserver.NewServer(endpoint, []*dnsserver.Config{createConfig(address, port, NewMetricsPlugin(chain))})
143 if err != nil {
144 return nil, err
145 }
146
147 return &Listener{server: server}, nil
148}
149