-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
145 lines (121 loc) · 3.48 KB
/
main.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"net"
"net/http"
"strings"
"time"
)
// 发送魔术包的函数
func wakeOnLan(macAddress string) error {
// 验证 MAC 地址格式
if len(macAddress) != 17 {
return fmt.Errorf("invalid MAC address format")
}
// 创建魔术包:前6个字节为 0xFF,后面重复6次目标 MAC 地址
magicPacket := make([]byte, 102)
// 填充魔术包的前 6 个字节为 0xFF
for i := 0; i < 6; i++ {
magicPacket[i] = 0xFF
}
// 提取 MAC 地址并重复 16 次
macBytes := parseMacAddress(macAddress)
for i := 6; i < len(magicPacket); i += len(macBytes) {
copy(magicPacket[i:], macBytes)
}
// 设置目标广播地址和端口
addr := net.UDPAddr{
IP: net.IPv4(255, 255, 255, 255), // 广播地址
Port: 9, // WOL 默认使用端口 9
}
// 创建 UDP 连接
conn, err := net.DialUDP("udp", nil, &addr)
if err != nil {
return err
}
defer conn.Close()
// 发送魔术包
_, err = conn.Write(magicPacket)
if err != nil {
return err
}
// 给目标设备一点时间来接收包并唤醒
time.Sleep(time.Second)
return nil
}
// 解析 MAC 地址为字节数组,支持 `:` 和 `-` 分隔符
func parseMacAddress(macAddress string) []byte {
// 去掉 MAC 地址中的分隔符(支持 `:` 和 `-`)
macAddress = strings.ReplaceAll(macAddress, ":", "")
macAddress = strings.ReplaceAll(macAddress, "-", "")
// 如果 MAC 地址长度不等于 12 字符(6 字节),则无效
if len(macAddress) != 12 {
return nil
}
// 转换为字节数组
macBytes := make([]byte, 6)
for i := 0; i < 6; i++ {
fmt.Sscanf(macAddress[i*2:i*2+2], "%x", &macBytes[i])
}
return macBytes
}
// CLI 入口
func runCLI(mac string) {
if mac == "" {
log.Println("MAC address is required")
return
}
// 调用 WOL 函数
log.Printf("sending magic packet to MAC address: %s\n", mac)
if err := wakeOnLan(mac); err != nil {
log.Printf("failed to send magic packet: %v\n", err)
} else {
log.Println("magic packet sent successfully!")
}
}
// API 入口
func wakeOnLanHandler(w http.ResponseWriter, r *http.Request) {
var req struct {
MacAddress string `json:"mac_address"`
}
// 解析 JSON 请求体
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil || req.MacAddress == "" {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
// 记录请求的 MAC 地址和请求者 IP 地址
clientIP := r.RemoteAddr
log.Printf("received request from IP: %s to wake up MAC address: %s\n", clientIP, req.MacAddress)
// 调用 WOL 函数
err = wakeOnLan(req.MacAddress)
if err != nil {
log.Printf("failed to send magic packet to %s: %v\n", req.MacAddress, err)
http.Error(w, fmt.Sprintf("failed to send magic packet: %v", err), http.StatusInternalServerError)
return
}
// 返回成功响应
log.Printf("magic packet successfully sent to %s\n", req.MacAddress)
w.WriteHeader(http.StatusOK)
w.Write([]byte("magic packet sent successfully!"))
}
func main() {
// 定义命令行参数
mac := flag.String("mac", "", "The MAC address to wake up (format: XX:XX:XX:XX:XX:XX or XX-XX-XX-XX-XX-XX)")
flag.Parse()
// 如果指定了 -mac 参数,执行 CLI 模式
if *mac != "" {
runCLI(*mac)
return
}
// 启动 Web 服务器 API 模式
http.HandleFunc("/wakeonlan", wakeOnLanHandler)
// 启动 Web 服务器
log.Println("starting WOL API server on port 8080...")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatalf("failed to start server: %v\n", err)
}
}