mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 01:15:41 +08:00
85 lines
2.0 KiB
Go
85 lines
2.0 KiB
Go
package dhcpd
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"net"
|
|
"syscall"
|
|
|
|
"github.com/insomniacslk/dhcp/dhcpv4"
|
|
|
|
"github.com/nadoo/glider/pkg/log"
|
|
)
|
|
|
|
func reply(iface *net.Interface, resp *dhcpv4.DHCPv4) error {
|
|
p := [590]byte{12: 0x08, //ethernet layer: 14 bytes
|
|
14: 0x45, 16: 0x02, 17: 0x40, 22: 0x40, 23: 0x11, //ip layer: 20 bytes
|
|
35: 67, 37: 68, 38: 0x02, 39: 0x2c, //udp layer: 8 bytes
|
|
}
|
|
|
|
copy(p[0:], resp.ClientHWAddr[0:6])
|
|
copy(p[6:], iface.HardwareAddr[0:6])
|
|
copy(p[26:], resp.ServerIPAddr[0:4])
|
|
copy(p[30:], resp.YourIPAddr[0:4])
|
|
|
|
// ip layer checksum
|
|
checksum := checksum(p[14:34])
|
|
binary.BigEndian.PutUint16(p[24:], checksum)
|
|
|
|
// dhcp payload
|
|
copy(p[42:], resp.ToBytes())
|
|
|
|
// udp layer checksum, set to zero
|
|
// https://datatracker.ietf.org/doc/html/rfc768
|
|
// An all zero transmitted checksum value means that the transmitter generated no
|
|
// checksum (for debugging or for higher level protocols that don't care).
|
|
|
|
fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, 0)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot open socket: %v", err)
|
|
}
|
|
defer func() {
|
|
err = syscall.Close(fd)
|
|
if err != nil {
|
|
log.F("dhcpd: cannot close socket: %v", err)
|
|
}
|
|
}()
|
|
|
|
err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
|
|
if err != nil {
|
|
log.F("dhcpd: cannot set option for socket: %v", err)
|
|
}
|
|
|
|
var hwAddr [8]byte
|
|
copy(hwAddr[0:6], resp.ClientHWAddr[0:6])
|
|
ethAddr := syscall.SockaddrLinklayer{
|
|
Protocol: 0,
|
|
Ifindex: iface.Index,
|
|
Halen: 6,
|
|
Addr: hwAddr,
|
|
}
|
|
err = syscall.Sendto(fd, p[:], 0, ðAddr)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot send frame via socket: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func checksum(bytes []byte) uint16 {
|
|
var csum uint32
|
|
for i := 0; i < len(bytes); i += 2 {
|
|
csum += uint32(bytes[i]) << 8
|
|
csum += uint32(bytes[i+1])
|
|
}
|
|
for {
|
|
// Break when sum is less or equals to 0xFFFF
|
|
if csum <= 65535 {
|
|
break
|
|
}
|
|
// Add carry to the sum
|
|
csum = (csum >> 16) + uint32(uint16(csum))
|
|
}
|
|
// Flip all the bits
|
|
return ^uint16(csum)
|
|
}
|