Skip to content

Commit

Permalink
fix 0xrawsec#98: Provide system information in /endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
qjerome committed Jan 21, 2022
1 parent 63c89a3 commit 7e23ab3
Show file tree
Hide file tree
Showing 19 changed files with 984 additions and 159 deletions.
32 changes: 29 additions & 3 deletions api/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/0xrawsec/golang-utils/crypto/data"
"github.com/0xrawsec/golang-utils/fsutil"
"github.com/0xrawsec/golang-utils/log"
"github.com/0xrawsec/whids/hids/sysinfo"
"github.com/0xrawsec/whids/utils"
)

// ClientConfig structure definition
Expand Down Expand Up @@ -229,15 +231,14 @@ func (m *ManagerClient) IsServerUp() bool {
}
resp, err := m.HTTPClient.Do(get)
if err != nil {
log.Errorf("IsServerUp cannot issue server key request: %s", err)
return false
}

if resp != nil {
defer resp.Body.Close()
return resp.StatusCode == 200
}
return false

return resp.StatusCode == 200
}

// IsServerAuthenticated returns true if the server is authenticated and thus can be trusted
Expand Down Expand Up @@ -539,6 +540,31 @@ func (m *ManagerClient) FetchCommand() (*Command, error) {
return command, fmt.Errorf("FetchCommand failed, server cannot be authenticated")
}

func (m *ManagerClient) PostSystemInfo(info *sysinfo.SystemInfo) error {
funcName := utils.GetCurFuncName()
if auth, _ := m.IsServerAuthenticated(); auth {
if b, err := json.Marshal(info); err != nil {
return fmt.Errorf("%s failed to marshal data: %s", funcName, err)
} else {
if req, err := m.PrepareGzip("POST", EptAPIPostSystemInfo, bytes.NewBuffer(b)); err != nil {
return err
} else {
if resp, err := m.HTTPClient.Do(req); err != nil {
return fmt.Errorf("%s failed to issue HTTP request: %s", funcName, err)
} else {
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("%s received bad status code %d: %s", funcName, resp.StatusCode, respBodyToString(resp))
} else {
return nil
}
}
}
}
}
return fmt.Errorf("%s failed, server cannot be authenticated", funcName)
}

// Close closes idle connections from underlying transport
func (m *ManagerClient) Close() {
m.HTTPClient.CloseIdleConnections()
Expand Down
24 changes: 13 additions & 11 deletions api/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@ import (
"time"

"github.com/0xrawsec/sod"
"github.com/0xrawsec/whids/hids/sysinfo"
)

// Endpoint structure used to track and interact with endpoints
type Endpoint struct {
sod.Item
Uuid string `json:"uuid" sod:"unique"`
Hostname string `json:"hostname"`
IP string `json:"ip"`
Group string `json:"group"`
Criticality int `json:"criticality"`
Key string `json:"key,omitempty"`
Command *Command `json:"command,omitempty"`
Score float64 `json:"score"`
Status string `json:"status"`
LastDetection time.Time `json:"last-detection"`
LastConnection time.Time `json:"last-connection"`
Uuid string `json:"uuid" sod:"unique"`
Hostname string `json:"hostname"`
IP string `json:"ip"`
Group string `json:"group"`
Criticality int `json:"criticality"`
Key string `json:"key,omitempty"`
Command *Command `json:"command,omitempty"`
Score float64 `json:"score"`
Status string `json:"status"`
SystemInfo *sysinfo.SystemInfo `json:"system-info,omitempty"`
LastDetection time.Time `json:"last-detection"`
LastConnection time.Time `json:"last-connection"`
}

// NewEndpoint returns a new Endpoint structure
Expand Down
5 changes: 4 additions & 1 deletion api/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"path/filepath"
"regexp"
"sync"
"time"

"github.com/0xrawsec/sod"
"github.com/0xrawsec/whids/event"
Expand Down Expand Up @@ -326,7 +327,9 @@ func NewManager(c *ManagerConfig) (*Manager, error) {

func (m *Manager) initializeDB() (err error) {
// Creating Endpoint table
if err = m.db.Create(&Endpoint{}, sod.DefaultSchema); err != nil {
endpointSchema := sod.DefaultSchema
endpointSchema.Asynchrone(100, 10*time.Second)
if err = m.db.Create(&Endpoint{}, endpointSchema); err != nil {
return
}

Expand Down
22 changes: 0 additions & 22 deletions api/manager_admin_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,28 +50,6 @@ func admApiParseTime(stimestamp string) (t time.Time, err error) {
return
}

func muxGetVar(rq *http.Request, name string) (string, error) {
vars := mux.Vars(rq)
if value, ok := vars[name]; ok {
return value, nil
}
return "", fmt.Errorf("unknown mux variable")
}

func format(format string, a ...interface{}) string {
return fmt.Sprintf(format, a...)
}

// read posted data and unseriablize it from JSON
func readPostAsJSON(rq *http.Request, i interface{}) error {
defer rq.Body.Close()
b, err := ioutil.ReadAll(rq.Body)
if err != nil {
return fmt.Errorf("failed to read POST body: %w", err)
}
return json.Unmarshal(b, i)
}

// AdminAPIConfig configuration for Administrative API
type AdminAPIConfig struct {
Host string `toml:"host" comment:"Hostname or IP address where the API should listen to"`
Expand Down
19 changes: 19 additions & 0 deletions api/manager_endpoint_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/0xrawsec/whids/event"
"github.com/0xrawsec/whids/hids/sysinfo"
"github.com/0xrawsec/whids/utils"

"github.com/0xrawsec/golang-utils/log"
Expand Down Expand Up @@ -138,6 +139,7 @@ func (m *Manager) runEndpointAPI() {
// POST based
rt.HandleFunc(EptAPIPostLogsPath, m.Collect).Methods("POST")
rt.HandleFunc(EptAPIPostDumpPath, m.UploadDump).Methods("POST")
rt.HandleFunc(EptAPIPostSystemInfo, m.SystemInfo).Methods("POST")

// GET based
rt.HandleFunc(EptAPIServerKeyPath, m.ServerKey).Methods("GET")
Expand Down Expand Up @@ -379,3 +381,20 @@ func (m *Manager) Command(wt http.ResponseWriter, rq *http.Request) {
}
}
}

// Command HTTP handler
func (m *Manager) SystemInfo(wt http.ResponseWriter, rq *http.Request) {
id := rq.Header.Get(EndpointUUIDHeader)
switch rq.Method {
case "POST":
if endpt, ok := m.endpoints.GetMutByUUID(id); ok {
info := sysinfo.SystemInfo{}
if err := readPostAsJSON(rq, &info); err != nil {
log.Errorf("Failed to receive system information for %s", endpt.Uuid)
http.Error(wt, "Failed to unmarshal data", http.StatusInternalServerError)
} else {
endpt.SystemInfo = &info
}
}
}
}
Loading

0 comments on commit 7e23ab3

Please sign in to comment.