summaryrefslogtreecommitdiffhomepage
path: root/dhcpv4/dhcpv4.go
diff options
context:
space:
mode:
Diffstat (limited to 'dhcpv4/dhcpv4.go')
-rw-r--r--dhcpv4/dhcpv4.go76
1 files changed, 73 insertions, 3 deletions
diff --git a/dhcpv4/dhcpv4.go b/dhcpv4/dhcpv4.go
index 49eeae1..182d4a4 100644
--- a/dhcpv4/dhcpv4.go
+++ b/dhcpv4/dhcpv4.go
@@ -5,10 +5,11 @@ import (
"encoding/binary"
"errors"
"fmt"
- "github.com/insomniacslk/dhcp/iana"
"log"
"net"
"strings"
+
+ "github.com/insomniacslk/dhcp/iana"
)
// HeaderSize is the DHCPv4 header size in bytes.
@@ -37,6 +38,35 @@ type DHCPv4 struct {
options []Option
}
+// IPv4AddrsForInterface obtains the currently-configured, non-loopback IPv4
+// addresses for iface.
+func IPv4AddrsForInterface(iface *net.Interface) ([]net.IP, error) {
+ addrs, err := iface.Addrs()
+ var v4addrs []net.IP
+ if err != nil {
+ return v4addrs, err
+ }
+ for _, addr := range addrs {
+ var ip net.IP
+ switch v := addr.(type) {
+ case *net.IPAddr:
+ ip = v.IP
+ case *net.IPNet:
+ ip = v.IP
+ }
+
+ if ip == nil || ip.IsLoopback() {
+ continue
+ }
+ ip = ip.To4()
+ if ip == nil {
+ continue
+ }
+ v4addrs = append(v4addrs, ip)
+ }
+ return v4addrs, nil
+}
+
// GenerateTransactionID generates a random 32-bits number suitable for use as
// TransactionID
func GenerateTransactionID() (*uint32, error) {
@@ -105,7 +135,7 @@ func NewDiscoveryForInterface(ifname string) (*DHCPv4, error) {
d.SetBroadcast()
d.AddOption(Option{
Code: OptionDHCPMessageType,
- Data: []byte{1},
+ Data: []byte{byte(MessageTypeDiscover)},
})
d.AddOption(Option{
Code: OptionParameterRequestList,
@@ -116,6 +146,46 @@ func NewDiscoveryForInterface(ifname string) (*DHCPv4, error) {
return d, nil
}
+// NewInformForInterface builds a new DHCPv4 Informational message with default
+// Ethernet HW type and the hardware address obtained from the specified
+// interface. It does NOT put a DHCP End option at the end.
+func NewInformForInterface(ifname string, needsBroadcast bool) (*DHCPv4, error) {
+ d, err := New()
+ if err != nil {
+ return nil, err
+ }
+
+ // get hw addr
+ iface, err := net.InterfaceByName(ifname)
+ if err != nil {
+ return nil, err
+ }
+ d.SetOpcode(OpcodeBootRequest)
+ d.SetHwType(iana.HwTypeEthernet)
+ d.SetHwAddrLen(uint8(len(iface.HardwareAddr)))
+ d.SetClientHwAddr(iface.HardwareAddr)
+
+ if needsBroadcast {
+ d.SetBroadcast()
+ } else {
+ d.SetUnicast()
+ }
+
+ // Set Client IP as iface's currently-configured IP.
+ localIPs, err := IPv4AddrsForInterface(iface)
+ if err != nil || len(localIPs) == 0 {
+ return nil, fmt.Errorf("could not get local IPs for iface %s", ifname)
+ }
+ d.SetClientIPAddr(localIPs[0])
+
+ d.AddOption(Option{
+ Code: OptionDHCPMessageType,
+ Data: []byte{byte(MessageTypeInform)},
+ })
+
+ return d, nil
+}
+
// RequestFromOffer builds a DHCPv4 request from an offer.
func RequestFromOffer(offer DHCPv4) (*DHCPv4, error) {
d, err := New()
@@ -147,7 +217,7 @@ func RequestFromOffer(offer DHCPv4) (*DHCPv4, error) {
d.SetServerIPAddr(serverIP)
d.AddOption(Option{
Code: OptionDHCPMessageType,
- Data: []byte{3},
+ Data: []byte{byte(MessageTypeRequest)},
})
d.AddOption(Option{
Code: OptionRequestedIPAddress,