-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoperator.go
148 lines (135 loc) · 4.46 KB
/
operator.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// operator.go
// Package main handles operator-related commands and functions, including operator commands such as KICK, BAN, UNBAN, and LISTBANS.
package main
import (
"fmt"
"net"
"os"
"sync"
"github.com/drewwalton19216801/tailutils"
)
var (
operatorID string // operatorID stores the client ID of the operator.
operatorMutex = sync.RWMutex{} // operatorMutex synchronizes access to the operatorID variable.
)
// isOperator returns true if the provided client ID is the operator's ID.
func isOperator(clientID string) bool {
operatorMutex.RLock()
defer operatorMutex.RUnlock()
return clientID == operatorID
}
// handleOperatorCommand processes operator commands issued by the operator client.
// Supported commands include:
// - SERVERINFO: Retrieves information about the server, including the Tailscale IP address.
// - KICK <clientID>: Disconnects the specified client from the server.
// - BAN <clientID>: Bans the specified client and disconnects them if connected.
// - UNBAN <clientID>: Removes a client from the banned list.
// - LISTBANS: Lists all currently banned clients.
// The function checks if the sender is the operator before executing the command.
func handleOperatorCommand(command, senderID string, args []string, conn net.Conn) {
if !isOperator(senderID) {
conn.Write([]byte("ERROR Not authorized as operator\n"))
return
}
switch command {
case "SERVERINFO":
// Provide server information
tailscaleIP4, ip4err := tailutils.GetTailscaleIP()
tailscaleIP6, ip6err := tailutils.GetTailscaleIP6()
tailscaleIP := ""
if ip4err == nil && ip6err == nil {
tailscaleIP = fmt.Sprintf("%s, %s", tailscaleIP4, tailscaleIP6)
} else if ip4err == nil {
tailscaleIP = tailscaleIP4
} else if ip6err == nil {
tailscaleIP = tailscaleIP6
}
// Get the server's hostname
hostname, err := os.Hostname()
if err != nil {
hostname = "Unknown"
}
conn.Write([]byte(fmt.Sprintf("SERVERINFO Server: %s\n", hostname)))
if ip4err != nil && ip6err != nil {
// This should never happen, but we check just in case
conn.Write([]byte("SERVERINFO No Tailscale IP\n"))
} else {
conn.Write([]byte(fmt.Sprintf("SERVERINFO Tailscale IP(s): %s\n", tailscaleIP)))
}
case "KICK":
if len(args) != 1 {
conn.Write([]byte("ERROR Usage: KICK <clientID>\n"))
return
}
targetID := args[0]
// Don't allow kicking the operator
if targetID == operatorID {
conn.Write([]byte("ERROR Cannot kick the operator\n"))
return
}
// Lock the clients map to safely access and modify it
clientMutex.Lock()
if client, exists := clients[targetID]; exists {
client.Conn.Write([]byte("KICKED You have been kicked by the operator\n"))
client.Conn.Close()
delete(clients, targetID)
conn.Write([]byte(fmt.Sprintf("SUCCESS Kicked client %s\n", targetID)))
} else {
conn.Write([]byte(fmt.Sprintf("ERROR Client %s not found\n", targetID)))
}
clientMutex.Unlock()
case "BAN":
if len(args) != 1 {
conn.Write([]byte("ERROR Usage: BAN <clientID>\n"))
return
}
targetID := args[0]
if targetID == operatorID {
conn.Write([]byte("ERROR Cannot ban the operator\n"))
return
}
// Add client to the banned list
banMutex.Lock()
bannedClients[targetID] = true
banMutex.Unlock()
// Disconnect the client if connected
clientMutex.Lock()
if client, exists := clients[targetID]; exists {
client.Conn.Write([]byte("BANNED You have been banned by the operator\n"))
client.Conn.Close()
delete(clients, targetID)
}
clientMutex.Unlock()
conn.Write([]byte(fmt.Sprintf("SUCCESS Banned client %s\n", targetID)))
case "UNBAN":
if len(args) != 1 {
conn.Write([]byte("ERROR Usage: UNBAN <clientID>\n"))
return
}
targetID := args[0]
// Remove client from the banned list
banMutex.Lock()
if _, exists := bannedClients[targetID]; exists {
delete(bannedClients, targetID)
conn.Write([]byte(fmt.Sprintf("SUCCESS Unbanned client %s\n", targetID)))
} else {
conn.Write([]byte(fmt.Sprintf("ERROR Client %s not found in banned list\n", targetID)))
}
banMutex.Unlock()
case "LISTBANS":
// List all banned clients
conn.Write([]byte("BEGIN_RESPONSE\n"))
banMutex.RLock()
if len(bannedClients) == 0 {
conn.Write([]byte("No clients are currently banned\n"))
} else {
for clientID := range bannedClients {
conn.Write([]byte(fmt.Sprintf("BANNED %s\n", clientID)))
}
}
banMutex.RUnlock()
conn.Write([]byte("END_RESPONSE\n"))
default:
conn.Write([]byte("ERROR Unknown operator command\n"))
}
}