fix(shutdown): Fix shutdown command

This commit is contained in:
Björn Benouarets
2025-11-11 20:38:49 +01:00
parent 8ed56f7ba0
commit b8964d7763
4 changed files with 115 additions and 21 deletions

View File

@@ -60,25 +60,52 @@ func ExtractAuthFromPacket(data []byte) (string, string, []byte, bool) {
return "", "", nil, false
}
// Extract authentication part
authEnd := strings.Index(dataStr[len(AuthPrefix):], ":")
if authEnd == -1 {
// Find the first colon after "AUTH:" (end of username)
searchStart := len(AuthPrefix)
firstColon := strings.Index(dataStr[searchStart:], ":")
if firstColon == -1 {
return "", "", nil, false
}
authEnd += len(AuthPrefix)
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
authPart := dataStr[len(AuthPrefix):authEnd]
parts := strings.Split(authPart, ":")
if len(parts) != 2 {
return "", "", nil, false
}
username := parts[0]
password := parts[1]
username := dataStr[searchStart:firstColon]
password := dataStr[firstColon+1 : secondColon]
// Extract magic packet part (after "AUTH:username:password:")
magicPacketStart := authEnd + 1
magicPacketStart := secondColon + 1
if magicPacketStart >= len(data) {
return "", "", nil, false
}

View File

@@ -1,6 +1,7 @@
package server
import (
"encoding/hex"
"fmt"
"net"
"time"
@@ -69,13 +70,30 @@ func (s *UDPServer) Start(done chan bool) {
continue
}
packetData := buffer[:n]
// Debug: Display packet content
hexDump := hex.EncodeToString(packetData)
// Also try to show as string (for auth part)
stringPreview := ""
if len(packetData) > 0 && packetData[0] < 128 {
// Only show string preview if it looks like printable ASCII
maxLen := len(packetData)
if maxLen > 100 {
maxLen = 100
}
stringPreview = string(packetData[:maxLen])
}
masterlog.Info("Received UDP packet", map[string]interface{}{
"bytes": n,
"address": clientAddr,
"bytes": n,
"address": clientAddr,
"hex": hexDump,
"string_preview": stringPreview,
})
// Check authentication and magic packet
if s.isValidAuthenticatedMagicPacket(buffer[:n]) {
if s.isValidAuthenticatedMagicPacket(packetData) {
masterlog.Info("Authenticated Magic Packet detected! Shutting down system...", map[string]interface{}{
"address": clientAddr,
})
@@ -94,14 +112,38 @@ func (s *UDPServer) Start(done chan bool) {
func (s *UDPServer) isValidAuthenticatedMagicPacket(data []byte) bool {
username, password, magicPacketData, ok := magicpacket.ExtractAuthFromPacket(data)
if !ok {
masterlog.Info("Packet does not contain valid auth format", map[string]interface{}{
"packet_size": len(data),
})
return false
}
masterlog.Info("Extracted authentication from packet", map[string]interface{}{
"username": username,
"password_length": len(password),
"magic_packet_size": len(magicPacketData),
})
// Verify authentication
if !s.authenticator.Verify(username, password) {
masterlog.Info("Authentication failed", map[string]interface{}{
"username": username,
})
return false
}
masterlog.Info("Authentication successful", map[string]interface{}{
"username": username,
})
// Check if it's a valid magic packet
return magicpacket.IsMagicPacket(magicPacketData)
isValid := magicpacket.IsMagicPacket(magicPacketData)
if !isValid {
masterlog.Info("Magic packet validation failed", map[string]interface{}{
"magic_packet_size": len(magicPacketData),
"magic_packet_hex": hex.EncodeToString(magicPacketData),
})
}
return isValid
}

View File

@@ -4,15 +4,33 @@
package system
import (
"log"
"os/exec"
"git.secnex.io/secnex/masterlog"
)
// Shutdown shuts down the system (Unix/Linux/macOS)
func Shutdown() {
// Try shutdown command first
cmd := exec.Command("shutdown", "-h", "now")
if err := cmd.Run(); err != nil {
log.Fatalf("Failed to shutdown system: %v", err)
masterlog.Error("Failed to shutdown system (trying with sudo)", map[string]interface{}{
"error": err,
})
// Try with sudo if the first attempt failed
cmd = exec.Command("sudo", "shutdown", "-h", "now")
if err := cmd.Run(); err != nil {
masterlog.Error("Failed to shutdown system even with sudo", map[string]interface{}{
"error": err,
"note": "The application may need to be run with sudo privileges",
})
// Don't use log.Fatalf here, just log the error
// The system might still shutdown or the user can manually shutdown
return
}
}
masterlog.Info("Shutdown command executed successfully")
}

View File

@@ -4,8 +4,9 @@
package system
import (
"log"
"os/exec"
"git.secnex.io/secnex/masterlog"
)
// Shutdown shuts down the system (Windows)
@@ -13,6 +14,12 @@ func Shutdown() {
cmd := exec.Command("shutdown", "/s", "/t", "0")
if err := cmd.Run(); err != nil {
log.Fatalf("Failed to shutdown system: %v", err)
masterlog.Error("Failed to shutdown system", map[string]interface{}{
"error": err,
"note": "The application may need administrator privileges",
})
return
}
masterlog.Info("Shutdown command executed successfully")
}