Skip to content

Commit

Permalink
DHCPv4: syscall -> x/sys/unix
Browse files Browse the repository at this point in the history
Fixes #156

Build a simple client like so:
```
package main

import (
    "fmt"
    "time"

    "github.com/insomniacslk/dhcp/dhcpv4"
)

func main() {
    client := dhcpv4.Client{ReadTimeout: 5 * time.Second, WriteTimeout: 5 * time.Second}
    conversation, err := client.Exchange("en0", nil)
    if err != nil {
        fmt.Println(err)
    }
    for _, m := range conversation {
        fmt.Println(m.Summary())
    }
}
```

and run:
```
$ sudo ./main
Password:
DHCPv4
  opcode=BootRequest
  hwtype=Ethernet
  hwaddrlen=6
  hopcount=0
  transactionid=0xabfad715
  numseconds=0
  flags=Broadcast (0x8000)
  clientipaddr=0.0.0.0
  youripaddr=0.0.0.0
  serveripaddr=0.0.0.0
  gatewayipaddr=0.0.0.0
  clienthwaddr=8c:85:90:20:2e:33
  serverhostname=
  bootfilename=
  options=
    DHCP Message Type -> DISCOVER
    Parameter Request List -> [Subnet Mask, Router, Domain Name, Domain Name Server]
    End -> []

DHCPv4
  opcode=BootReply
  hwtype=Ethernet
  hwaddrlen=6
  hopcount=0
  transactionid=0xabfad715
  numseconds=0
  flags=Broadcast (0x8000)
  clientipaddr=0.0.0.0
  youripaddr=192.168.0.105
  serveripaddr=0.0.0.0
  gatewayipaddr=0.0.0.0
  clienthwaddr=8c:85:90:20:2e:33
  serverhostname=
  bootfilename=
  options=
    DHCP Message Type -> OFFER
    Server Identifier -> 192.168.0.1
    IP Addresses Lease Time -> 5648
    Subnet Mask -> ffffff00
    Routers -> 192.168.0.1
    Domain Name Servers -> 8.8.8.8, 8.8.4.4
    End -> []

DHCPv4
  opcode=BootRequest
  hwtype=Ethernet
  hwaddrlen=6
  hopcount=0
  transactionid=0xabfad715
  numseconds=0
  flags=Broadcast (0x8000)
  clientipaddr=0.0.0.0
  youripaddr=0.0.0.0
  serveripaddr=192.168.0.1
  gatewayipaddr=0.0.0.0
  clienthwaddr=8c:85:90:20:2e:33
  serverhostname=
  bootfilename=
  options=
    DHCP Message Type -> REQUEST
    Requested IP Address -> 192.168.0.105
    Server Identifier -> 192.168.0.1
    End -> []

DHCPv4
  opcode=BootReply
  hwtype=Ethernet
  hwaddrlen=6
  hopcount=0
  transactionid=0xabfad715
  numseconds=0
  flags=Broadcast (0x8000)
  clientipaddr=0.0.0.0
  youripaddr=192.168.0.105
  serveripaddr=0.0.0.0
  gatewayipaddr=0.0.0.0
  clienthwaddr=8c:85:90:20:2e:33
  serverhostname=
  bootfilename=
  options=
    DHCP Message Type -> ACK
    Server Identifier -> 192.168.0.1
    IP Addresses Lease Time -> 7200
    Subnet Mask -> ffffff00
    Routers -> 192.168.0.1
    Domain Name Servers -> 8.8.8.8, 8.8.4.4
    End -> []
```
  • Loading branch information
get9 authored and insomniacslk committed Oct 7, 2018
1 parent c3fc640 commit 4eedccf
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 28 deletions.
7 changes: 5 additions & 2 deletions dhcpv4/bindtodevice_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ package dhcpv4

import (
"net"
"syscall"

"golang.org/x/sys/unix"
)

// BindToInterface emulates linux's SO_BINDTODEVICE option for a socket by using
// SO_IP_BOUND_IF.
func BindToInterface(fd int, ifname string) error {
iface, err := net.InterfaceByName(ifname)
if err != nil {
return err
}
return syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_BOUND_IF, iface.Index)
return unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_BOUND_IF, iface.Index)
}
6 changes: 2 additions & 4 deletions dhcpv4/bindtodevice_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

package dhcpv4

import (
"syscall"
)
import "golang.org/x/sys/unix"

func BindToInterface(fd int, ifname string) error {
return syscall.BindToDevice(fd, ifname)
return unix.BindToDevice(fd, ifname)
}
5 changes: 3 additions & 2 deletions dhcpv4/bsdp/vendor_class_identifier_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package bsdp

import (
"fmt"
"syscall"

"golang.org/x/sys/unix"
)

// MakeVendorClassIdentifier calls the sysctl syscall on macOS to get the
// platform model.
func MakeVendorClassIdentifier() (string, error) {
// Fetch hardware model for class ID.
hwModel, err := syscall.Sysctl("hw.model")
hwModel, err := unix.Sysctl("hw.model")
if err != nil {
return "", err
}
Expand Down
42 changes: 22 additions & 20 deletions dhcpv4/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"errors"
"net"
"os"
"syscall"
"time"

"golang.org/x/net/ipv4"
"golang.org/x/sys/unix"
)

// MaxUDPReceivedPacketSize is the (arbitrary) maximum UDP packet size supported
Expand Down Expand Up @@ -69,22 +69,22 @@ func MakeRawBroadcastPacket(payload []byte) ([]byte, error) {
return ret, nil
}

// MakeBroadcastSocket creates a socket that can be passed to syscall.Sendto
// MakeBroadcastSocket creates a socket that can be passed to unix.Sendto
// that will send packets out to the broadcast address.
func MakeBroadcastSocket(ifname string) (int, error) {
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_RAW, unix.IPPROTO_RAW)
if err != nil {
return fd, err
}
err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
if err != nil {
return fd, err
}
err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
err = unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_HDRINCL, 1)
if err != nil {
return fd, err
}
err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_BROADCAST, 1)
if err != nil {
return fd, err
}
Expand All @@ -98,17 +98,17 @@ func MakeBroadcastSocket(ifname string) (int, error) {
// MakeListeningSocket creates a listening socket on 0.0.0.0 for the DHCP client
// port and returns it.
func MakeListeningSocket(ifname string) (int, error) {
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
if err != nil {
return fd, err
}
err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
if err != nil {
return fd, err
}
var addr [4]byte
copy(addr[:], net.IPv4zero.To4())
if err = syscall.Bind(fd, &syscall.SockaddrInet4{Port: ClientPort, Addr: addr}); err != nil {
if err = unix.Bind(fd, &unix.SockaddrInet4{Port: ClientPort, Addr: addr}); err != nil {
return fd, err
}
err = BindToInterface(fd, ifname)
Expand Down Expand Up @@ -184,31 +184,33 @@ func BroadcastSendReceive(sendFd, recvFd int, packet *DHCPv4, readTimeout, write

// Create a goroutine to perform the blocking send, and time it out after
// a certain amount of time.
var destination [4]byte
var (
destination [4]byte
response *DHCPv4
)
copy(destination[:], net.IPv4bcast.To4())
remoteAddr := syscall.SockaddrInet4{Port: ClientPort, Addr: destination}
remoteAddr := unix.SockaddrInet4{Port: ClientPort, Addr: destination}
recvErrors := make(chan error, 1)
var response *DHCPv4
go func(errs chan<- error) {
conn, err := net.FileConn(os.NewFile(uintptr(recvFd), ""))
conn, innerErr := net.FileConn(os.NewFile(uintptr(recvFd), ""))
if err != nil {
errs <- err
errs <- innerErr
return
}
defer conn.Close()
conn.SetReadDeadline(time.Now().Add(readTimeout))

for {
buf := make([]byte, MaxUDPReceivedPacketSize)
n, _, _, _, err := conn.(*net.UDPConn).ReadMsgUDP(buf, []byte{})
if err != nil {
errs <- err
n, _, _, _, innerErr := conn.(*net.UDPConn).ReadMsgUDP(buf, []byte{})
if innerErr != nil {
errs <- innerErr
return
}

response, err = FromBytes(buf[:n])
response, innerErr = FromBytes(buf[:n])
if err != nil {
errs <- err
errs <- innerErr
return
}
// check that this is a response to our message
Expand All @@ -231,7 +233,7 @@ func BroadcastSendReceive(sendFd, recvFd int, packet *DHCPv4, readTimeout, write
}
recvErrors <- nil
}(recvErrors)
if err = syscall.Sendto(sendFd, packetBytes, 0, &remoteAddr); err != nil {
if err = unix.Sendto(sendFd, packetBytes, 0, &remoteAddr); err != nil {
return nil, err
}

Expand Down

0 comments on commit 4eedccf

Please sign in to comment.