wol_wake.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "regexp"
  9. )
  10. /* A complete go sending a WOL packet
  11. This is from
  12. https://sabhiram.com/development/2015/02/16/sending_wol_packets_with_golang.html
  13. */
  14. // A MacAddress is 6 bytes in a row
  15. type MacAddress [6]byte
  16. // A MagicPacket is constituted of 6 bytes of 0xFF followed by
  17. // 16 groups of the destination MAC address.
  18. type MagicPacket struct {
  19. header [6]byte
  20. payload [16]MacAddress
  21. }
  22. // Define globals for MacAddress parsing
  23. var (
  24. delims = ":-"
  25. re_MAC = regexp.MustCompile(`^([0-9a-fA-F]{2}[` + delims + `]){5}([0-9a-fA-F]{2})$`)
  26. )
  27. // This function accepts a MAC Address string, and returns a pointer to
  28. // a MagicPacket object. A Magic Packet is a broadcast frame which
  29. // contains 6 bytes of 0xFF followed by 16 repetitions of a given mac address.
  30. func NewMagicPacket(mac string) (*MagicPacket, error) {
  31. var packet MagicPacket
  32. var macAddr MacAddress
  33. // We only support 6 byte MAC addresses
  34. if !re_MAC.MatchString(mac) {
  35. return nil, errors.New("MAC address " + mac + " is not valid.")
  36. }
  37. hwAddr, err := net.ParseMAC(mac)
  38. if err != nil {
  39. return nil, err
  40. }
  41. // Copy bytes from the returned HardwareAddr -> a fixed size MACAddress
  42. for idx := range macAddr {
  43. macAddr[idx] = hwAddr[idx]
  44. }
  45. // Setup the header which is 6 repetitions of 0xFF
  46. for idx := range packet.header {
  47. packet.header[idx] = 0xFF
  48. }
  49. // Setup the payload which is 16 repetitions of the MAC addr
  50. for idx := range packet.payload {
  51. packet.payload[idx] = macAddr
  52. }
  53. return &packet, nil
  54. }
  55. // This function accepts a MAC address string, and s
  56. // Function to send a magic packet to a given mac address
  57. func SendMagicPacket(tvip, macAddr string) error {
  58. magicPacket, err := NewMagicPacket(macAddr)
  59. if err != nil {
  60. return err
  61. }
  62. // Fill our byte buffer with the bytes in our MagicPacket
  63. var buf bytes.Buffer
  64. binary.Write(&buf, binary.BigEndian, magicPacket)
  65. // Get a UDPAddr to send the broadcast to
  66. udpAddr, err := net.ResolveUDPAddr("udp", tvip)
  67. if err != nil {
  68. fmt.Printf("Unable to get a UDP address for %s\n", tvip)
  69. return err
  70. }
  71. // Open a UDP connection, and defer its cleanup
  72. connection, err := net.DialUDP("udp", nil, udpAddr)
  73. if err != nil {
  74. fmt.Printf("Unable to dial UDP address for %s\n", tvip)
  75. return err
  76. }
  77. defer connection.Close()
  78. // Write the bytes of the MagicPacket to the connection
  79. var neededBytes int = buf.Len()
  80. bytesWritten, err := connection.Write(buf.Bytes())
  81. if err != nil {
  82. fmt.Printf("Unable to write packet to connection\n")
  83. return err
  84. } else if bytesWritten != neededBytes {
  85. fmt.Printf("Warning: %d bytes written, %d expected!\n", bytesWritten, neededBytes)
  86. }
  87. return nil
  88. }