aboutsummaryrefslogtreecommitdiff
path: root/core/setup/file.go
blob: a0b90c3ca2d9d05a6545e774e0d7ac5a92d18425 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package setup

import (
	"fmt"
	"net"
	"os"

	"github.com/miekg/coredns/middleware"
	"github.com/miekg/coredns/middleware/file"
)

// File sets up the file middleware.
func File(c *Controller) (middleware.Middleware, error) {
	zones, err := fileParse(c)
	if err != nil {
		return nil, err
	}

	// Add startup functions to notify the master(s).
	for _, n := range zones.Names {
		c.Startup = append(c.Startup, func() error {
			zones.Z[n].StartupOnce.Do(func() {
				if len(zones.Z[n].TransferTo) > 0 {
					zones.Z[n].Notify()
				}
				zones.Z[n].Reload(nil)
			})
			return nil
		})
	}

	return func(next middleware.Handler) middleware.Handler {
		return file.File{Next: next, Zones: zones}
	}, nil

}

func fileParse(c *Controller) (file.Zones, error) {
	z := make(map[string]*file.Zone)
	names := []string{}
	for c.Next() {
		if c.Val() == "file" {
			// file db.file [zones...]
			if !c.NextArg() {
				return file.Zones{}, c.ArgErr()
			}
			fileName := c.Val()

			origins := c.ServerBlockHosts
			args := c.RemainingArgs()
			if len(args) > 0 {
				origins = args
			}

			reader, err := os.Open(fileName)
			if err != nil {
				// bail out
				return file.Zones{}, err
			}

			for i, _ := range origins {
				origins[i] = middleware.Host(origins[i]).Normalize()
				zone, err := file.Parse(reader, origins[i], fileName)
				if err == nil {
					z[origins[i]] = zone
				} else {
					return file.Zones{}, err
				}
				names = append(names, origins[i])
			}

			noReload := false
			for c.NextBlock() {
				t, _, e := transferParse(c)
				if e != nil {
					return file.Zones{}, e
				}
				switch c.Val() {
				case "no_reload":
					noReload = true
				}
				// discard from, here, maybe check and show log when we do?
				for _, origin := range origins {
					if t != nil {
						z[origin].TransferTo = append(z[origin].TransferTo, t...)
					}
					z[origin].NoReload = noReload
				}
			}
		}
	}
	return file.Zones{Z: z, Names: names}, nil
}

// transferParse parses transfer statements: 'transfer to [address...]'.
func transferParse(c *Controller) (tos, froms []string, err error) {
	what := c.Val()
	if !c.NextArg() {
		return nil, nil, c.ArgErr()
	}
	value := c.Val()
	switch what {
	case "transfer":
		if value == "to" {
			tos = c.RemainingArgs()
			for i, _ := range tos {
				if tos[i] != "*" {
					if x := net.ParseIP(tos[i]); x == nil {
						return nil, nil, fmt.Errorf("must specify an IP addres: `%s'", tos[i])
					}
					tos[i] = middleware.Addr(tos[i]).Normalize()
				}
			}
		}
		if value == "from" {
			froms = c.RemainingArgs()
			for i, _ := range froms {
				if froms[i] != "*" {
					if x := net.ParseIP(froms[i]); x == nil {
						return nil, nil, fmt.Errorf("must specify an IP addres: `%s'", froms[i])
					}
					froms[i] = middleware.Addr(froms[i]).Normalize()
				} else {
					return nil, nil, fmt.Errorf("can't use '*' in transfer from")
				}
			}
		}
	}
	return
}