Skip to content

Instantly share code, notes, and snippets.

@maple3142
Created September 26, 2024 14:35
Show Gist options
  • Save maple3142/03668d75c5c319244b474e881c16835a to your computer and use it in GitHub Desktop.
Save maple3142/03668d75c5c319244b474e881c16835a to your computer and use it in GitHub Desktop.
wake on lan go
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"log"
"math/big"
"net"
"net/http"
"os"
"strconv"
"time"
)
const (
defaultTargetMAC = "11:22:33:44:55:66"
defaultListenPort = 12345
)
var targetMAC net.HardwareAddr
var listenPort int
func generateSelfSignedCert() (tls.Certificate, error) {
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return tls.Certificate{}, err
}
notBefore := time.Now()
notAfter := notBefore.Add(365 * 24 * time.Hour)
serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
if err != nil {
return tls.Certificate{}, err
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"maple3142"},
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageContentCommitment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
template.DNSNames = []string{"localhost"}
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
return tls.Certificate{}, err
}
privBytes, err := x509.MarshalECPrivateKey(priv)
if err != nil {
return tls.Certificate{}, err
}
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: privBytes})
return tls.X509KeyPair(certPEM, keyPEM)
}
func wol(mac net.HardwareAddr) {
magicPacket := make([]byte, 6+16*len(mac))
for i := 0; i < 6; i++ {
magicPacket[i] = 0xFF
}
for i := 0; i < 16; i++ {
copy(magicPacket[6+i*len(mac):], mac)
}
conn, err := net.Dial("udp", "255.255.255.255:9")
if err != nil {
log.Println("Failed to send magic packet:", err)
return
}
defer conn.Close()
conn.Write(magicPacket)
log.Println("Magic packet sent")
}
func handleWOL(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/wol" {
if r.Method == http.MethodPost {
wol(targetMAC)
fmt.Fprintln(w, "Magic packet sent")
} else {
w.Header().Set("Content-Type", "text/html")
fmt.Fprintln(w, `<form method="post"><button>Wake up</button></form>`)
}
} else {
http.NotFound(w, r)
}
}
func main() {
// read mac address and port from environment variables
var err error
targetMACStr := os.Getenv("TARGET_MAC")
if targetMACStr != "" {
targetMAC, err = net.ParseMAC(targetMACStr)
if err != nil {
log.Printf("Invalid MAC address: %v", err)
return
}
} else {
targetMAC, err = net.ParseMAC(defaultTargetMAC)
if err != nil {
panic(err)
}
}
listenPortStr := os.Getenv("PORT")
listenPort, err := strconv.Atoi(listenPortStr)
if err != nil {
listenPort = defaultListenPort
}
log.Printf("TARGET_MAC: %s, LISTEN_PORT: %d", targetMAC, listenPort)
log.Println("Target and port can be set by environment variables TARGET_MAC and PORT")
cert, err := generateSelfSignedCert()
if err != nil {
log.Fatalf("Failed to generate certificate: %v", err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12,
}
server := &http.Server{
Addr: fmt.Sprintf(":%d", listenPort),
TLSConfig: tlsConfig,
Handler: http.HandlerFunc(handleWOL),
}
log.Printf("Starting server on port %d", listenPort)
log.Fatal(server.ListenAndServeTLS("", ""))
}
// GOARCH=arm go build -ldflags "-s -w" ./wol_go.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment