package magicpacket import ( "bytes" "strings" ) const ( // Magic packet format: 6 bytes of 0xFF followed by 16 repetitions of the MAC address MagicPacketHeader = 6 MacAddressRepetitions = 16 MacAddressLength = 6 // Authentication format for UDP: "AUTH:username:password:" followed by magic packet AuthPrefix = "AUTH:" ) // IsMagicPacket checks if the received data is a valid Wake-on-LAN Magic Packet // Format: 6 bytes of 0xFF followed by 16 repetitions of the MAC address (6 bytes each) func IsMagicPacket(data []byte) bool { // Minimum size: 6 (header) + 16*6 (MAC repetitions) = 102 bytes minSize := MagicPacketHeader + (MacAddressRepetitions * MacAddressLength) if len(data) < minSize { return false } // Check for 6 bytes of 0xFF at the beginning header := data[:MagicPacketHeader] for _, b := range header { if b != 0xFF { return false } } // Extract the MAC address (first 6 bytes after header) macAddr := data[MagicPacketHeader : MagicPacketHeader+MacAddressLength] // Check if the MAC address is repeated 16 times for i := 1; i < MacAddressRepetitions; i++ { offset := MagicPacketHeader + (i * MacAddressLength) if offset+MacAddressLength > len(data) { return false } repeatedMac := data[offset : offset+MacAddressLength] if !bytes.Equal(macAddr, repeatedMac) { return false } } return true } // ExtractAuthFromPacket extracts username and password from an authenticated packet // Format: "AUTH:username:password:" followed by standard magic packet // Returns username, password, magicPacketData, and success status func ExtractAuthFromPacket(data []byte) (string, string, []byte, bool) { dataStr := string(data) // Check for authentication prefix if !strings.HasPrefix(dataStr, AuthPrefix) { return "", "", nil, false } // Find the first colon after "AUTH:" (end of username) searchStart := len(AuthPrefix) firstColon := strings.Index(dataStr[searchStart:], ":") if firstColon == -1 { return "", "", nil, false } firstColon += searchStart // Find the second colon after the first one (end of password) secondColon := strings.Index(dataStr[firstColon+1:], ":") if secondColon == -1 { // If no second colon, the password might be followed directly by binary data // In this case, we need to find where the magic packet starts (6 bytes of 0xFF) // Look for the magic packet header starting after the password passwordEnd := len(dataStr) for i := firstColon + 1; i < len(data) && i < firstColon+100; i++ { // Check if we found the magic packet header (6 consecutive 0xFF bytes) if i+5 < len(data) { allFF := true for j := 0; j < 6; j++ { if data[i+j] != 0xFF { allFF = false break } } if allFF { passwordEnd = i break } } } username := dataStr[searchStart:firstColon] password := dataStr[firstColon+1 : passwordEnd] magicPacketData := data[passwordEnd:] return username, password, magicPacketData, true } secondColon += firstColon + 1 // Extract username and password username := dataStr[searchStart:firstColon] password := dataStr[firstColon+1 : secondColon] // Extract magic packet part (after "AUTH:username:password:") magicPacketStart := secondColon + 1 if magicPacketStart >= len(data) { return "", "", nil, false } magicPacketData := data[magicPacketStart:] return username, password, magicPacketData, true }