package wol //////////////////////////////////////////////////////////////////////////////// import ( "bytes" "encoding/binary" "fmt" "net" "regexp" ) //////////////////////////////////////////////////////////////////////////////// var ( delims = ":-" reMAC = regexp.MustCompile(`^([0-9a-fA-F]{2}[` + delims + `]){5}([0-9a-fA-F]{2})$`) ) //////////////////////////////////////////////////////////////////////////////// // MACAddress represents a 6 byte network mac address. type MACAddress [6]byte // A MagicPacket is constituted of 6 bytes of 0xFF followed by 16-groups of the // destination MAC address. type MagicPacket struct { header [6]byte payload [16]MACAddress } // New 返回一个基于mac地址字符串的魔法包。 func New(mac string) (*MagicPacket, error) { var packet MagicPacket var macAddr MACAddress hwAddr, err := net.ParseMAC(mac) if err != nil { return nil, err } // We only support 6 byte MAC addresses since it is much harder to use the // binary.Write(...) interface when the size of the MagicPacket is dynamic. if !reMAC.MatchString(mac) { return nil, fmt.Errorf("%s is not a IEEE 802 MAC-48 address", mac) } // Copy bytes from the returned HardwareAddr -> a fixed size MACAddress. for idx := range macAddr { macAddr[idx] = hwAddr[idx] } // Setup the header which is 6 repetitions of 0xFF. for idx := range packet.header { packet.header[idx] = 0xFF } // Setup the payload which is 16 repetitions of the MAC addr. for idx := range packet.payload { packet.payload[idx] = macAddr } return &packet, nil } // Marshal 将魔术包结构序列化为一个102字节数组。 func (mp *MagicPacket) Marshal() ([]byte, error) { var buf bytes.Buffer if err := binary.Write(&buf, binary.BigEndian, mp); err != nil { return nil, err } return buf.Bytes(), nil } // ipFromInterface returns a `*net.UDPAddr` from a network interface name. func ipFromInterface(iface string) (*net.UDPAddr, error) { ief, err := net.InterfaceByName(iface) if err != nil { return nil, err } addrs, err := ief.Addrs() if err == nil && len(addrs) <= 0 { err = fmt.Errorf("no address associated with interface %s", iface) } if err != nil { return nil, err } // Validate that one of the addrs is a valid network IP address. for _, addr := range addrs { switch ip := addr.(type) { case *net.IPNet: if !ip.IP.IsLoopback() && ip.IP.To4() != nil { return &net.UDPAddr{ IP: ip.IP, }, nil } } } return nil, fmt.Errorf("no address associated with interface %s", iface) } // wake 执行唤醒指令 func Wake(macAddr string, ip string, port string) error { bcastInterface := "" bcastAddr := fmt.Sprintf("%s:%s", ip, port) udpAddr, err := net.ResolveUDPAddr("udp", bcastAddr) if err != nil { return err } // 获取魔术包 mp, err := New(macAddr) if err != nil { return err } // 魔术包转字节流 bs, err := mp.Marshal() if err != nil { return err } var localAddr *net.UDPAddr if bcastInterface != "" { localAddr, err = ipFromInterface(bcastInterface) if err != nil { return err } } // 创建UDP链接 conn, err := net.DialUDP("udp", localAddr, udpAddr) if err != nil { return err } defer conn.Close() // 开始发送UDP数据 fmt.Printf("正在发送魔术包MAC: %s 目标: %s\n", macAddr, bcastAddr) n, err := conn.Write(bs) if err == nil && n != 102 { err = fmt.Errorf("已发送的魔术包 %d 字节 (应发送魔术包 102 字节)", n) } if err != nil { return err } fmt.Printf("魔术包发送成功MAC: %s 目标: %s\n", macAddr, bcastAddr) return nil } // wake 执行唤醒指令 带指定接口 func WakespecifyInterfac(macAddr string, ip string, port string, bcastInterface string) error { // bcastInterface := "" bcastAddr := fmt.Sprintf("%s:%s", ip, port) udpAddr, err := net.ResolveUDPAddr("udp", bcastAddr) if err != nil { return err } // 获取魔术包 mp, err := New(macAddr) if err != nil { return err } // 魔术包转字节流 bs, err := mp.Marshal() if err != nil { return err } var localAddr *net.UDPAddr if bcastInterface != "" { localAddr, err = ipFromInterface(bcastInterface) if err != nil { return err } } // 创建UDP链接 conn, err := net.DialUDP("udp", localAddr, udpAddr) if err != nil { return err } defer conn.Close() // 开始发送UDP数据 fmt.Printf("正在发送魔术包MAC: %s 目标: %s\n", macAddr, bcastAddr) n, err := conn.Write(bs) if err == nil && n != 102 { err = fmt.Errorf("已发送的魔术包 %d 字节 (应发送魔术包 102 字节)", n) } if err != nil { return err } fmt.Printf("魔术包发送成功MAC: %s 目标: %s\n", macAddr, bcastAddr) return nil }