"Fossies" - the Fresh Open Source Software Archive 
Member "AdGuardHome-0.104.3/internal/dhcpd/dhcpd.go" (19 Nov 2020, 6157 Bytes) of package /linux/misc/dns/AdGuardHome-0.104.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the latest
Fossies "Diffs" side-by-side code changes report for "dhcpd.go":
0.104.1_vs_0.104.3.
1 // Package dhcpd provides a DHCP server.
2 package dhcpd
3
4 import (
5 "encoding/hex"
6 "net"
7 "net/http"
8 "path/filepath"
9 "runtime"
10 "strconv"
11 "strings"
12 "time"
13
14 "github.com/AdguardTeam/AdGuardHome/internal/util"
15 "github.com/AdguardTeam/golibs/log"
16 )
17
18 const (
19 defaultDiscoverTime = time.Second * 3
20 leaseExpireStatic = 1
21 )
22
23 var webHandlersRegistered = false
24
25 // Lease contains the necessary information about a DHCP lease
26 type Lease struct {
27 HWAddr net.HardwareAddr `json:"mac"`
28 IP net.IP `json:"ip"`
29 Hostname string `json:"hostname"`
30
31 // Lease expiration time
32 // 1: static lease
33 Expiry time.Time `json:"expires"`
34 }
35
36 // ServerConfig - DHCP server configuration
37 // field ordering is important -- yaml fields will mirror ordering from here
38 type ServerConfig struct {
39 Enabled bool `yaml:"enabled"`
40 InterfaceName string `yaml:"interface_name"`
41
42 Conf4 V4ServerConf `yaml:"dhcpv4"`
43 Conf6 V6ServerConf `yaml:"dhcpv6"`
44
45 WorkDir string `yaml:"-"`
46 DBFilePath string `yaml:"-"` // path to DB file
47
48 // Called when the configuration is changed by HTTP request
49 ConfigModified func() `yaml:"-"`
50
51 // Register an HTTP handler
52 HTTPRegister func(string, string, func(http.ResponseWriter, *http.Request)) `yaml:"-"`
53 }
54
55 type OnLeaseChangedT func(flags int)
56
57 // flags for onLeaseChanged()
58 const (
59 LeaseChangedAdded = iota
60 LeaseChangedAddedStatic
61 LeaseChangedRemovedStatic
62
63 LeaseChangedDBStore
64 )
65
66 // Server - the current state of the DHCP server
67 type Server struct {
68 srv4 DHCPServer
69 srv6 DHCPServer
70
71 conf ServerConfig
72
73 // Called when the leases DB is modified
74 onLeaseChanged []OnLeaseChangedT
75 }
76
77 type ServerInterface interface {
78 Leases(flags int) []Lease
79 SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT)
80 }
81
82 // CheckConfig checks the configuration
83 func (s *Server) CheckConfig(config ServerConfig) error {
84 return nil
85 }
86
87 // Create - create object
88 func Create(config ServerConfig) *Server {
89 s := &Server{}
90
91 s.conf.Enabled = config.Enabled
92 s.conf.InterfaceName = config.InterfaceName
93 s.conf.HTTPRegister = config.HTTPRegister
94 s.conf.ConfigModified = config.ConfigModified
95 s.conf.DBFilePath = filepath.Join(config.WorkDir, dbFilename)
96
97 if !webHandlersRegistered && s.conf.HTTPRegister != nil {
98 if runtime.GOOS == "windows" {
99 // Our DHCP server doesn't work on Windows yet, so
100 // signal that to the front with an HTTP 501.
101 //
102 // TODO(a.garipov): This needs refactoring. We
103 // shouldn't even try and initialize a DHCP server on
104 // Windows, but there are currently too many
105 // interconnected parts--such as HTTP handlers and
106 // frontend--to make that work properly.
107 s.registerNotImplementedHandlers()
108 } else {
109 s.registerHandlers()
110 }
111
112 webHandlersRegistered = true
113 }
114
115 var err4, err6 error
116 v4conf := config.Conf4
117 v4conf.Enabled = s.conf.Enabled
118 if len(v4conf.RangeStart) == 0 {
119 v4conf.Enabled = false
120 }
121 v4conf.InterfaceName = s.conf.InterfaceName
122 v4conf.notify = s.onNotify
123 s.srv4, err4 = v4Create(v4conf)
124
125 v6conf := config.Conf6
126 v6conf.Enabled = s.conf.Enabled
127 if len(v6conf.RangeStart) == 0 {
128 v6conf.Enabled = false
129 }
130 v6conf.InterfaceName = s.conf.InterfaceName
131 v6conf.notify = s.onNotify
132 s.srv6, err6 = v6Create(v6conf)
133
134 if err4 != nil {
135 log.Error("%s", err4)
136 return nil
137 }
138 if err6 != nil {
139 log.Error("%s", err6)
140 return nil
141 }
142
143 if s.conf.Enabled && !v4conf.Enabled && !v6conf.Enabled {
144 log.Error("Can't enable DHCP server because neither DHCPv4 nor DHCPv6 servers are configured")
145 return nil
146 }
147
148 // we can't delay database loading until DHCP server is started,
149 // because we need static leases functionality available beforehand
150 s.dbLoad()
151 return s
152 }
153
154 // server calls this function after DB is updated
155 func (s *Server) onNotify(flags uint32) {
156 if flags == LeaseChangedDBStore {
157 s.dbStore()
158 return
159 }
160
161 s.notify(int(flags))
162 }
163
164 // SetOnLeaseChanged - set callback
165 func (s *Server) SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT) {
166 s.onLeaseChanged = append(s.onLeaseChanged, onLeaseChanged)
167 }
168
169 func (s *Server) notify(flags int) {
170 if len(s.onLeaseChanged) == 0 {
171 return
172 }
173 for _, f := range s.onLeaseChanged {
174 f(flags)
175 }
176 }
177
178 // WriteDiskConfig - write configuration
179 func (s *Server) WriteDiskConfig(c *ServerConfig) {
180 c.Enabled = s.conf.Enabled
181 c.InterfaceName = s.conf.InterfaceName
182 s.srv4.WriteDiskConfig4(&c.Conf4)
183 s.srv6.WriteDiskConfig6(&c.Conf6)
184 }
185
186 // Start will listen on port 67 and serve DHCP requests.
187 func (s *Server) Start() error {
188 err := s.srv4.Start()
189 if err != nil {
190 log.Error("DHCPv4: start: %s", err)
191 return err
192 }
193
194 err = s.srv6.Start()
195 if err != nil {
196 log.Error("DHCPv6: start: %s", err)
197 return err
198 }
199
200 return nil
201 }
202
203 // Stop closes the listening UDP socket
204 func (s *Server) Stop() {
205 s.srv4.Stop()
206 s.srv6.Stop()
207 }
208
209 // flags for Leases() function
210 const (
211 LeasesDynamic = 1
212 LeasesStatic = 2
213 LeasesAll = LeasesDynamic | LeasesStatic
214 )
215
216 // Leases returns the list of current DHCP leases (thread-safe)
217 func (s *Server) Leases(flags int) []Lease {
218 result := s.srv4.GetLeases(flags)
219
220 v6leases := s.srv6.GetLeases(flags)
221 result = append(result, v6leases...)
222
223 return result
224 }
225
226 // FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
227 func (s *Server) FindMACbyIP(ip net.IP) net.HardwareAddr {
228 if ip.To4() != nil {
229 return s.srv4.FindMACbyIP(ip)
230 }
231 return s.srv6.FindMACbyIP(ip)
232 }
233
234 // AddStaticLease - add static v4 lease
235 func (s *Server) AddStaticLease(lease Lease) error {
236 return s.srv4.AddStaticLease(lease)
237 }
238
239 // Parse option string
240 // Format:
241 // CODE TYPE VALUE
242 func parseOptionString(s string) (uint8, []byte) {
243 s = strings.TrimSpace(s)
244 scode := util.SplitNext(&s, ' ')
245 t := util.SplitNext(&s, ' ')
246 sval := util.SplitNext(&s, ' ')
247
248 code, err := strconv.Atoi(scode)
249 if err != nil || code <= 0 || code > 255 {
250 return 0, nil
251 }
252
253 var val []byte
254
255 switch t {
256 case "hex":
257 val, err = hex.DecodeString(sval)
258 if err != nil {
259 return 0, nil
260 }
261
262 case "ip":
263 ip := net.ParseIP(sval)
264 if ip == nil {
265 return 0, nil
266 }
267 val = ip
268 if ip.To4() != nil {
269 val = ip.To4()
270 }
271
272 default:
273 return 0, nil
274 }
275
276 return uint8(code), val
277 }