160 lines
3.3 KiB
Go
160 lines
3.3 KiB
Go
package collector
|
|
|
|
// Query combines filtering, sorting, and limiting into a single operation
|
|
type Query struct {
|
|
Filter FilterOptions
|
|
Sort SortOptions
|
|
Limit int
|
|
}
|
|
|
|
// NewQuery creates a query with sensible defaults
|
|
func NewQuery() *Query {
|
|
return &Query{
|
|
Filter: FilterOptions{},
|
|
Sort: SortOptions{Field: SortByLport, Direction: SortAsc},
|
|
Limit: 0,
|
|
}
|
|
}
|
|
|
|
// WithFilter sets the filter options
|
|
func (q *Query) WithFilter(f FilterOptions) *Query {
|
|
q.Filter = f
|
|
return q
|
|
}
|
|
|
|
// WithSort sets the sort options
|
|
func (q *Query) WithSort(s SortOptions) *Query {
|
|
q.Sort = s
|
|
return q
|
|
}
|
|
|
|
// WithSortString parses and sets sort options from a string like "pid:desc"
|
|
func (q *Query) WithSortString(s string) *Query {
|
|
q.Sort = ParseSortOptions(s)
|
|
return q
|
|
}
|
|
|
|
// WithLimit sets the maximum number of results
|
|
func (q *Query) WithLimit(n int) *Query {
|
|
q.Limit = n
|
|
return q
|
|
}
|
|
|
|
// Proto filters by protocol
|
|
func (q *Query) Proto(proto string) *Query {
|
|
q.Filter.Proto = proto
|
|
return q
|
|
}
|
|
|
|
// State filters by connection state
|
|
func (q *Query) State(state string) *Query {
|
|
q.Filter.State = state
|
|
return q
|
|
}
|
|
|
|
// Process filters by process name (substring match)
|
|
func (q *Query) Process(proc string) *Query {
|
|
q.Filter.Proc = proc
|
|
return q
|
|
}
|
|
|
|
// PID filters by process ID
|
|
func (q *Query) PID(pid int) *Query {
|
|
q.Filter.Pid = pid
|
|
return q
|
|
}
|
|
|
|
// LocalPort filters by local port
|
|
func (q *Query) LocalPort(port int) *Query {
|
|
q.Filter.Lport = port
|
|
return q
|
|
}
|
|
|
|
// RemotePort filters by remote port
|
|
func (q *Query) RemotePort(port int) *Query {
|
|
q.Filter.Rport = port
|
|
return q
|
|
}
|
|
|
|
// IPv4Only filters to only IPv4 connections
|
|
func (q *Query) IPv4Only() *Query {
|
|
q.Filter.IPv4 = true
|
|
q.Filter.IPv6 = false
|
|
return q
|
|
}
|
|
|
|
// IPv6Only filters to only IPv6 connections
|
|
func (q *Query) IPv6Only() *Query {
|
|
q.Filter.IPv4 = false
|
|
q.Filter.IPv6 = true
|
|
return q
|
|
}
|
|
|
|
// Listening filters to only listening sockets
|
|
func (q *Query) Listening() *Query {
|
|
q.Filter.State = "LISTEN"
|
|
return q
|
|
}
|
|
|
|
// Established filters to only established connections
|
|
func (q *Query) Established() *Query {
|
|
q.Filter.State = "ESTABLISHED"
|
|
return q
|
|
}
|
|
|
|
// Contains filters by substring in process, local addr, or remote addr
|
|
func (q *Query) Contains(s string) *Query {
|
|
q.Filter.Contains = s
|
|
return q
|
|
}
|
|
|
|
// Execute runs the query and returns results
|
|
func (q *Query) Execute() ([]Connection, error) {
|
|
conns, err := GetConnections()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return q.Apply(conns), nil
|
|
}
|
|
|
|
// Apply applies the query to a slice of connections
|
|
func (q *Query) Apply(conns []Connection) []Connection {
|
|
result := FilterConnections(conns, q.Filter)
|
|
SortConnections(result, q.Sort)
|
|
|
|
if q.Limit > 0 && len(result) > q.Limit {
|
|
result = result[:q.Limit]
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// common pre-built queries
|
|
|
|
// ListeningTCP returns a query for TCP listeners
|
|
func ListeningTCP() *Query {
|
|
return NewQuery().Proto("tcp").Listening()
|
|
}
|
|
|
|
// ListeningAll returns a query for all listeners
|
|
func ListeningAll() *Query {
|
|
return NewQuery().Listening()
|
|
}
|
|
|
|
// EstablishedTCP returns a query for established TCP connections
|
|
func EstablishedTCP() *Query {
|
|
return NewQuery().Proto("tcp").Established()
|
|
}
|
|
|
|
// ByProcess returns a query filtered by process name
|
|
func ByProcess(name string) *Query {
|
|
return NewQuery().Process(name)
|
|
}
|
|
|
|
// ByPort returns a query filtered by local port
|
|
func ByPort(port int) *Query {
|
|
return NewQuery().LocalPort(port)
|
|
}
|
|
|