-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparseopts.go
210 lines (180 loc) · 4.96 KB
/
parseopts.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
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package dhcp4
import (
"encoding/binary"
"net"
"time"
"github.com/google/gopacket/layers"
)
func parseDHCPDuration(b []byte) time.Duration {
return time.Duration(binary.BigEndian.Uint32(b)) * time.Second
}
// Option is an interface implemented by all Opt* DHCP option types.
type Option interface {
Type() layers.DHCPOpt
}
// OptSubnetMask represents a SubnetMask DHCP option.
type OptSubnetMask struct {
Mask net.IPMask
}
// Type implements Option.
func (o *OptSubnetMask) Type() layers.DHCPOpt {
return layers.DHCPOptSubnetMask
}
// OptBroadcast represents a Broadcast DHCP option.
type OptBroadcast struct {
Broadcast net.IP
}
// Type implements Option.
func (o *OptBroadcast) Type() layers.DHCPOpt {
return layers.DHCPOptBroadcastAddr
}
// OptRouter represents a Router DHCP option.
type OptRouter struct {
Router net.IP
}
// Type implements Option.
func (o *OptRouter) Type() layers.DHCPOpt {
return layers.DHCPOptRouter
}
// OptDNS represents a DNS DHCP option.
type OptDNS struct {
DNS []net.IP
}
// Type implements Option.
func (o *OptDNS) Type() layers.DHCPOpt {
return layers.DHCPOptDNS
}
// OptLeaseTime represents a LeaseTime DHCP option.
type OptLeaseTime struct {
LeaseTime time.Duration
}
// Type implements Option.
func (o *OptLeaseTime) Type() layers.DHCPOpt {
return layers.DHCPOptLeaseTime
}
// OptT1 represents a T1 DHCP option.
type OptT1 struct {
T1 time.Duration
}
// Type implements Option.
func (o *OptT1) Type() layers.DHCPOpt {
return layers.DHCPOptT1
}
// OptDomainName represents a DomainName DHCP option.
type OptDomainName struct {
DomainName string
}
// Type implements Option.
func (o *OptDomainName) Type() layers.DHCPOpt {
return layers.DHCPOptDomainName
}
// ParseOptions converts layers.DHCPOption type/byte-slice pairs into Option.
func ParseOptions(opts []layers.DHCPOption) []Option {
var results []Option
for _, o := range opts {
switch o.Type {
case layers.DHCPOptSubnetMask:
results = append(results, &OptSubnetMask{net.IPMask(o.Data)})
case layers.DHCPOptRouter:
results = append(results, &OptRouter{net.IP(o.Data)})
case layers.DHCPOptBroadcastAddr:
results = append(results, &OptBroadcast{net.IP(o.Data)})
case layers.DHCPOptDNS:
var dns []net.IP
for b := o.Data; len(b) >= 4; b = b[4:] {
dns = append(dns, net.IP(b[:4]))
}
results = append(results, &OptDNS{dns})
case layers.DHCPOptLeaseTime:
results = append(results, &OptLeaseTime{parseDHCPDuration(o.Data)})
case layers.DHCPOptT1:
results = append(results, &OptT1{parseDHCPDuration(o.Data)})
case layers.DHCPOptDomainName:
results = append(results, &OptDomainName{string(o.Data)})
}
}
return results
}
// HasMessageType returns true if any of the specified DHCP options declares the
// DHCP message type to be mt.
func HasMessageType(opts []layers.DHCPOption, mt layers.DHCPMsgType) bool {
for _, o := range opts {
if o.Type != layers.DHCPOptMessageType {
continue
}
if len(o.Data) != 1 {
continue
}
if layers.DHCPMsgType(o.Data[0]) == mt {
return true
}
}
return false
}
// ServerID extracts all ServerID DHCP options. This is convenient when
// responding to a server.
func ServerID(opts []layers.DHCPOption) []layers.DHCPOption {
for _, o := range opts {
if o.Type == layers.DHCPOptServerID {
return []layers.DHCPOption{o}
}
}
return nil
}
// Lease represents a DHCP lease.
type Lease struct {
IP net.IP
Netmask net.IPMask
Broadcast net.IP
Router net.IP
DNS []net.IP
Domain string
RenewalTime time.Duration
}
// LeaseFromACK constructs a Lease from the specified DHCPACK packet.
func LeaseFromACK(ack *layers.DHCPv4) Lease {
lease := Lease{
IP: ack.YourClientIP,
}
leaseTime := 10 * time.Minute // seems sensible as a fallback
// As per RFC 2131 section 4.4.5:
// renewal time defaults to 50% of the lease time
var renewalTime *time.Duration
for _, opt := range ParseOptions(ack.Options) {
switch o := opt.(type) {
case *OptSubnetMask:
lease.Netmask = o.Mask
case *OptBroadcast:
lease.Broadcast = o.Broadcast
case *OptRouter:
lease.Router = o.Router
case *OptDomainName:
lease.Domain = o.DomainName
case *OptDNS:
lease.DNS = o.DNS
case *OptLeaseTime:
leaseTime = o.LeaseTime
case *OptT1:
renewalTime = &o.T1
}
}
if renewalTime == nil {
d := time.Duration(float64(leaseTime) * 0.5)
renewalTime = &d
}
lease.RenewalTime = *renewalTime
return lease
}