-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
113 lines (98 loc) · 2.61 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package main
import (
"fmt"
"github.com/op/go-logging"
"net"
"net/http"
"os"
"os/exec"
"os/user"
"time"
)
// Keyword sent to trigger panic.
const Keyword string = "Panic!"
// HTTPPort to listen on.
const HTTPPort int = 9999
// UDPPort to listen on.
const UDPPort int = 9998
// BufferSize for UDP buffer.
const BufferSize int = 64000
// Instantiate the logger.
var log = logging.MustGetLogger("gopanic")
// Generic error handle.
func errorCheck(err error) {
if err != nil {
panic(err)
}
}
// Called when there is an HTTP request to the server, all
// we need to do is propagate the panic and then run the
// panic.
func handleHTTP(w http.ResponseWriter, r *http.Request) {
propagatePanic()
doPanic()
}
// Listen for UDP packets on the broadcast address, if
// this matches Keyword, then run the panic.
func handleUDP() {
conn, err := net.ListenUDP("udp4", &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: UDPPort,
})
errorCheck(err)
defer conn.Close()
var buff = make([]byte, BufferSize)
n, addr, err := conn.ReadFromUDP(buff)
errorCheck(err)
if string(buff[0:n]) == Keyword {
log.Info("Accepting panic from %s", addr)
doPanic()
}
}
// Propagate the panic to the broadcast address, so that
// all hosts on this network can see.
func propagatePanic() {
log.Info("Propagating panic to broadcast")
conn, err := net.DialUDP("udp4", nil, &net.UDPAddr{
IP: net.IPv4(255, 255, 255, 255),
Port: UDPPort,
})
errorCheck(err)
defer conn.Close()
_, err = conn.Write([]byte(Keyword))
errorCheck(err)
}
// Template for what to do in the case of a panic.
// By default, we'll try to halt the system.
func doPanic() {
proc := exec.Command("shutdown", "-H", "now")
proc.Start()
}
// Setup the formatter and level of the logger.
func setupLogger() {
format := logging.MustStringFormatter(
"(%{time:2006/01/02 15:04:05.999 -07:00}) %{color}[%{level}]%{color:reset}: %{message}",
)
backend := logging.NewLogBackend(os.Stderr, "", 0)
backendFormatter := logging.NewBackendFormatter(backend, format)
backendLeveled := logging.AddModuleLevel(backend)
backendLeveled.SetLevel(logging.ERROR, "")
logging.SetBackend(backendLeveled, backendFormatter)
}
// Entry point. Start the HTTP server and start
// listening for UDP.
func main() {
setupLogger()
log.Info("Starting gopanic daemon")
currentUser, err := user.Current()
errorCheck(err)
if currentUser.Uid != "0" {
log.Warning("Not running as root user (%s), this means no halt on panic.", currentUser.Username)
}
http.HandleFunc("/", handleHTTP)
go http.ListenAndServe(fmt.Sprintf(":%d", HTTPPort), nil)
for {
time.Sleep(100 * time.Millisecond)
handleUDP()
}
}