-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add network tools commands for NAS and Wake-on-LAN
- Introduce a new command `nas` for network-attached storage tools. - Implement a new `wol` command which allows the sending of Wake-on-LAN packets. - Add a new `wol` package to handle the construction and sending of magic packets. - Modify the root command to include the newly created `nas` command. - Ensure error handling is implemented for MAC address input in the `wol` command. - Include licensing information in the newly created files. Signed-off-by: ysicing <i@ysicing.me>
- Loading branch information
Showing
4 changed files
with
174 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright (c) 2024 ysicing(ysicing.me, ysicing@12306.work) All rights reserved. | ||
// Use of this source code is covered by the following dual licenses: | ||
// (1) Y PUBLIC LICENSE 1.0 (YPL 1.0) | ||
// (2) Affero General Public License 3.0 (AGPL 3.0) | ||
// License that can be found in the LICENSE file. | ||
|
||
package cmd | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
"github.com/ysicing/tiga/cmd/nas" | ||
"github.com/ysicing/tiga/pkg/factory" | ||
) | ||
|
||
func newCmdNas(f factory.Factory) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "nas", | ||
Short: "nas tools", | ||
Args: cobra.NoArgs, | ||
} | ||
cmd.AddCommand(nas.WolCmd(f)) | ||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright (c) 2024 ysicing(ysicing.me, ysicing@12306.work) All rights reserved. | ||
// Use of this source code is covered by the following dual licenses: | ||
// (1) Y PUBLIC LICENSE 1.0 (YPL 1.0) | ||
// (2) Affero General Public License 3.0 (AGPL 3.0) | ||
// License that can be found in the LICENSE file. | ||
|
||
package nas | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/ysicing/tiga/internal/pkg/wol" | ||
"github.com/ysicing/tiga/pkg/factory" | ||
) | ||
|
||
func WolCmd(f factory.Factory) *cobra.Command { | ||
var mac string | ||
cmd := &cobra.Command{ | ||
Use: "wol", | ||
Short: "wol tools", | ||
RunE: func(_ *cobra.Command, _ []string) error { | ||
if mac == "" { | ||
return fmt.Errorf("mac address is required") | ||
} | ||
if err := wol.Wake(mac); err != nil { | ||
f.GetLog().Warnf("wol %s failed: %v", mac, err) | ||
return nil | ||
} | ||
f.GetLog().Donef("wol %s success", mac) | ||
return nil | ||
}, | ||
} | ||
cmd.Flags().StringVarP(&mac, "mac", "m", "", "mac address") | ||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// Copyright (c) 2024 ysicing(ysicing.me, ysicing@12306.work) All rights reserved. | ||
// Use of this source code is covered by the following dual licenses: | ||
// (1) Y PUBLIC LICENSE 1.0 (YPL 1.0) | ||
// (2) Affero General Public License 3.0 (AGPL 3.0) | ||
// License that can be found in the LICENSE file. | ||
|
||
package wol | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"fmt" | ||
"net" | ||
"regexp" | ||
) | ||
|
||
// think from https://github.com/xiaoxinpro/WolGoWeb | ||
|
||
var ( | ||
delims = ":-" | ||
reMAC = regexp.MustCompile(`^([0-9a-fA-F]{2}[` + delims + `]){5}([0-9a-fA-F]{2})$`) | ||
) | ||
|
||
// MACAddress represents a 6 byte network mac address. | ||
type MACAddress [6]byte | ||
|
||
// A MagicPacket is constituted of 6 bytes of 0xFF followed by 16-groups of the | ||
// destination MAC address. | ||
type MagicPacket struct { | ||
header [6]byte | ||
payload [16]MACAddress | ||
} | ||
|
||
// New 返回一个基于mac地址字符串的魔法包。 | ||
func New(mac string) (*MagicPacket, error) { | ||
var packet MagicPacket | ||
var macAddr MACAddress | ||
|
||
hwAddr, err := net.ParseMAC(mac) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// We only support 6 byte MAC addresses since it is much harder to use the | ||
// binary.Write(...) interface when the size of the MagicPacket is dynamic. | ||
if !reMAC.MatchString(mac) { | ||
return nil, fmt.Errorf("%s is not a IEEE 802 MAC-48 address", mac) | ||
} | ||
|
||
// Copy bytes from the returned HardwareAddr -> a fixed size MACAddress. | ||
for idx := range macAddr { | ||
macAddr[idx] = hwAddr[idx] | ||
} | ||
|
||
// Setup the header which is 6 repetitions of 0xFF. | ||
for idx := range packet.header { | ||
packet.header[idx] = 0xFF | ||
} | ||
|
||
// Setup the payload which is 16 repetitions of the MAC addr. | ||
for idx := range packet.payload { | ||
packet.payload[idx] = macAddr | ||
} | ||
|
||
return &packet, nil | ||
} | ||
|
||
// Marshal 将魔术包结构序列化为一个102字节数组。 | ||
func (mp *MagicPacket) Marshal() ([]byte, error) { | ||
var buf bytes.Buffer | ||
if err := binary.Write(&buf, binary.BigEndian, mp); err != nil { | ||
return nil, err | ||
} | ||
|
||
return buf.Bytes(), nil | ||
} | ||
|
||
// wake 执行唤醒指令 | ||
func Wake(macAddr string) error { | ||
udpAddr, err := net.ResolveUDPAddr("udp", "255.255.255.255:9") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// 获取魔术包 | ||
mp, err := New(macAddr) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// 魔术包转字节流 | ||
bs, err := mp.Marshal() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var localAddr *net.UDPAddr | ||
// 创建UDP链接 | ||
conn, err := net.DialUDP("udp", localAddr, udpAddr) | ||
if err != nil { | ||
return err | ||
} | ||
defer conn.Close() | ||
|
||
// 开始发送UDP数据 | ||
n, err := conn.Write(bs) | ||
if err == nil && n != 102 { | ||
err = fmt.Errorf("sent magic packet %d bytes (should send magic packet 102 bytes)", n) | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} |