sendEthernet.go 2.6 KB

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