| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- // 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
- }
|