224 lines
4.4 KiB
Go
224 lines
4.4 KiB
Go
package network
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"NanoKVM-Server/proto"
|
|
)
|
|
|
|
const (
|
|
WolMacFile = "/etc/kvm/cache/wol"
|
|
)
|
|
|
|
func (s *Service) WakeOnLAN(c *gin.Context) {
|
|
var req proto.WakeOnLANReq
|
|
var rsp proto.Response
|
|
|
|
if err := proto.ParseFormRequest(c, &req); err != nil {
|
|
rsp.ErrRsp(c, -1, "invalid arguments")
|
|
return
|
|
}
|
|
|
|
mac, err := parseMAC(req.Mac)
|
|
if err != nil {
|
|
rsp.ErrRsp(c, -2, "invalid MAC address")
|
|
return
|
|
}
|
|
|
|
command := fmt.Sprintf("ether-wake -b %s", mac)
|
|
cmd := exec.Command("sh", "-c", command)
|
|
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
log.Errorf("failed to wake on lan: %s", err)
|
|
rsp.ErrRsp(c, -3, string(output))
|
|
return
|
|
}
|
|
|
|
go saveMac(mac)
|
|
|
|
rsp.OkRsp(c)
|
|
log.Debugf("wake on lan: %s", mac)
|
|
}
|
|
|
|
func (s *Service) GetMac(c *gin.Context) {
|
|
var rsp proto.Response
|
|
|
|
content, err := os.ReadFile(WolMacFile)
|
|
if err != nil {
|
|
rsp.ErrRsp(c, -2, "open file error")
|
|
return
|
|
}
|
|
|
|
data := &proto.GetMacRsp{
|
|
Macs: strings.Split(string(content), "\n"),
|
|
}
|
|
|
|
rsp.OkRspWithData(c, data)
|
|
}
|
|
|
|
func (s *Service) SetMacName(c *gin.Context) {
|
|
var req proto.SetMacNameReq // Mac:string Name:string
|
|
var rsp proto.Response
|
|
|
|
if err := proto.ParseFormRequest(c, &req); err != nil {
|
|
rsp.ErrRsp(c, -1, "invalid arguments")
|
|
return
|
|
}
|
|
|
|
content, err := os.ReadFile(WolMacFile)
|
|
if err != nil {
|
|
log.Errorf("failed to open %s: %s", WolMacFile, err)
|
|
rsp.ErrRsp(c, -2, "read failed")
|
|
return
|
|
}
|
|
|
|
macs := strings.Split(string(content), "\n")
|
|
var newLines []string
|
|
macFound := false
|
|
|
|
for _, line := range macs {
|
|
parts := strings.Split(line, " ")
|
|
if req.Mac != parts[0] {
|
|
newLines = append(newLines, line)
|
|
continue
|
|
}
|
|
newLines = append(newLines, parts[0]+" "+req.Name)
|
|
macFound = true
|
|
}
|
|
|
|
if !macFound {
|
|
log.Errorf("failed to found mac %s: %s", req.Mac, err)
|
|
rsp.ErrRsp(c, -3, "write failed")
|
|
return
|
|
}
|
|
|
|
data := strings.Join(newLines, "\n")
|
|
err = os.WriteFile(WolMacFile, []byte(data), 0o644)
|
|
if err != nil {
|
|
log.Errorf("failed to write %s: %s", WolMacFile, err)
|
|
rsp.ErrRsp(c, -3, "write failed")
|
|
return
|
|
}
|
|
|
|
rsp.OkRsp(c)
|
|
log.Debugf("set wol mac name: %s %s", req.Mac, req.Name)
|
|
}
|
|
|
|
func (s *Service) DeleteMac(c *gin.Context) {
|
|
var req proto.DeleteMacReq
|
|
var rsp proto.Response
|
|
|
|
if err := proto.ParseFormRequest(c, &req); err != nil {
|
|
rsp.ErrRsp(c, -1, "invalid arguments")
|
|
return
|
|
}
|
|
|
|
content, err := os.ReadFile(WolMacFile)
|
|
if err != nil {
|
|
log.Errorf("failed to open %s: %s", WolMacFile, err)
|
|
rsp.ErrRsp(c, -2, "read failed")
|
|
return
|
|
}
|
|
|
|
macs := strings.Split(string(content), "\n")
|
|
var newMacs []string
|
|
|
|
for _, mac := range macs {
|
|
parts := strings.Split(mac, " ")
|
|
if req.Mac != parts[0] {
|
|
newMacs = append(newMacs, mac)
|
|
}
|
|
}
|
|
|
|
data := strings.Join(newMacs, "\n")
|
|
err = os.WriteFile(WolMacFile, []byte(data), 0o644)
|
|
if err != nil {
|
|
log.Errorf("failed to write %s: %s", WolMacFile, err)
|
|
rsp.ErrRsp(c, -3, "write failed")
|
|
return
|
|
}
|
|
|
|
rsp.OkRsp(c)
|
|
log.Debugf("delete wol mac: %s", req.Mac)
|
|
}
|
|
|
|
func parseMAC(mac string) (string, error) {
|
|
mac = strings.ToUpper(strings.TrimSpace(mac))
|
|
|
|
mac = strings.ReplaceAll(mac, "-", "")
|
|
mac = strings.ReplaceAll(mac, ":", "")
|
|
mac = strings.ReplaceAll(mac, ".", "")
|
|
|
|
matched, err := regexp.MatchString("^[0-9A-F]{12}$", mac)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if !matched {
|
|
return "", fmt.Errorf("invalid MAC address: %s", mac)
|
|
}
|
|
|
|
var result strings.Builder
|
|
for i := 0; i < 12; i += 2 {
|
|
if i > 0 {
|
|
result.WriteString(":")
|
|
}
|
|
result.WriteString(mac[i : i+2])
|
|
}
|
|
|
|
return result.String(), nil
|
|
}
|
|
|
|
func saveMac(mac string) {
|
|
if isMacExist(mac) {
|
|
return
|
|
}
|
|
|
|
err := os.MkdirAll(filepath.Dir(WolMacFile), 0o644)
|
|
if err != nil {
|
|
log.Errorf("failed to create dir: %s", err)
|
|
return
|
|
}
|
|
|
|
file, err := os.OpenFile(WolMacFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
|
if err != nil {
|
|
log.Errorf("failed to open %s: %s", WolMacFile, err)
|
|
return
|
|
}
|
|
defer func() {
|
|
_ = file.Close()
|
|
}()
|
|
|
|
content := fmt.Sprintf("%s\n", mac)
|
|
_, err = file.WriteString(content)
|
|
if err != nil {
|
|
log.Errorf("failed to write %s: %s", WolMacFile, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func isMacExist(mac string) bool {
|
|
content, err := os.ReadFile(WolMacFile)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
macs := strings.Split(string(content), "\n")
|
|
for _, item := range macs {
|
|
parts := strings.Split(item, " ")
|
|
if mac == parts[0] {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|