Skip to content

Commit

Permalink
build: support for !linux builds (#6)
Browse files Browse the repository at this point in the history
Makes ARP magic optional.
  • Loading branch information
DSpeichert committed Nov 28, 2021
1 parent f6d1736 commit 03cb277
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.16.x
go-version: 1.17.x

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
Expand Down
5 changes: 5 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ builds:
- -s -w -X github.com/DSpeichert/netbootd/cmd.version={{.Version}} -X github.com/DSpeichert/netbootd/cmd.commit={{.ShortCommit}} -X github.com/DSpeichert/netbootd/cmd.date={{.Date}}
goos:
- linux
- darwin
goarch:
- amd64
- arm
- arm64
goarm:
- 7

archives:
- wrap_in_directory: true
Expand Down
4 changes: 2 additions & 2 deletions cmd/arpinject.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cmd

import (
"github.com/DSpeichert/netbootd/dhcpd"
"github.com/DSpeichert/netbootd/dhcpd/arp"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"net"
Expand Down Expand Up @@ -31,7 +31,7 @@ var arpInjectCmd = &cobra.Command{
Err(err).
Msg("cannot parse mac")
}
if err = dhcpd.InjectArp(parsedIp, parsedMac, dhcpd.ATF_COM, device); err != nil {
if err = arp.InjectArp(parsedIp, parsedMac, arp.ATF_COM, device); err != nil {
log.Error().
Err(err).
Msg("cannot inject arp entry")
Expand Down
31 changes: 31 additions & 0 deletions dhcpd/arp/arp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package arp

import (
"syscall"
)

// ARP Flag values
// these are not in golang.org/x/sys/unix
const (
// completed entry (ha valid)
ATF_COM = 0x02
// permanent entry
ATF_PERM = 0x04
// publish entry
ATF_PUBL = 0x08
// has requested trailers
ATF_USETRAILERS = 0x10
// want to use a netmask (only for proxy entries)
ATF_NETMASK = 0x20
// don't answer this addresses
ATF_DONTPUB = 0x40
)

// https://man7.org/linux/man-pages/man7/arp.7.html
type arpReq struct {
ArpPa syscall.RawSockaddrInet4
ArpHa syscall.RawSockaddr
Flags int32
Netmask syscall.RawSockaddr
Dev [16]byte
}
49 changes: 49 additions & 0 deletions dhcpd/arp/arp_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//go:build linux && !amd64 && !arm64
// +build linux,!amd64,!arm64

package arp

import (
"net"
"os"
"syscall"
"unsafe"

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

// InjectArp injects an ARP entry into dev's ARP table
// syscalls roughly based on https://www.unix.com/302447674-post3.html
// see:
// https://github.com/torvalds/linux/blob/8cf8821e15cd553339a5b48ee555a0439c2b2742/net/ipv4/arp.c#L1179
// https://github.com/torvalds/linux/blob/8cf8821e15cd553339a5b48ee555a0439c2b2742/net/ipv4/arp.c#L1024
func InjectArp(ip net.IP, mac net.HardwareAddr, flags int32, dev string) (err error) {
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
if err != nil {
return
}
f := os.NewFile(uintptr(fd), "")
defer f.Close()

return InjectArpFd(uintptr(fd), ip, mac, flags, dev)
}

func InjectArpFd(fd uintptr, ip net.IP, mac net.HardwareAddr, flags int32, dev string) (err error) {
arpReq := arpReq{
ArpPa: syscall.RawSockaddrInet4{
Family: syscall.AF_INET,
},
//Flags: 0x02 | 0x04, // ATF_COM | ATF_PERM;
Flags: flags,
}
copy(arpReq.ArpPa.Addr[:], ip.To4())
copy(arpReq.ArpHa.Data[:], mac)
copy(arpReq.Dev[:], dev)

_, _, errno := unix.Syscall(unix.SYS_IOCTL, fd, unix.SIOCSARP, uintptr(unsafe.Pointer(&arpReq)))
if errno != 0 {
return errno
}

return
}
34 changes: 7 additions & 27 deletions dhcpd/arp.go → dhcpd/arp/arp_linux_64.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,19 @@
package dhcpd
//go:build linux && (amd64 || arm64)
// +build linux
// +build amd64 arm64

package arp

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

// ARP Flag values
// these are not in golang.org/x/sys/unix
const (
// completed entry (ha valid)
ATF_COM = 0x02
// permanent entry
ATF_PERM = 0x04
// publish entry
ATF_PUBL = 0x08
// has requested trailers
ATF_USETRAILERS = 0x10
// want to use a netmask (only for proxy entries)
ATF_NETMASK = 0x20
// don't answer this addresses
ATF_DONTPUB = 0x40
"golang.org/x/sys/unix"
)

// https://man7.org/linux/man-pages/man7/arp.7.html
type arpReq struct {
ArpPa syscall.RawSockaddrInet4
ArpHa syscall.RawSockaddr
Flags int32
Netmask syscall.RawSockaddr
Dev [16]byte
}

// InjectArp injects an ARP entry into dev's ARP table
// syscalls roughly based on https://www.unix.com/302447674-post3.html
// see:
// https://github.com/torvalds/linux/blob/8cf8821e15cd553339a5b48ee555a0439c2b2742/net/ipv4/arp.c#L1179
Expand Down
18 changes: 18 additions & 0 deletions dhcpd/arp/arp_notlinux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//go:build !linux
// +build !linux

package arp

import (
"errors"
"net"
)

// InjectArp injects an ARP entry into dev's ARP table
func InjectArp(ip net.IP, mac net.HardwareAddr, flags int32, dev string) (err error) {
return errors.New("not implemented")
}

func InjectArpFd(fd uintptr, ip net.IP, mac net.HardwareAddr, flags int32, dev string) (err error) {
return errors.New("not implemented")
}
7 changes: 5 additions & 2 deletions dhcpd/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ package dhcpd
import (
"errors"
"net"
"runtime"
"strings"

"github.com/DSpeichert/netbootd/dhcpd/arp"
mfest "github.com/DSpeichert/netbootd/manifest"
"github.com/insomniacslk/dhcp/dhcpv4"
"golang.org/x/net/ipv4"
Expand Down Expand Up @@ -69,6 +71,7 @@ func (server *Server) HandleMsg4(buf []byte, oob *ipv4.ControlMessage, peer net.
if err != nil {
server.logger.Error().
Err(err).
Int("ifIndex", ifIndex).
Msg("failed to find local interface")
resp = nil
goto response
Expand Down Expand Up @@ -187,9 +190,9 @@ response:
rawConn, err := server.UdpConn.SyscallConn()
if device != "" && err == nil {
rawConn.Control(func(fd uintptr) {
err = InjectArpFd(fd, resp.YourIPAddr, req.ClientHWAddr, ATF_COM, device)
err = arp.InjectArpFd(fd, resp.YourIPAddr, req.ClientHWAddr, arp.ATF_COM, device)
})
if err != nil {
if err != nil && runtime.GOOS == "linux" {
server.logger.Error().
Err(err).
Msg("ioctl failed")
Expand Down

0 comments on commit 03cb277

Please sign in to comment.