A Go client for the Greenbone Management Protocol (GMP) to interact with Greenbone/OpenVAS vulnerability management servers.
Caution
Expect breaking changes as the library matures.
- Go 1.23+
- Access to a Greenbone/OpenVAS server with GMP enabled
Note
An example docker-compose.yml is provided in ./hack for local testing.
package main
import (
"context"
"fmt"
"log"
"github.com/brennoo/go-gmp/client"
"github.com/brennoo/go-gmp/commands"
"github.com/brennoo/go-gmp/connections"
)
func main() {
ctx := context.Background()
// Connect
conn, err := connections.NewTLSConnection("gmp.example.com:9390", true)
if err != nil {
log.Fatalf("failed to connect: %v", err)
}
defer conn.Close()
// Authenticate
cli := client.New(conn)
_, err := cli.Authenticate(&commands.Authenticate{
Credentials: &commands.AuthenticateCredentials{
Username: "admin",
Password: "secret",
},
})
if err != nil {
log.Fatalf("auth failed: %v", err)
}
// Query
tasksResp, err := cli.GetTasks(ctx)
if err != nil {
log.Fatalf("get tasks failed: %v", err)
}
for _, task := range tasksResp.Task {
fmt.Printf("Task: %s (%s)\n", task.Name, task.Status)
}
}The library provides two filtering approaches:
tasksResp, err := cli.GetTasks(ctx, "status=running", "sort=name")import "github.com/brennoo/go-gmp/commands/filtering"
tasksResp, err := cli.GetTasks(ctx,
filtering.WithStatus(filtering.StatusRunning),
filtering.WithSort(filtering.SortByName, filtering.SortAsc),
)The library provides two approaches for handling large datasets:
| Resource | One-shot | Iterator |
|---|---|---|
| Tasks | GetTasks |
Tasks |
| Results | GetResults |
Results |
| Assets | GetAssets |
Assets |
| Targets | GetTargets |
Targets |
| Tickets | GetTickets |
Tickets |
| Port Lists | GetPortLists |
PortLists |
| Settings | GetSettings |
Settings |
// Get first page with default limit
tasksResp, err := cli.GetTasks(ctx)
// Get with custom limit and filters
tasksResp, err := cli.GetTasks(ctx, "rows=50", "status=running")taskIter := cli.Tasks(ctx, 10)
defer taskIter.Close()
for taskIter.Next() {
task := taskIter.Current()
fmt.Printf("Task: %s\n", task.Name)
}
if err := taskIter.Err(); err != nil {
log.Printf("Error: %v", err)
}The library provides structured error handling using Go's errors.As pattern for better error management and debugging.
The library defines several error types:
GMPError- Server-side errors from the GMP protocolNetworkError- Client-side network and transport errors
| Error Type | Description | HTTP Status |
|---|---|---|
ErrorTypeAuthentication |
Authentication failed | 401 |
ErrorTypeNotFound |
Resource not found | 404 |
ErrorTypePermission |
Insufficient permissions | 403 |
ErrorTypeInvalidRequest |
Invalid request format | 400 |
ErrorTypeServerError |
Server internal error | 500+ |
ErrorTypeNetwork |
Network/transport error | N/A |
import (
"errors"
"log"
"github.com/brennoo/go-gmp/commands"
)
tasksResp, err := cli.GetTasks(ctx)
if err != nil {
var gmpErr *commands.GMPError
if errors.As(err, &gmpErr) {
switch gmpErr.Type {
case commands.ErrorTypeAuthentication:
log.Fatal("Authentication failed:", gmpErr.StatusText)
case commands.ErrorTypeNotFound:
log.Println("No tasks found, continuing...")
return nil // Not necessarily an error
case commands.ErrorTypeNetwork:
log.Println("Network error, will retry...")
// Implement retry logic
default:
log.Printf("GMP error: %v", gmpErr)
}
} else {
// Handle non-GMP errors
log.Printf("Unexpected error: %v", err)
}
}When using iterators for pagination, structured error handling provides better control:
taskIter := cli.Tasks(ctx, 10)
defer taskIter.Close()
for taskIter.Next() {
task := taskIter.Current()
fmt.Printf("Task: %s\n", task.Name)
}
if err := taskIter.Err(); err != nil {
var gmpErr *commands.GMPError
if errors.As(err, &gmpErr) {
switch gmpErr.Type {
case commands.ErrorTypeAuthentication:
log.Fatal("Authentication failed:", gmpErr.StatusText)
case commands.ErrorTypeNotFound:
log.Println("No tasks found, continuing...")
case commands.ErrorTypeNetwork:
log.Println("Network error, will retry...")
// Implement retry logic here
default:
log.Printf("GMP error: %v", gmpErr)
}
} else {
// Handle non-GMP errors (e.g., network issues)
log.Printf("Unexpected error: %v", err)
}
}Send custom or unsupported commands:
raw := `<get_custom_resource foo="bar"/>`
resp, err := cli.RawXML(raw)All GMP commands are available as typed structs matching the protocol XML. Add new commands by following the existing pattern.
Based on github.com/filewalkwithme/go-gmp.