Skip to content

Commit

Permalink
feat: refactor, add magicpacket validation and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jedrw committed Feb 6, 2025
1 parent 6007849 commit d4672c4
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 106 deletions.
45 changes: 34 additions & 11 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
version: 2.1

jobs:
test:
docker:
- image: cimg/go:1.22
steps:
- checkout
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- go-mod-v1
- run:
name: Install Dependencies
command: go get ./...
- save_cache:
key: go-mod-v1-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
- run:
name: Run tests
command: go test ./...
build:
docker:
docker:
- image: cimg/go:1.22
steps:
- run:
Expand All @@ -20,27 +39,27 @@ jobs:
key: go-mod-v1-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
- run:
- run:
name: Build
command: go build -C cmd/gowake/ -v -ldflags="-w -s"
- run:
name: Upx
command: upx ./cmd/gowake/gowake
- persist_to_workspace:
root: ~/project
paths:
- cmd/gowake/gowake
paths:
- cmd/gowake/gowake
release:
docker:
- image: cimg/base:current
docker:
- image: cimg/base:current
steps:
- attach_workspace:
at: ./
- run:
- run:
name: Package
command: tar cvfz ${CIRCLE_PROJECT_REPONAME}_${CIRCLE_TAG}_linux_amd64.tar.gz cmd/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_PROJECT_REPONAME}
- run:
name: Release
name: Release
command: |
curl -v \
-X POST \
Expand All @@ -56,7 +75,7 @@ jobs:
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/jedrw/${CIRCLE_PROJECT_REPONAME}/releases/tags/${CIRCLE_TAG} \
| jq '.id')
curl -v \
-X POST \
-H "Accept: application/vnd.github+json" \
Expand All @@ -67,8 +86,12 @@ jobs:
--data-binary @${CIRCLE_PROJECT_REPONAME}_${CIRCLE_TAG}_linux_amd64.tar.gz
workflows:
build_and_release:
test_build_and_release:
jobs:
- test:
filters:
tags:
only: /v\d+\.\d+\.\d+/
- build:
filters:
tags:
Expand All @@ -77,10 +100,10 @@ workflows:
context:
- github
requires:
- test
- build
filters:
branches:
ignore: /.*/
tags:
only: /v\d+\.\d+\.\d+/

53 changes: 21 additions & 32 deletions cmd/gowake/gowake.go
Original file line number Diff line number Diff line change
@@ -1,59 +1,48 @@
package main

import (
"errors"
"fmt"
"regexp"
"net"

"github.com/jedrw/gowake/cmd/listen"
"github.com/jedrw/gowake/cmd/gowake/listen"
"github.com/jedrw/gowake/pkg/magicpacket"
"github.com/spf13/cobra"
)

var gowakeCmd = &cobra.Command{
Use: "gowake [macaddress]",
Short: "Send a magic packet in order wake a compliant machine",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
// Get port
port, _ := cmd.Flags().GetInt("port")
var port int
var ip string

// Get IP
var gowakeCmd = &cobra.Command{
Use: "gowake [macaddress]",
Short: "Send a magic packet",
Args: cobra.ExactArgs(1),
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
ip, _ := cmd.Flags().GetString("ip")

is_ip, _ := regexp.MatchString(`^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$`, ip)
if !is_ip {
fmt.Println("Please provide a valid IP address")
return
if net.ParseIP(ip) == nil {
return errors.New("got invalid IP")
}

// Check for mac address
if len(args) < 1 {
fmt.Println("Please provide a MAC address")
return
}

// Build packet
mp, err := magicpacket.New(args[0])
port, _ := cmd.Flags().GetInt("port")
magicPacket, err := magicpacket.New(args[0])
if err != nil {
fmt.Println(err.Error())
return
return err
}

// Send packet
err = magicpacket.Send(mp, ip, port)
err = magicpacket.Send(magicPacket, ip, port)
if err != nil {
fmt.Println(err.Error())
return err
}

fmt.Printf("Sent magic packet to %v\n", args[0])
fmt.Printf("Sent magic packet %s to %s:%d\n", args[0], ip, port)
return nil
},
}

func init() {
var port int
var ip string
gowakeCmd.AddCommand(listen.ListenCmd)
gowakeCmd.PersistentFlags().IntVarP(&port, "port", "p", 9, "Port to send or listen for magic packet")
gowakeCmd.Flags().IntVarP(&port, "port", "p", 9, "Port to send magic packet to")
gowakeCmd.Flags().StringVarP(&ip, "ip", "i", "255.255.255.255", "Destination (IP or broadcast address) for the magic packet")
gowakeCmd.PersistentFlags().BoolP("help", "h", false, "Print help for command")
cobra.EnableCommandSorting = false
Expand Down
51 changes: 51 additions & 0 deletions cmd/gowake/listen/listen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package listen

import (
"errors"
"fmt"
"syscall"

"github.com/jedrw/gowake/pkg/magicpacket"
"github.com/spf13/cobra"
)

var port int
var ip string

var ListenCmd = &cobra.Command{
Use: "listen",
Short: "Listen for a magic packet",
RunE: func(cmd *cobra.Command, args []string) error {
ip, _ := cmd.Flags().GetString("ip")
port, _ := cmd.Flags().GetInt("port")
cont, _ := cmd.Flags().GetBool("continuous")
fmt.Printf("Listening for magic packets on %s:%d\n", ip, port)
for {
remote, mac, err := magicpacket.Listen(ip, port)
if err != nil {
var errno syscall.Errno
if errors.As(err, &errno) {
if errno == syscall.EACCES {
return fmt.Errorf("%w: please run as elevated user", err)
}
} else {
return err
}
}

fmt.Printf("%s from %s\n", mac, remote.String())
if !cont {
break
}
}

return nil
},
}

func init() {
var continuous bool
ListenCmd.Flags().IntVarP(&port, "port", "p", 9, "Port to listen for magic packets on")
ListenCmd.Flags().StringVarP(&ip, "ip", "i", "0.0.0.0", "Address to listen for magic packets on")
ListenCmd.Flags().BoolVarP(&continuous, "continuous", "c", false, "Listen continuously for magic packets")
}
39 changes: 0 additions & 39 deletions cmd/listen/listen.go

This file was deleted.

26 changes: 10 additions & 16 deletions pkg/magicpacket/listen.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package magicpacket

import (
"bytes"
"fmt"
"net"
)

func Listen(port int) (*net.UDPAddr, string, error) {
func Listen(ip string, port int) (*net.UDPAddr, string, error) {
listenIP := net.ParseIP(ip)
if listenIP == nil {
return nil, "", fmt.Errorf("invalid IP: %s", ip)
}

addr := net.UDPAddr{
IP: net.ParseIP("0.0.0.0"),
IP: listenIP,
Port: port,
}

Expand All @@ -18,21 +22,11 @@ func Listen(port int) (*net.UDPAddr, string, error) {
}
defer listener.Close()

var magicPacket MagicPacket
remote := &net.UDPAddr{}
_, remote, err = listener.ReadFromUDP(magicPacket[:])
magicPacket := MagicPacket{}
_, remote, err := listener.ReadFromUDP(magicPacket[:])
if err != nil {
return remote, "", err
}

macLength := 6
offset := 6
for i := 0; i < 16; i++ {
if !bytes.Equal(magicPacket[offset:offset+macLength], magicPacket[96:]) {
return remote, "", fmt.Errorf("received malformed magicpacket from %v", remote)
}
offset += 6
}

return remote, net.HardwareAddr.String(magicPacket[96:]), err
return remote, magicPacket.Mac(), magicPacket.Validate()
}
41 changes: 36 additions & 5 deletions pkg/magicpacket/magicpacket.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,62 @@
package magicpacket

import (
"bytes"
"errors"
"fmt"
"net"
)

var (
ErrNotValidEUI48MacAddress = errors.New("not a valid EUI-48 MAC address")
ErrMalformedMagicPacket = errors.New("malformed magic packet")
)

type MagicPacket [102]byte

func New(mac string) (MagicPacket, error) {
// Parse mac address
hwAddr, err := net.ParseMAC(mac)
if err != nil {
return MagicPacket{}, err
}

if len(hwAddr) != 6 {
return MagicPacket{}, fmt.Errorf("invalid EUI-48 MAC address")
return MagicPacket{}, fmt.Errorf("%w, %s", ErrNotValidEUI48MacAddress, hwAddr)
}

// Build magicpacket
magicPacket := MagicPacket{255, 255, 255, 255, 255, 255}

offset := 6
for i := 0; i < 16; i++ {
copy(magicPacket[offset:], hwAddr[:])
offset += 6
}

return magicPacket, err
return magicPacket, nil
}

func (mp MagicPacket) Bytes() []byte {
return mp[:]
}

func (mp MagicPacket) Mac() string {
return net.HardwareAddr.String(mp[96:])
}

func (mp MagicPacket) Validate() error {
macLength := 6
offset := 6
for i := 0; i < 16; i++ {
if !bytes.Equal(mp[offset:offset+macLength], mp[96:]) {
return ErrMalformedMagicPacket
}

offset += 6
}

_, err := net.ParseMAC(mp.Mac())
if err != nil {
return err
}

return nil
}
Loading

0 comments on commit d4672c4

Please sign in to comment.