diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..3c4f05a
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,49 @@
+name: Run tests
+
+on:
+ push:
+ branches:
+ - "*"
+ pull_request:
+ branches:
+ - "*"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ name: Run tests
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: actions/setup-go@v3
+ with:
+ go-version: '1.18.3'
+
+ - name: Ensure linux agent compiles
+ run: |
+ ARCHS='amd64 386 arm64 arm'
+ for i in ${ARCHS}; do
+ env CGO_ENABLED=0 GOOS=linux GOARCH=${i} go build -ldflags "-s -w"
+ done
+
+ - name: Ensure windows agent compiles
+ run: |
+ ARCHS='amd64 386'
+ for i in ${ARCHS}; do
+ env CGO_ENABLED=0 GOOS=windows GOARCH=${i} go build -ldflags "-s -w"
+ done
+
+ - name: Ensure mac agent compiles
+ run: |
+ ARCHS='amd64 arm64'
+ for i in ${ARCHS}; do
+ env CGO_ENABLED=0 GOOS=darwin GOARCH=${i} go build -ldflags "-s -w"
+ done
+
+ - name: Ensure freebsd agent compiles
+ run: |
+ ARCHS='amd64 386 arm64 arm'
+ for i in ${ARCHS}; do
+ env CGO_ENABLED=0 GOOS=freebsd GOARCH=${i} go build -ldflags "-s -w"
+ done
diff --git a/agent/agent.go b/agent/agent.go
index 567d56a..2e465e0 100644
--- a/agent/agent.go
+++ b/agent/agent.go
@@ -66,6 +66,9 @@ type Agent struct {
Platform string
GoArch string
ServiceConfig *service.Config
+ NatsServer string
+ NatsProxyPath string
+ NatsProxyPort string
}
const (
@@ -139,9 +142,25 @@ func New(logger *logrus.Logger, version string) *Agent {
},
}
+ var natsProxyPath, natsProxyPort string
+ if ac.NatsProxyPath == "" {
+ natsProxyPath = "natsws"
+ }
+
+ if ac.NatsProxyPort == "" {
+ natsProxyPort = "443"
+ }
+
+ // check if using nats standard tcp, otherwise use nats websockets by default
+ var natsServer string
+ if ac.NatsStandardPort != "" {
+ natsServer = fmt.Sprintf("tls://%s:%s", ac.APIURL, ac.NatsStandardPort)
+ } else {
+ natsServer = fmt.Sprintf("wss://%s:%s", ac.APIURL, natsProxyPort)
+ }
+
return &Agent{
Hostname: info.Hostname,
- Arch: info.Architecture,
BaseURL: ac.BaseURL,
AgentID: ac.AgentID,
ApiURL: ac.APIURL,
@@ -164,6 +183,9 @@ func New(logger *logrus.Logger, version string) *Agent {
Platform: runtime.GOOS,
GoArch: runtime.GOARCH,
ServiceConfig: svcConf,
+ NatsServer: natsServer,
+ NatsProxyPath: natsProxyPath,
+ NatsProxyPort: natsProxyPort,
}
}
@@ -360,6 +382,7 @@ func (a *Agent) setupNatsOptions() []nats.Option {
opts = append(opts, nats.RetryOnFailedConnect(true))
opts = append(opts, nats.MaxReconnects(-1))
opts = append(opts, nats.ReconnectBufSize(-1))
+ opts = append(opts, nats.ProxyPath(a.NatsProxyPath))
return opts
}
@@ -385,6 +408,7 @@ func (a *Agent) CleanupAgentUpdates() {
return
}
+ // winagent-v* is deprecated
files, err := filepath.Glob("winagent-v*.exe")
if err == nil {
for _, f := range files {
@@ -392,6 +416,13 @@ func (a *Agent) CleanupAgentUpdates() {
}
}
+ agents, err := filepath.Glob("tacticalagent-v*.exe")
+ if err == nil {
+ for _, f := range agents {
+ os.Remove(f)
+ }
+ }
+
cderr = os.Chdir(os.Getenv("TMP"))
if cderr != nil {
a.Logger.Errorln(cderr)
diff --git a/agent/agent_linux.go b/agent/agent_unix.go
similarity index 89%
rename from agent/agent_linux.go
rename to agent/agent_unix.go
index 1027344..037b112 100644
--- a/agent/agent_linux.go
+++ b/agent/agent_unix.go
@@ -1,3 +1,6 @@
+//go:build !windows
+// +build !windows
+
/*
Copyright 2022 AmidaWare LLC.
@@ -15,6 +18,7 @@ import (
"bufio"
"fmt"
"os"
+ "path/filepath"
"runtime"
"strconv"
"strings"
@@ -142,15 +146,18 @@ func NewAgentConfig() *rmm.AgentConfig {
pk, _ := strconv.Atoi(agentpk)
ret := &rmm.AgentConfig{
- BaseURL: viper.GetString("baseurl"),
- AgentID: viper.GetString("agentid"),
- APIURL: viper.GetString("apiurl"),
- Token: viper.GetString("token"),
- AgentPK: agentpk,
- PK: pk,
- Cert: viper.GetString("cert"),
- Proxy: viper.GetString("proxy"),
- CustomMeshDir: viper.GetString("meshdir"),
+ BaseURL: viper.GetString("baseurl"),
+ AgentID: viper.GetString("agentid"),
+ APIURL: viper.GetString("apiurl"),
+ Token: viper.GetString("token"),
+ AgentPK: agentpk,
+ PK: pk,
+ Cert: viper.GetString("cert"),
+ Proxy: viper.GetString("proxy"),
+ CustomMeshDir: viper.GetString("meshdir"),
+ NatsProxyPath: viper.GetString("natsproxypath"),
+ NatsProxyPort: viper.GetString("natsproxyport"),
+ NatsStandardPort: viper.GetString("natsstandardport"),
}
return ret
}
@@ -244,8 +251,29 @@ func (a *Agent) AgentUpdate(url, inno, version string) {
os.Chmod(f.Name(), 0755)
err = os.Rename(f.Name(), self)
if err != nil {
- a.Logger.Errorln("AgentUpdate() os.Rename():", err)
- return
+ a.Logger.Debugln("Detected /tmp on different filesystem")
+ // rename does not work when src and dest are on different filesystems
+ // so we need to manually copy it to the same fs then rename it
+ cwd, err := os.Getwd()
+ if err != nil {
+ a.Logger.Errorln("AgentUpdate() os.Getwd():", err)
+ return
+ }
+ // create a tmpfile in same fs as agent
+ tmpfile := filepath.Join(cwd, GenerateAgentID())
+ defer os.Remove(tmpfile)
+ a.Logger.Debugln("Copying tmpfile from", f.Name(), "to", tmpfile)
+ cperr := copyFile(f.Name(), tmpfile)
+ if cperr != nil {
+ a.Logger.Errorln("AgentUpdate() copyFile:", cperr)
+ return
+ }
+ os.Chmod(tmpfile, 0755)
+ rerr := os.Rename(tmpfile, self)
+ if rerr != nil {
+ a.Logger.Errorln("AgentUpdate() os.Rename():", rerr)
+ return
+ }
}
opts := a.NewCMDOpts()
diff --git a/agent/agent_windows.go b/agent/agent_windows.go
index 0912cd2..70367c7 100644
--- a/agent/agent_windows.go
+++ b/agent/agent_windows.go
@@ -61,17 +61,23 @@ func NewAgentConfig() *rmm.AgentConfig {
cert, _, _ := k.GetStringValue("Cert")
proxy, _, _ := k.GetStringValue("Proxy")
customMeshDir, _, _ := k.GetStringValue("MeshDir")
+ natsProxyPath, _, _ := k.GetStringValue("NatsProxyPath")
+ natsProxyPort, _, _ := k.GetStringValue("NatsProxyPort")
+ natsStandardPort, _, _ := k.GetStringValue("NatsStandardPort")
return &rmm.AgentConfig{
- BaseURL: baseurl,
- AgentID: agentid,
- APIURL: apiurl,
- Token: token,
- AgentPK: agentpk,
- PK: pk,
- Cert: cert,
- Proxy: proxy,
- CustomMeshDir: customMeshDir,
+ BaseURL: baseurl,
+ AgentID: agentid,
+ APIURL: apiurl,
+ Token: token,
+ AgentPK: agentpk,
+ PK: pk,
+ Cert: cert,
+ Proxy: proxy,
+ CustomMeshDir: customMeshDir,
+ NatsProxyPath: natsProxyPath,
+ NatsProxyPort: natsProxyPort,
+ NatsStandardPort: natsStandardPort,
}
}
@@ -635,7 +641,7 @@ func (a *Agent) AgentUninstall(code string) {
func (a *Agent) addDefenderExlusions() {
code := `
Add-MpPreference -ExclusionPath 'C:\Program Files\TacticalAgent\*'
-Add-MpPreference -ExclusionPath 'C:\Windows\Temp\winagent-v*.exe'
+Add-MpPreference -ExclusionPath 'C:\Windows\Temp\tacticalagent-v*.exe'
Add-MpPreference -ExclusionPath 'C:\Windows\Temp\trmm\*'
Add-MpPreference -ExclusionPath 'C:\Program Files\Mesh Agent\*'
`
diff --git a/agent/checkin.go b/agent/checkin.go
index 1deebbd..9990198 100644
--- a/agent/checkin.go
+++ b/agent/checkin.go
@@ -12,7 +12,6 @@ https://license.tacticalrmm.com
package agent
import (
- "fmt"
"runtime"
"time"
@@ -78,8 +77,7 @@ func (a *Agent) NatsMessage(nc *nats.Conn, mode string) {
func (a *Agent) DoNatsCheckIn() {
opts := a.setupNatsOptions()
- server := fmt.Sprintf("tls://%s:4222", a.ApiURL)
- nc, err := nats.Connect(server, opts...)
+ nc, err := nats.Connect(a.NatsServer, opts...)
if err != nil {
a.Logger.Errorln(err)
return
diff --git a/agent/install.go b/agent/install.go
index 8614794..a975581 100644
--- a/agent/install.go
+++ b/agent/install.go
@@ -82,11 +82,6 @@ func (a *Agent) Install(i *Installer) {
a.Logger.Debugln("API:", i.SaltMaster)
- terr := TestTCP(fmt.Sprintf("%s:4222", i.SaltMaster))
- if terr != nil {
- a.installerMsg(fmt.Sprintf("ERROR: Either port 4222 TCP is not open on your RMM, or nats.service is not running.\n\n%s", terr.Error()), "error", i.Silent)
- }
-
baseURL := u.Scheme + "://" + u.Host
a.Logger.Debugln("Base URL:", baseURL)
@@ -138,14 +133,6 @@ func (a *Agent) Install(i *Installer) {
rClient.SetProxy(i.Proxy)
}
- var arch string
- switch a.Arch {
- case "x86_64":
- arch = "64"
- case "x86":
- arch = "32"
- }
-
var installerMeshSystemEXE string
if len(i.MeshDir) > 0 {
installerMeshSystemEXE = filepath.Join(i.MeshDir, "MeshAgent.exe")
@@ -159,7 +146,7 @@ func (a *Agent) Install(i *Installer) {
mesh := filepath.Join(a.ProgramDir, a.MeshInstaller)
if i.LocalMesh == "" {
a.Logger.Infoln("Downloading mesh agent...")
- payload := map[string]string{"arch": arch, "plat": a.Platform}
+ payload := map[string]string{"goarch": a.GoArch, "plat": a.Platform}
r, err := rClient.R().SetBody(payload).SetOutput(mesh).Post(fmt.Sprintf("%s/api/v3/meshexe/", baseURL))
if err != nil {
a.installerMsg(fmt.Sprintf("Failed to download mesh agent: %s", err.Error()), "error", i.Silent)
diff --git a/agent/install_linux.go b/agent/install_unix.go
similarity index 96%
rename from agent/install_linux.go
rename to agent/install_unix.go
index b9debcc..cf6a068 100644
--- a/agent/install_linux.go
+++ b/agent/install_unix.go
@@ -1,3 +1,6 @@
+//go:build !windows
+// +build !windows
+
/*
Copyright 2022 AmidaWare LLC.
diff --git a/agent/process.go b/agent/process.go
index bd3e4ee..ae7c392 100644
--- a/agent/process.go
+++ b/agent/process.go
@@ -64,9 +64,16 @@ func (a *Agent) KillHungUpdates() {
if err != nil {
continue
}
+
+ // winagent-v* is deprecated
if strings.Contains(p.Exe, "winagent-v") {
a.Logger.Debugln("killing process", p.Exe)
KillProc(int32(p.PID))
}
+
+ if strings.Contains(p.Exe, "tacticalagent-v") {
+ a.Logger.Debugln("killing process", p.Exe)
+ KillProc(int32(p.PID))
+ }
}
}
diff --git a/agent/rpc.go b/agent/rpc.go
index 7d24d0b..e457ecd 100644
--- a/agent/rpc.go
+++ b/agent/rpc.go
@@ -54,8 +54,7 @@ func (a *Agent) RunRPC() {
var wg sync.WaitGroup
wg.Add(1)
opts := a.setupNatsOptions()
- server := fmt.Sprintf("tls://%s:4222", a.ApiURL)
- nc, err := nats.Connect(server, opts...)
+ nc, err := nats.Connect(a.NatsServer, opts...)
if err != nil {
a.Logger.Fatalln("RunRPC() nats.Connect()", err)
}
diff --git a/agent/svc.go b/agent/svc.go
index 6e21b15..e360ebf 100644
--- a/agent/svc.go
+++ b/agent/svc.go
@@ -12,7 +12,6 @@ https://license.tacticalrmm.com
package agent
import (
- "fmt"
"sync"
"time"
@@ -38,8 +37,7 @@ func (a *Agent) AgentSvc() {
time.Sleep(time.Duration(sleepDelay) * time.Second)
opts := a.setupNatsOptions()
- server := fmt.Sprintf("tls://%s:4222", a.ApiURL)
- nc, err := nats.Connect(server, opts...)
+ nc, err := nats.Connect(a.NatsServer, opts...)
if err != nil {
a.Logger.Fatalln("AgentSvc() nats.Connect()", err)
}
diff --git a/build/rmm.exe.manifest b/build/rmm.exe.manifest
index b37646b..243bb4d 100644
--- a/build/rmm.exe.manifest
+++ b/build/rmm.exe.manifest
@@ -3,7 +3,7 @@
diff --git a/build/setup.iss b/build/setup.iss
index 99bcd12..3a10b72 100644
--- a/build/setup.iss
+++ b/build/setup.iss
@@ -1,5 +1,5 @@
#define MyAppName "Tactical RMM Agent"
-#define MyAppVersion "2.0.4"
+#define MyAppVersion "2.1.0"
#define MyAppPublisher "AmidaWare LLC"
#define MyAppURL "https://github.com/amidaware"
#define MyAppExeName "tacticalrmm.exe"
diff --git a/main.go b/main.go
index 392c376..ce69cfb 100644
--- a/main.go
+++ b/main.go
@@ -25,7 +25,7 @@ import (
)
var (
- version = "2.0.4"
+ version = "2.1.0"
log = logrus.New()
logFile *os.File
)
@@ -197,6 +197,6 @@ func installUsage() {
}
func updateUsage() {
- u := `Usage: tacticalrmm.exe -m update -updateurl https://example.com/winagent-vX.X.X.exe -inno winagent-vX.X.X.exe -updatever 1.1.1`
+ u := `Usage: tacticalrmm.exe -m update -updateurl https://example.com/tacticalagent-vX.X.X.exe -inno tacticalagent-vX.X.X.exe -updatever 1.1.1`
fmt.Println(u)
}
diff --git a/shared/types.go b/shared/types.go
index 64ae5be..2038f5e 100644
--- a/shared/types.go
+++ b/shared/types.go
@@ -33,15 +33,18 @@ type ProcessMsg struct {
}
type AgentConfig struct {
- BaseURL string
- AgentID string
- APIURL string
- Token string
- AgentPK string
- PK int
- Cert string
- Proxy string
- CustomMeshDir string
+ BaseURL string
+ AgentID string
+ APIURL string
+ Token string
+ AgentPK string
+ PK int
+ Cert string
+ Proxy string
+ CustomMeshDir string
+ NatsProxyPath string
+ NatsProxyPort string
+ NatsStandardPort string
}
type RunScriptResp struct {
diff --git a/versioninfo.json b/versioninfo.json
index 13186f9..ef230db 100644
--- a/versioninfo.json
+++ b/versioninfo.json
@@ -2,14 +2,14 @@
"FixedFileInfo": {
"FileVersion": {
"Major": 2,
- "Minor": 0,
- "Patch": 4,
+ "Minor": 1,
+ "Patch": 0,
"Build": 0
},
"ProductVersion": {
"Major": 2,
- "Minor": 0,
- "Patch": 4,
+ "Minor": 1,
+ "Patch": 0,
"Build": 0
},
"FileFlagsMask": "3f",
@@ -22,14 +22,14 @@
"Comments": "",
"CompanyName": "AmidaWare LLC",
"FileDescription": "Tactical RMM Agent",
- "FileVersion": "v2.0.4.0",
+ "FileVersion": "v2.1.0.0",
"InternalName": "tacticalrmm.exe",
"LegalCopyright": "Copyright (c) 2022 AmidaWare LLC",
"LegalTrademarks": "",
"OriginalFilename": "tacticalrmm.exe",
"PrivateBuild": "",
"ProductName": "Tactical RMM Agent",
- "ProductVersion": "v2.0.4.0",
+ "ProductVersion": "v2.1.0.0",
"SpecialBuild": ""
},
"VarFileInfo": {