1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
// Copyright 2018-present the CoreDHCP Authors. All rights reserved
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
// +build linux
package server
import (
"fmt"
"net"
"syscall"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/insomniacslk/dhcp/dhcpv4"
)
//this function sends an unicast to the hardware address defined in resp.ClientHWAddr,
//the layer3 destination address is still the broadcast address;
//iface: the interface where the DHCP message should be sent;
//resp: DHCPv4 struct, which should be sent;
func sendEthernet(iface net.Interface, resp *dhcpv4.DHCPv4) error {
eth := layers.Ethernet{
EthernetType: layers.EthernetTypeIPv4,
SrcMAC: iface.HardwareAddr,
DstMAC: resp.ClientHWAddr,
}
ip := layers.IPv4{
Version: 4,
TTL: 64,
SrcIP: resp.ServerIPAddr,
DstIP: resp.YourIPAddr,
Protocol: layers.IPProtocolUDP,
Flags: layers.IPv4DontFragment,
}
udp := layers.UDP{
SrcPort: dhcpv4.ServerPort,
DstPort: dhcpv4.ClientPort,
}
err := udp.SetNetworkLayerForChecksum(&ip)
if err != nil {
return fmt.Errorf("Send Ethernet: Couldn't set network layer: %v", err)
}
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
}
// Decode a packet
packet := gopacket.NewPacket(resp.ToBytes(), layers.LayerTypeDHCPv4, gopacket.NoCopy)
dhcpLayer := packet.Layer(layers.LayerTypeDHCPv4)
dhcp, ok := dhcpLayer.(gopacket.SerializableLayer)
if !ok {
return fmt.Errorf("Layer %s is not serializable", dhcpLayer.LayerType().String())
}
err = gopacket.SerializeLayers(buf, opts, ð, &ip, &udp, dhcp)
if err != nil {
return fmt.Errorf("Cannot serialize layer: %v", err)
}
data := buf.Bytes()
fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, 0)
if err != nil {
return fmt.Errorf("Send Ethernet: Cannot open socket: %v", err)
}
defer func() {
err = syscall.Close(fd)
if err != nil {
log.Errorf("Send Ethernet: Cannot close socket: %v", err)
}
}()
err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
if err != nil {
log.Errorf("Send Ethernet: 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, //not used
}
err = syscall.Sendto(fd, data, 0, ðAddr)
if err != nil {
return fmt.Errorf("Cannot send frame via socket: %v", err)
}
return nil
}
|