前阵子在少数派上写了一篇水文发表在这里把手机变为生产力工具,打造免费的华为云电脑 https://sspai.com/post/52303,老婆那时候赞助我买的华为大屏手机,我才想着怎么把手机弄成PC机一样能方便的工作。
其实对于我有DDNS域名,再加上可以连入内网VPN,路由出口就是公网IP,剩下唯一需要解决的问题是如何远程开机,所以我就再水一篇帖贴代码,好久没写文章了。
在支持WOL功能的网卡上都支持开机唤醒,一般比较古老的十多年的机器都支持这个,这个唤醒的网络包叫做Magic Packets,是AMD发起的非事实的业界标准。
具体到对应的协议包是对应UDP的9号端口,基本包是6个字节的0xFF,然后16次重复目标接口的MAC地址,总共是102字节
这个用go实现的代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
package main
import (
"bytes"
"encoding/binary"
"flag"
"fmt"
"net"
"os"
"regexp"
)
type MACAddress [6]byte
type MagicPacket struct {
header [6]byte
payload [16]MACAddress
}
var (
delims = ":-"
reMAC = regexp.MustCompile(`^([0-9a-fA-F]{2}[` + delims + `]){5}([0-9a-fA-F]{2})$`)
macAddr string
bcastInterface string
)
func init() {
flag.StringVar(&macAddr, "mac", "", "wake up by MAC address, a valid MAC is like: 01-02-03-04-05-06, 01:02:03:04:05:06")
flag.StringVar(&bcastInterface, "interface", "", "outbound interface to broadcast using")
flag.Usage = usage
}
func usage() {
flag.PrintDefaults()
os.Exit(2)
}
func NewMagicBuff(mac string) (*MagicPacket, error) {
var packet MagicPacket
var macAddr MACAddress
if !reMAC.MatchString(mac) {
return nil, fmt.Errorf("%s is not a IEEE 802 MAC-48 address", mac)
}
hwAddr, err := net.ParseMAC(mac)
if err != nil {
return nil, err
}
for idx := range macAddr {
macAddr[idx] = hwAddr[idx]
}
for idx := range packet.header {
packet.header[idx] = 0xFF
}
for idx := range packet.payload {
packet.payload[idx] = macAddr
}
return &packet, nil
}
func main() {
var localaddr *net.UDPAddr
flag.Parse()
if macAddr == "" {
usage()
}
fmt.Printf("Mac is %s, interface is %s \n", macAddr, bcastInterface)
ief, _ := net.InterfaceByName(bcastInterface)
addrs, _ := ief.Addrs()
for _, addr := range addrs {
switch ip := addr.(type) {
case *net.IPNet:
if ip.IP.DefaultMask() != nil {
fmt.Println(ip.IP)
localaddr = &net.UDPAddr{
IP: ip.IP,
}
}
}
}
// ipwake := "192.168.2.15"
// addrip := net.ParseIP(ipwake)
remoteAddr, _ := net.ResolveUDPAddr("udp", "255.255.255.255:9")
conn, _ := net.DialUDP("udp", localaddr, remoteAddr)
defer conn.Close()
var mp *MagicPacket
mp, err := NewMagicBuff(macAddr)
if err != nil {
return
}
var buf bytes.Buffer
if err = binary.Write(&buf, binary.BigEndian, mp); err != nil {
return
}
fmt.Printf("Attempting to send a magic packet to MAC %s, local IP: %s \n", macAddr, localaddr.IP)
conn.Write(buf.Bytes())
fmt.Println("Done!")
}
|
代码简单清晰就没写什么注释了,这段代码可以直接编译放到路由上运行,调用的时候一个参数是WAN口名称,写一段这个脚本就可以轻松调用了
1
2
3
4
5
6
|
#!/bin/sh
MAC_ADDR="01-02-03-04-05-06"
WAKEUP_BIN="wakeup"
LOCALIP_ADDR=$(ifconfig | awk 'NR==1 {if (index($1,":") == 0) print $1; else print substr($1, 0, index($1,":")-1)}')
Basepath=$(cd `dirname $0`; pwd)
$Basepath"/"$WAKEUP_BIN -mac "$MAC_ADDR" -interface "$LOCALIP_ADDR"
|