117 lines
3.3 KiB
Go
117 lines
3.3 KiB
Go
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
|
|
}
|