-
Notifications
You must be signed in to change notification settings - Fork 19
/
dhcp.go
98 lines (85 loc) · 2.66 KB
/
dhcp.go
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
package main
import (
"context"
"net"
"time"
etcd "github.com/coreos/etcd/clientv3"
"github.com/golang/glog"
dhcp "github.com/krolaw/dhcp4"
"github.com/pkg/errors"
)
type DHCPHandler struct {
client *etcd.Client
prefix string
timeout time.Duration
ip net.IP
options dhcp.Options
start net.IP
end net.IP
leaseDuration time.Duration
}
func (h *DHCPHandler) ServeDHCP(p dhcp.Packet, msgType dhcp.MessageType, options dhcp.Options) dhcp.Packet {
ctx, cancel := context.WithTimeout(context.Background(), h.timeout)
defer cancel()
switch msgType {
case dhcp.Discover:
glog.Infof("handling discover")
nic := p.CHAddr().String()
ip, err := h.handleDiscover(ctx, nic)
if err != nil {
glog.Errorf("failed to respond to discover request: %v", err)
return nil
}
glog.Infof("offering %v to %v", ip, nic)
return dhcp.ReplyPacket(p, dhcp.Offer, h.ip, ip, h.leaseDuration,
h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
case dhcp.Request:
if server, ok := options[dhcp.OptionServerIdentifier]; ok && !net.IP(server).Equal(h.ip) {
return nil // Message not for this dhcp server
}
reqIP := net.IP(options[dhcp.OptionRequestedIPAddress])
if reqIP == nil {
reqIP = net.IP(p.CIAddr())
}
ip, err := h.handleRequest(ctx, reqIP, p.CHAddr().String())
if err != nil {
glog.Errorf("could not lease: %v", err)
return dhcp.ReplyPacket(p, dhcp.NAK, h.ip, nil, 0, nil)
}
glog.Infof("leased %v to %v", reqIP, p.CHAddr().String())
return dhcp.ReplyPacket(p, dhcp.ACK, h.ip, ip, h.leaseDuration,
h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
case dhcp.Release, dhcp.Decline:
err := h.revokeLease(ctx, p.CHAddr().String())
if err != nil {
glog.Errorf("could not revoke lease for %v: %v", p.CHAddr().String(), err)
}
}
return nil
}
func (h *DHCPHandler) handleDiscover(ctx context.Context, nic string) (net.IP, error) {
leased, err := h.nicLeasedIP(ctx, nic)
if err != nil {
return nil, errors.Wrap(err, "could not lookup existing nic lease")
}
if leased != nil {
glog.Infof("found previous lease for %v", nic)
return leased, nil
}
new, err := h.freeIP(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not find next free ip")
}
return new, nil
}
func (h *DHCPHandler) handleRequest(ctx context.Context, ip net.IP, nic string) (net.IP, error) {
glog.Infof("handling request for %v from %v", ip, nic)
if len(ip) != 4 || ip.Equal(net.IPv4zero) {
return nil, errors.New("invalid ip requested")
}
err := h.leaseIP(ctx, ip, nic, h.leaseDuration*2)
if err != nil {
return nil, errors.Wrap(err, "could not update lease")
}
return ip, nil
}