Release 2.1.0

This commit is contained in:
wh1te909 2022-07-07 11:41:33 -07:00
commit 25dfa5db55
15 changed files with 172 additions and 63 deletions

49
.github/workflows/ci.yml vendored Normal file
View File

@ -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

View File

@ -66,6 +66,9 @@ type Agent struct {
Platform string Platform string
GoArch string GoArch string
ServiceConfig *service.Config ServiceConfig *service.Config
NatsServer string
NatsProxyPath string
NatsProxyPort string
} }
const ( 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{ return &Agent{
Hostname: info.Hostname, Hostname: info.Hostname,
Arch: info.Architecture,
BaseURL: ac.BaseURL, BaseURL: ac.BaseURL,
AgentID: ac.AgentID, AgentID: ac.AgentID,
ApiURL: ac.APIURL, ApiURL: ac.APIURL,
@ -164,6 +183,9 @@ func New(logger *logrus.Logger, version string) *Agent {
Platform: runtime.GOOS, Platform: runtime.GOOS,
GoArch: runtime.GOARCH, GoArch: runtime.GOARCH,
ServiceConfig: svcConf, 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.RetryOnFailedConnect(true))
opts = append(opts, nats.MaxReconnects(-1)) opts = append(opts, nats.MaxReconnects(-1))
opts = append(opts, nats.ReconnectBufSize(-1)) opts = append(opts, nats.ReconnectBufSize(-1))
opts = append(opts, nats.ProxyPath(a.NatsProxyPath))
return opts return opts
} }
@ -385,6 +408,7 @@ func (a *Agent) CleanupAgentUpdates() {
return return
} }
// winagent-v* is deprecated
files, err := filepath.Glob("winagent-v*.exe") files, err := filepath.Glob("winagent-v*.exe")
if err == nil { if err == nil {
for _, f := range files { 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")) cderr = os.Chdir(os.Getenv("TMP"))
if cderr != nil { if cderr != nil {
a.Logger.Errorln(cderr) a.Logger.Errorln(cderr)

View File

@ -1,3 +1,6 @@
//go:build !windows
// +build !windows
/* /*
Copyright 2022 AmidaWare LLC. Copyright 2022 AmidaWare LLC.
@ -15,6 +18,7 @@ import (
"bufio" "bufio"
"fmt" "fmt"
"os" "os"
"path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
@ -142,15 +146,18 @@ func NewAgentConfig() *rmm.AgentConfig {
pk, _ := strconv.Atoi(agentpk) pk, _ := strconv.Atoi(agentpk)
ret := &rmm.AgentConfig{ ret := &rmm.AgentConfig{
BaseURL: viper.GetString("baseurl"), BaseURL: viper.GetString("baseurl"),
AgentID: viper.GetString("agentid"), AgentID: viper.GetString("agentid"),
APIURL: viper.GetString("apiurl"), APIURL: viper.GetString("apiurl"),
Token: viper.GetString("token"), Token: viper.GetString("token"),
AgentPK: agentpk, AgentPK: agentpk,
PK: pk, PK: pk,
Cert: viper.GetString("cert"), Cert: viper.GetString("cert"),
Proxy: viper.GetString("proxy"), Proxy: viper.GetString("proxy"),
CustomMeshDir: viper.GetString("meshdir"), CustomMeshDir: viper.GetString("meshdir"),
NatsProxyPath: viper.GetString("natsproxypath"),
NatsProxyPort: viper.GetString("natsproxyport"),
NatsStandardPort: viper.GetString("natsstandardport"),
} }
return ret return ret
} }
@ -244,8 +251,29 @@ func (a *Agent) AgentUpdate(url, inno, version string) {
os.Chmod(f.Name(), 0755) os.Chmod(f.Name(), 0755)
err = os.Rename(f.Name(), self) err = os.Rename(f.Name(), self)
if err != nil { if err != nil {
a.Logger.Errorln("AgentUpdate() os.Rename():", err) a.Logger.Debugln("Detected /tmp on different filesystem")
return // 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() opts := a.NewCMDOpts()

View File

@ -61,17 +61,23 @@ func NewAgentConfig() *rmm.AgentConfig {
cert, _, _ := k.GetStringValue("Cert") cert, _, _ := k.GetStringValue("Cert")
proxy, _, _ := k.GetStringValue("Proxy") proxy, _, _ := k.GetStringValue("Proxy")
customMeshDir, _, _ := k.GetStringValue("MeshDir") customMeshDir, _, _ := k.GetStringValue("MeshDir")
natsProxyPath, _, _ := k.GetStringValue("NatsProxyPath")
natsProxyPort, _, _ := k.GetStringValue("NatsProxyPort")
natsStandardPort, _, _ := k.GetStringValue("NatsStandardPort")
return &rmm.AgentConfig{ return &rmm.AgentConfig{
BaseURL: baseurl, BaseURL: baseurl,
AgentID: agentid, AgentID: agentid,
APIURL: apiurl, APIURL: apiurl,
Token: token, Token: token,
AgentPK: agentpk, AgentPK: agentpk,
PK: pk, PK: pk,
Cert: cert, Cert: cert,
Proxy: proxy, Proxy: proxy,
CustomMeshDir: customMeshDir, CustomMeshDir: customMeshDir,
NatsProxyPath: natsProxyPath,
NatsProxyPort: natsProxyPort,
NatsStandardPort: natsStandardPort,
} }
} }
@ -635,7 +641,7 @@ func (a *Agent) AgentUninstall(code string) {
func (a *Agent) addDefenderExlusions() { func (a *Agent) addDefenderExlusions() {
code := ` code := `
Add-MpPreference -ExclusionPath 'C:\Program Files\TacticalAgent\*' 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:\Windows\Temp\trmm\*'
Add-MpPreference -ExclusionPath 'C:\Program Files\Mesh Agent\*' Add-MpPreference -ExclusionPath 'C:\Program Files\Mesh Agent\*'
` `

View File

@ -12,7 +12,6 @@ https://license.tacticalrmm.com
package agent package agent
import ( import (
"fmt"
"runtime" "runtime"
"time" "time"
@ -78,8 +77,7 @@ func (a *Agent) NatsMessage(nc *nats.Conn, mode string) {
func (a *Agent) DoNatsCheckIn() { func (a *Agent) DoNatsCheckIn() {
opts := a.setupNatsOptions() opts := a.setupNatsOptions()
server := fmt.Sprintf("tls://%s:4222", a.ApiURL) nc, err := nats.Connect(a.NatsServer, opts...)
nc, err := nats.Connect(server, opts...)
if err != nil { if err != nil {
a.Logger.Errorln(err) a.Logger.Errorln(err)
return return

View File

@ -82,11 +82,6 @@ func (a *Agent) Install(i *Installer) {
a.Logger.Debugln("API:", i.SaltMaster) 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 baseURL := u.Scheme + "://" + u.Host
a.Logger.Debugln("Base URL:", baseURL) a.Logger.Debugln("Base URL:", baseURL)
@ -138,14 +133,6 @@ func (a *Agent) Install(i *Installer) {
rClient.SetProxy(i.Proxy) rClient.SetProxy(i.Proxy)
} }
var arch string
switch a.Arch {
case "x86_64":
arch = "64"
case "x86":
arch = "32"
}
var installerMeshSystemEXE string var installerMeshSystemEXE string
if len(i.MeshDir) > 0 { if len(i.MeshDir) > 0 {
installerMeshSystemEXE = filepath.Join(i.MeshDir, "MeshAgent.exe") installerMeshSystemEXE = filepath.Join(i.MeshDir, "MeshAgent.exe")
@ -159,7 +146,7 @@ func (a *Agent) Install(i *Installer) {
mesh := filepath.Join(a.ProgramDir, a.MeshInstaller) mesh := filepath.Join(a.ProgramDir, a.MeshInstaller)
if i.LocalMesh == "" { if i.LocalMesh == "" {
a.Logger.Infoln("Downloading mesh agent...") 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)) r, err := rClient.R().SetBody(payload).SetOutput(mesh).Post(fmt.Sprintf("%s/api/v3/meshexe/", baseURL))
if err != nil { if err != nil {
a.installerMsg(fmt.Sprintf("Failed to download mesh agent: %s", err.Error()), "error", i.Silent) a.installerMsg(fmt.Sprintf("Failed to download mesh agent: %s", err.Error()), "error", i.Silent)

View File

@ -1,3 +1,6 @@
//go:build !windows
// +build !windows
/* /*
Copyright 2022 AmidaWare LLC. Copyright 2022 AmidaWare LLC.

View File

@ -64,9 +64,16 @@ func (a *Agent) KillHungUpdates() {
if err != nil { if err != nil {
continue continue
} }
// winagent-v* is deprecated
if strings.Contains(p.Exe, "winagent-v") { if strings.Contains(p.Exe, "winagent-v") {
a.Logger.Debugln("killing process", p.Exe) a.Logger.Debugln("killing process", p.Exe)
KillProc(int32(p.PID)) KillProc(int32(p.PID))
} }
if strings.Contains(p.Exe, "tacticalagent-v") {
a.Logger.Debugln("killing process", p.Exe)
KillProc(int32(p.PID))
}
} }
} }

View File

@ -54,8 +54,7 @@ func (a *Agent) RunRPC() {
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
opts := a.setupNatsOptions() opts := a.setupNatsOptions()
server := fmt.Sprintf("tls://%s:4222", a.ApiURL) nc, err := nats.Connect(a.NatsServer, opts...)
nc, err := nats.Connect(server, opts...)
if err != nil { if err != nil {
a.Logger.Fatalln("RunRPC() nats.Connect()", err) a.Logger.Fatalln("RunRPC() nats.Connect()", err)
} }

View File

@ -12,7 +12,6 @@ https://license.tacticalrmm.com
package agent package agent
import ( import (
"fmt"
"sync" "sync"
"time" "time"
@ -38,8 +37,7 @@ func (a *Agent) AgentSvc() {
time.Sleep(time.Duration(sleepDelay) * time.Second) time.Sleep(time.Duration(sleepDelay) * time.Second)
opts := a.setupNatsOptions() opts := a.setupNatsOptions()
server := fmt.Sprintf("tls://%s:4222", a.ApiURL) nc, err := nats.Connect(a.NatsServer, opts...)
nc, err := nats.Connect(server, opts...)
if err != nil { if err != nil {
a.Logger.Fatalln("AgentSvc() nats.Connect()", err) a.Logger.Fatalln("AgentSvc() nats.Connect()", err)
} }

View File

@ -3,7 +3,7 @@
<assemblyIdentity <assemblyIdentity
type="win32" type="win32"
name="TacticalRMM" name="TacticalRMM"
version="2.0.4.0" version="2.1.0.0"
processorArchitecture="*"/> processorArchitecture="*"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security> <security>

View File

@ -1,5 +1,5 @@
#define MyAppName "Tactical RMM Agent" #define MyAppName "Tactical RMM Agent"
#define MyAppVersion "2.0.4" #define MyAppVersion "2.1.0"
#define MyAppPublisher "AmidaWare LLC" #define MyAppPublisher "AmidaWare LLC"
#define MyAppURL "https://github.com/amidaware" #define MyAppURL "https://github.com/amidaware"
#define MyAppExeName "tacticalrmm.exe" #define MyAppExeName "tacticalrmm.exe"

View File

@ -25,7 +25,7 @@ import (
) )
var ( var (
version = "2.0.4" version = "2.1.0"
log = logrus.New() log = logrus.New()
logFile *os.File logFile *os.File
) )
@ -197,6 +197,6 @@ func installUsage() {
} }
func updateUsage() { 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) fmt.Println(u)
} }

View File

@ -33,15 +33,18 @@ type ProcessMsg struct {
} }
type AgentConfig struct { type AgentConfig struct {
BaseURL string BaseURL string
AgentID string AgentID string
APIURL string APIURL string
Token string Token string
AgentPK string AgentPK string
PK int PK int
Cert string Cert string
Proxy string Proxy string
CustomMeshDir string CustomMeshDir string
NatsProxyPath string
NatsProxyPort string
NatsStandardPort string
} }
type RunScriptResp struct { type RunScriptResp struct {

View File

@ -2,14 +2,14 @@
"FixedFileInfo": { "FixedFileInfo": {
"FileVersion": { "FileVersion": {
"Major": 2, "Major": 2,
"Minor": 0, "Minor": 1,
"Patch": 4, "Patch": 0,
"Build": 0 "Build": 0
}, },
"ProductVersion": { "ProductVersion": {
"Major": 2, "Major": 2,
"Minor": 0, "Minor": 1,
"Patch": 4, "Patch": 0,
"Build": 0 "Build": 0
}, },
"FileFlagsMask": "3f", "FileFlagsMask": "3f",
@ -22,14 +22,14 @@
"Comments": "", "Comments": "",
"CompanyName": "AmidaWare LLC", "CompanyName": "AmidaWare LLC",
"FileDescription": "Tactical RMM Agent", "FileDescription": "Tactical RMM Agent",
"FileVersion": "v2.0.4.0", "FileVersion": "v2.1.0.0",
"InternalName": "tacticalrmm.exe", "InternalName": "tacticalrmm.exe",
"LegalCopyright": "Copyright (c) 2022 AmidaWare LLC", "LegalCopyright": "Copyright (c) 2022 AmidaWare LLC",
"LegalTrademarks": "", "LegalTrademarks": "",
"OriginalFilename": "tacticalrmm.exe", "OriginalFilename": "tacticalrmm.exe",
"PrivateBuild": "", "PrivateBuild": "",
"ProductName": "Tactical RMM Agent", "ProductName": "Tactical RMM Agent",
"ProductVersion": "v2.0.4.0", "ProductVersion": "v2.1.0.0",
"SpecialBuild": "" "SpecialBuild": ""
}, },
"VarFileInfo": { "VarFileInfo": {