Skip to content

Commit

Permalink
feat: Ipv6 support
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmetozer committed Feb 20, 2022
1 parent e0260e7 commit 9fb30db
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 9 deletions.
12 changes: 12 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ Example request body
"if": "lo",
"addr": "255.255.255.255",
"port": "7"
},
{
"mac": "00:15:5d:f5:bd:67",
"if": "eth0",
"addr": "fe80::900d:cafe:900d:c0de",
"port": "7"
},
{
"mac": "00:15:5d:f5:bd:67",
"if": "eth0",
"addr": "2001:db8:900d:cafe:900d:c0de:900d:11fe",
"port": "7"
}
]

Expand Down
84 changes: 77 additions & 7 deletions share/sendMagicPacket.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package share

import (
"errors"
"fmt"
"net"
"strings"
)

type MagicPacket struct {
Expand All @@ -15,10 +17,11 @@ type MagicPacket struct {
const magicPacketSize = 102

// SendMagicPacket
// Send magic packet to destination to wake up the remote
// Send magic packet to remote to wake up the remote
func (mp *MagicPacket) SendMagicPacket() error {

if len(mp.HWAddr) != 6 {

return fmt.Errorf("invalid mac '%v'", mp.HWAddr)
}

Expand All @@ -33,30 +36,97 @@ func (mp *MagicPacket) SendMagicPacket() error {

iface, err := net.InterfaceByName(mp.Device)
if err != nil {

return fmt.Errorf("interface by name: %w", err)
}

addrs, err := iface.Addrs()
if err != nil {

return fmt.Errorf("interface addrs: %w", err)
}

dialer := &net.Dialer{
LocalAddr: &net.UDPAddr{
IP: addrs[0].(*net.IPNet).IP,
Port: 0,
},
// To determine remote Address Is IPv6
remoteIsIPv6 := strings.Contains(mp.IPAddr, ":")
remote := mp.IPAddr
sourceIP := net.IP{}

// If remote address is IPv6, find same net type IP address
if remoteIsIPv6 {
sourceIP, err = findIP6SourceAddress(&addrs, mp.IPAddr)

// no ip v6 addr is found
if err != nil {

return fmt.Errorf("find IP6 source address: interface %v: %w", mp.Device, err)
}
if sourceIP.IsLinkLocalUnicast() {
remote = fmt.Sprintf("[%v%%%v]", remote, mp.Device)
} else {
remote = fmt.Sprintf("[%v]", remote)
}

} else {
IPv4Found := false
for i := range addrs {
if IP := addrs[i].(*net.IPNet).IP; strings.Contains(IP.String(), ".") {
IPv4Found = true
sourceIP = IP
break
}
}
if !IPv4Found {

return fmt.Errorf("interface '%v' does not have a IPv4 addr", mp.Device)
}
}

sourceAddr := &net.UDPAddr{
IP: sourceIP,
Port: 0, // Port zero is auto select for golang
Zone: mp.Device,
}

remoteAddr, err := net.ResolveUDPAddr("udp", remote+":"+mp.Port)
if err != nil {

return fmt.Errorf("remote resolve error: %w", err)
}
conn, err := dialer.Dial("udp", mp.IPAddr+":"+mp.Port)

conn, err := net.DialUDP("udp", sourceAddr, remoteAddr)

if err != nil {

return fmt.Errorf("dial: %w", err)
}
defer conn.Close()

_, err = conn.Write(packet[:])
if err != nil {

return fmt.Errorf("write: %w", err)
}

return nil
}

func findIP6SourceAddress(addrs *[]net.Addr, remoteAddress string) (net.IP, error) {

dstIP := net.ParseIP(remoteAddress)
// Try to find same net type IP
if dstIP.IsLinkLocalUnicast() { // if it is link local
for i := range *addrs {
if IP := (*addrs)[i].(*net.IPNet).IP; IP.IsLinkLocalUnicast() && strings.Contains(IP.String(), ":") {
return IP, nil
}
}
return net.IP{}, errors.New("no link local unicast IPv6 address is found")

}
for i := range *addrs {
if IP := (*addrs)[i].(*net.IPNet).IP; IP.IsGlobalUnicast() && strings.Contains(IP.String(), ":") {
return IP, nil
}
}
return net.IP{}, errors.New("no global IPv6 address is found")
}
3 changes: 1 addition & 2 deletions web/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ <h1>Wake On Lan</h1>

<div class="input-group">
<label for="ipaddr">IPAddr:</label>
<input type="text" id="IPAddr" name="ipaddr" value="255.255.255.255"
pattern="^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.){3}(25[0-5]|(2[0-4]|1\d|[1-9]|)\d)$" required>
<input type="text" id="IPAddr" name="ipaddr" value="255.255.255.255" required>
<label for="port">Port:</label>
<input type="number" min="0" max="65535" id="Port" name="port" value="7">
</div>
Expand Down

0 comments on commit 9fb30db

Please sign in to comment.