зеркало из https://github.com/mozilla/mig.git
[medium] add API endpoint to query agents
This commit is contained in:
Родитель
8d42d11915
Коммит
80d39565a8
|
@ -101,7 +101,7 @@ func main() {
|
|||
s.HandleFunc("/command", getCommand).Methods("GET")
|
||||
s.HandleFunc("/command/cancel/", describeCancelCommand).Methods("GET")
|
||||
s.HandleFunc("/command/cancel/", cancelCommand).Methods("POST")
|
||||
s.HandleFunc("/agent/dashboard", getAgentsDashboard).Methods("GET")
|
||||
s.HandleFunc("/agent", getAgent).Methods("GET")
|
||||
s.HandleFunc("/dashboard", getDashboard).Methods("GET")
|
||||
|
||||
// all set, start the http handler
|
||||
|
@ -157,14 +157,6 @@ func getHome(respWriter http.ResponseWriter, request *http.Request) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
resource.AddQuery(cljs.Query{
|
||||
Rel: "Get agent dashboard",
|
||||
Href: fmt.Sprintf("%s/agent/dashboard", ctx.Server.BaseURL),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = resource.AddLink(cljs.Link{
|
||||
Rel: "create action",
|
||||
Href: fmt.Sprintf("%s/action/create/", ctx.Server.BaseURL),
|
||||
|
@ -214,6 +206,18 @@ func getHome(respWriter http.ResponseWriter, request *http.Request) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
resource.AddQuery(cljs.Query{
|
||||
Rel: "Query agent by ID",
|
||||
Href: fmt.Sprintf("%s/agent", ctx.Server.BaseURL),
|
||||
Prompt: "GET endpoint to query an agent by ID, using url parameter ?agentid=<numerical id>",
|
||||
Data: []cljs.Data{
|
||||
{Name: "agentid", Value: "[0-9]{1,20}", Prompt: "Agent ID"},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
resource.AddQuery(cljs.Query{
|
||||
Rel: "Search stuff",
|
||||
Href: fmt.Sprintf("%s/search", ctx.Server.BaseURL),
|
||||
|
@ -566,7 +570,7 @@ func cancelCommand(respWriter http.ResponseWriter, request *http.Request) {
|
|||
respond(501, resource, respWriter, request, opid)
|
||||
}
|
||||
|
||||
func getAgentsDashboard(respWriter http.ResponseWriter, request *http.Request) {
|
||||
func getAgent(respWriter http.ResponseWriter, request *http.Request) {
|
||||
opid := mig.GenID()
|
||||
loc := fmt.Sprintf("http://%s:%d%s", ctx.Server.IP, ctx.Server.Port, request.URL.String())
|
||||
resource := cljs.New(loc)
|
||||
|
@ -578,7 +582,43 @@ func getAgentsDashboard(respWriter http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getAgentsDashboard()"}.Debug()
|
||||
}()
|
||||
respond(501, resource, respWriter, request, opid)
|
||||
agentID, err := strconv.ParseFloat(request.URL.Query()["agentid"][0], 64)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Wrong parameters 'agentid': '%v'", err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// retrieve the command
|
||||
var agt mig.Agent
|
||||
if agentID > 0 {
|
||||
agt, err = ctx.DB.AgentByID(agentID)
|
||||
if err != nil {
|
||||
if fmt.Sprintf("%v", err) == "Error while retrieving agent: 'sql: no rows in result set'" {
|
||||
// not found, return 404
|
||||
resource.SetError(cljs.Error{
|
||||
Code: fmt.Sprintf("%.0f", opid),
|
||||
Message: fmt.Sprintf("Agent ID '%.0f' not found", agentID)})
|
||||
respond(404, resource, respWriter, request, opid)
|
||||
return
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// bad request, return 400
|
||||
resource.SetError(cljs.Error{
|
||||
Code: fmt.Sprintf("%.0f", opid),
|
||||
Message: fmt.Sprintf("Invalid Agent ID '%.0f'", agentID)})
|
||||
respond(400, resource, respWriter, request, opid)
|
||||
return
|
||||
}
|
||||
// store the results in the resource
|
||||
agentItem, err := agentToItem(agt)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resource.AddItem(agentItem)
|
||||
respond(200, resource, respWriter, request, opid)
|
||||
}
|
||||
|
||||
func getDashboard(respWriter http.ResponseWriter, request *http.Request) {
|
||||
|
|
|
@ -85,6 +85,15 @@ func commandToItem(cmd mig.Command) (item cljs.Item, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// agentToItem receives an agent and returns an Item in Collection+JSON
|
||||
func agentToItem(agt mig.Agent) (item cljs.Item, err error) {
|
||||
item.Href = fmt.Sprintf("%s/agent?agentid=%.0f", ctx.Server.BaseURL, agt.ID)
|
||||
item.Data = []cljs.Data{
|
||||
{Name: "agent", Value: agt},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// agentsSumToItem receives an AgentsSum and returns an Item
|
||||
// in the Collection+JSON format
|
||||
func agentsSummaryToItem(sum []migdb.AgentsSum, count float64, ctx Context) (item cljs.Item, err error) {
|
||||
|
|
|
@ -83,6 +83,8 @@ func search(respWriter http.ResponseWriter, request *http.Request) {
|
|||
if err != nil {
|
||||
panic("after date not in RFC3339 format")
|
||||
}
|
||||
case "agentid":
|
||||
p.AgentID = request.URL.Query()["agentid"][0]
|
||||
case "agentname":
|
||||
p.AgentName = request.URL.Query()["agentname"][0]
|
||||
case "before":
|
||||
|
|
|
@ -68,6 +68,7 @@ type SearchParameters struct {
|
|||
After time.Time `json:"after"`
|
||||
Type string `json:"type"`
|
||||
Report string `json:"report"`
|
||||
AgentID string `json:"agentid"`
|
||||
AgentName string `json:"agentname"`
|
||||
ActionName string `json:"actionname"`
|
||||
ActionID string `json:"actionid"`
|
||||
|
@ -83,6 +84,7 @@ func NewSearchParameters() (p SearchParameters) {
|
|||
p.Before = time.Date(9998, time.January, 11, 11, 11, 11, 11, time.UTC)
|
||||
p.After = time.Date(11, time.January, 11, 11, 11, 11, 11, time.UTC)
|
||||
p.AgentName = "%"
|
||||
p.AgentID = "∞"
|
||||
p.ActionName = "%"
|
||||
p.ActionID = "∞"
|
||||
p.CommandID = "∞"
|
||||
|
@ -118,6 +120,18 @@ func (db *DB) SearchCommands(p SearchParameters) (commands []mig.Command, err er
|
|||
return
|
||||
}
|
||||
}
|
||||
var minAgentID float64 = 0
|
||||
var maxAgentID float64 = 18446744073709551616 //2^64
|
||||
if p.AgentID != "∞" {
|
||||
minAgentID, err = strconv.ParseFloat(p.AgentID, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
maxAgentID, err = strconv.ParseFloat(p.AgentID, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
rows, err := db.c.Query(`SELECT commands.id, commands.status, commands.results, commands.starttime, commands.finishtime,
|
||||
actions.id, actions.name, actions.target, actions.description, actions.threat,
|
||||
actions.operations, actions.validfrom, actions.expireafter,
|
||||
|
@ -130,11 +144,12 @@ func (db *DB) SearchCommands(p SearchParameters) (commands []mig.Command, err er
|
|||
AND actions.name LIKE $5
|
||||
AND actions.id >= $6 AND actions.id <= $7
|
||||
AND agents.name LIKE $8
|
||||
AND actions.threat->>'family' LIKE $9
|
||||
AND commands.status LIKE $10
|
||||
ORDER BY commands.id DESC LIMIT $11`,
|
||||
AND agents.id >= $9 AND agents.id <= $10
|
||||
AND actions.threat->>'family' LIKE $11
|
||||
AND commands.status LIKE $12
|
||||
ORDER BY commands.id DESC LIMIT $13`,
|
||||
p.Before, p.After, minCommandID, maxCommandID, p.ActionName, minActionID, maxActionID,
|
||||
p.AgentName, p.ThreatFamily, p.Status, uint64(p.Limit))
|
||||
p.AgentName, minAgentID, maxAgentID, p.ThreatFamily, p.Status, uint64(p.Limit))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error while finding commands: '%v'", err)
|
||||
return
|
||||
|
@ -257,7 +272,7 @@ func (db *DB) SearchAgents(p SearchParameters) (agents []mig.Agent, err error) {
|
|||
WHERE agents.heartbeattime <= $1 AND agents.heartbeattime >= $2
|
||||
AND agents.name LIKE $3
|
||||
AND agents.status LIKE $4
|
||||
ORDER BY agents.heartbeattime LIMIT $5`,
|
||||
ORDER BY agents.heartbeattime DESC LIMIT $5`,
|
||||
p.Before, p.After, p.AgentName, p.Status, uint64(p.Limit))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error while finding agents: '%v'", err)
|
||||
|
@ -691,6 +706,22 @@ func (db *DB) AgentByQueueAndPID(queueloc string, pid int) (agent mig.Agent, err
|
|||
return
|
||||
}
|
||||
|
||||
// AgentByID returns a single agent identified by its ID
|
||||
func (db *DB) AgentByID(id float64) (agent mig.Agent, err error) {
|
||||
err = db.c.QueryRow(`SELECT id, name, queueloc, os, version, pid, starttime, heartbeattime,
|
||||
status FROM agents WHERE id=$1`, id).Scan(
|
||||
&agent.ID, &agent.Name, &agent.QueueLoc, &agent.OS, &agent.Version, &agent.PID,
|
||||
&agent.StartTime, &agent.HeartBeatTS, &agent.Status)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error while retrieving agent: '%v'", err)
|
||||
return
|
||||
}
|
||||
if err == sql.ErrNoRows {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AgentsActiveSince returns an array of Agents that have sent a heartbeat between
|
||||
// a point in time and now
|
||||
func (db *DB) AgentsActiveSince(pointInTime time.Time) (agents []mig.Agent, err error) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче