mirror of
https://github.com/seriousm4x/UpSnap.git
synced 2026-03-31 06:24:06 -04:00
103 lines
2.3 KiB
Go
103 lines
2.3 KiB
Go
package networking
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/mdlayher/wol"
|
|
"github.com/pocketbase/pocketbase/core"
|
|
)
|
|
|
|
func SendMagicPacket(device *core.Record) error {
|
|
ip := device.GetString("ip")
|
|
mac := device.GetString("mac")
|
|
netmask := device.GetString("netmask")
|
|
password := device.GetString("password")
|
|
|
|
// parse inputs
|
|
parsedMac, err := net.ParseMAC(mac)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var bytePassword []byte
|
|
if len(password) == 0 || len(password) == 4 || len(password) == 6 {
|
|
bytePassword = []byte(password)
|
|
} else {
|
|
return fmt.Errorf("error: password must be 0, 4 or 6 characters long")
|
|
}
|
|
|
|
// get target addr
|
|
broadcastIp, err := getBroadcastIp(ip, netmask)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// send wake via udp port 9
|
|
if err := wakeUDP(broadcastIp, ip, parsedMac, bytePassword); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func wakeUDP(broadcastIp string, deviceIp string, target net.HardwareAddr, password []byte) error {
|
|
c, err := wol.NewClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer c.Close()
|
|
|
|
// send 6 magic packets to different addresses to enhance chance of waking up
|
|
destinations := []string{
|
|
// default user-calculated broadcast to port 9
|
|
fmt.Sprintf("%s:9", broadcastIp),
|
|
// user-calculated broadcast to port alternative port 7
|
|
fmt.Sprintf("%s:7", broadcastIp),
|
|
// broadcast to port 9
|
|
"255.255.255.255:9",
|
|
// broadcast to alternative port 7
|
|
"255.255.255.255:7",
|
|
// send direct to device via port 9 (for routed network WOL)
|
|
fmt.Sprintf("%s:9", deviceIp),
|
|
// send direct to device via alternative port 7 (for routed network WOL)
|
|
fmt.Sprintf("%s:7", deviceIp),
|
|
}
|
|
|
|
for _, dest := range destinations {
|
|
if err := c.WakePassword(dest, target, password); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getBroadcastIp(ipStr, maskStr string) (string, error) {
|
|
ip := net.ParseIP(ipStr)
|
|
if ip == nil {
|
|
return "", errors.New("ip not a valid ipv4 address")
|
|
}
|
|
ip = ip.To4()
|
|
if ip == nil {
|
|
return "", errors.New("ip not a valid ipv4 address")
|
|
}
|
|
|
|
mask := net.ParseIP(maskStr)
|
|
if mask == nil {
|
|
return "", errors.New("subnet mask not a valid ipv4 address")
|
|
}
|
|
mask = mask.To4()
|
|
ip = ip.To4()
|
|
if ip == nil {
|
|
return "", errors.New("subnet mask not a valid ipv4 address")
|
|
}
|
|
|
|
broadcast := make(net.IP, 4)
|
|
for i := range ip {
|
|
broadcast[i] = ip[i] | ^mask[i]
|
|
}
|
|
|
|
return broadcast.String(), nil
|
|
}
|