blob: 63c51becba5d1106f4c70611b7ea87682bcc16c6 [file] [log] [blame]
Lorenz Brun56a7ae62020-10-29 11:03:30 +01001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package dhcp4c
18
19import (
Lorenz Brundbac6cc2020-11-30 10:57:26 +010020 "encoding/binary"
Lorenz Brun56a7ae62020-10-29 11:03:30 +010021 "net"
22 "time"
23
24 "github.com/insomniacslk/dhcp/dhcpv4"
25)
26
Serge Bazanski216fe7b2021-05-21 18:36:16 +020027// Lease represents a DHCPv4 lease. It only consists of an IP, an expiration
28// timestamp and options as all other relevant parts of the message have been
29// normalized into their respective options. It also contains some smart
30// getters for commonly-used options which extract only valid information from
31// options.
Lorenz Brun56a7ae62020-10-29 11:03:30 +010032type Lease struct {
33 AssignedIP net.IP
34 ExpiresAt time.Time
35 Options dhcpv4.Options
36}
37
Serge Bazanski216fe7b2021-05-21 18:36:16 +020038// SubnetMask returns the SubnetMask option or the default mask if not set or
39// invalid.
Lorenz Brun56a7ae62020-10-29 11:03:30 +010040// It returns nil if the lease is nil.
41func (l *Lease) SubnetMask() net.IPMask {
42 if l == nil {
43 return nil
44 }
45 mask := net.IPMask(dhcpv4.GetIP(dhcpv4.OptionSubnetMask, l.Options))
Serge Bazanski216fe7b2021-05-21 18:36:16 +020046 // If given mask is not valid, use the default mask.
47 if _, bits := mask.Size(); bits != 32 {
Lorenz Brun56a7ae62020-10-29 11:03:30 +010048 mask = l.AssignedIP.DefaultMask()
49 }
50 return mask
51}
52
53// IPNet returns an IPNet from the assigned IP and subnet mask.
54// It returns nil if the lease is nil.
55func (l *Lease) IPNet() *net.IPNet {
56 if l == nil {
57 return nil
58 }
59 return &net.IPNet{
60 IP: l.AssignedIP,
61 Mask: l.SubnetMask(),
62 }
63}
64
Serge Bazanski216fe7b2021-05-21 18:36:16 +020065// Router returns the first valid router from the DHCP router option or nil if
66// none such exists.
Lorenz Brun56a7ae62020-10-29 11:03:30 +010067// It returns nil if the lease is nil.
68func (l *Lease) Router() net.IP {
69 if l == nil {
70 return nil
71 }
72 routers := dhcpv4.GetIPs(dhcpv4.OptionRouter, l.Options)
73 for _, r := range routers {
74 if r.IsGlobalUnicast() || r.IsLinkLocalUnicast() {
75 return r
76 }
77 }
78 // No (valid) router found
79 return nil
80}
Lorenz Brundbac6cc2020-11-30 10:57:26 +010081
82// DNSServers represents an ordered collection of DNS servers
83type DNSServers []net.IP
84
85func (a DNSServers) Equal(b DNSServers) bool {
86 if len(a) == len(b) {
87 if len(a) == 0 {
88 return true // both are empty or nil
89 }
90 for i, aVal := range a {
91 if !aVal.Equal(b[i]) {
92 return false
93 }
94 }
95 return true
96 }
97 return false
98
99}
100
101func ip4toInt(ip net.IP) uint32 {
102 ip4 := ip.To4()
103 if ip4 == nil {
104 return 0
105 }
106 return binary.BigEndian.Uint32(ip4)
107}
108
Serge Bazanski216fe7b2021-05-21 18:36:16 +0200109// DNSServers returns all unique valid DNS servers from the DHCP
110// DomainNameServers options.
Lorenz Brundbac6cc2020-11-30 10:57:26 +0100111// It returns nil if the lease is nil.
112func (l *Lease) DNSServers() DNSServers {
113 if l == nil {
114 return nil
115 }
116 rawServers := dhcpv4.GetIPs(dhcpv4.OptionDomainNameServer, l.Options)
117 var servers DNSServers
118 serversSeenMap := make(map[uint32]struct{})
119 for _, s := range rawServers {
120 ip4Num := ip4toInt(s)
121 if s.IsGlobalUnicast() || s.IsLinkLocalUnicast() || ip4Num != 0 {
122 if _, ok := serversSeenMap[ip4Num]; ok {
123 continue
124 }
125 serversSeenMap[ip4Num] = struct{}{}
126 servers = append(servers, s)
127 }
128 }
129 return servers
130}