mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
137 lines
3.8 KiB
Go
137 lines
3.8 KiB
Go
// SPDX-FileCopyrightText: 2022 Free Mobile
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
package console
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"akvorado/common/helpers"
|
|
"akvorado/console/filter"
|
|
)
|
|
|
|
type queryColumn int
|
|
|
|
func (qc queryColumn) MarshalText() ([]byte, error) {
|
|
got, ok := queryColumnMap.LoadValue(qc)
|
|
if ok {
|
|
return []byte(got), nil
|
|
}
|
|
return nil, errors.New("unknown field")
|
|
}
|
|
func (qc queryColumn) String() string {
|
|
got, _ := queryColumnMap.LoadValue(qc)
|
|
return got
|
|
}
|
|
func (qc *queryColumn) UnmarshalText(input []byte) error {
|
|
got, ok := queryColumnMap.LoadKey(string(input))
|
|
if ok {
|
|
*qc = got
|
|
return nil
|
|
}
|
|
return errors.New("unknown field")
|
|
}
|
|
|
|
// queryColumnsRequiringMainTable lists query columns only present in
|
|
// the main table. Also check filter/parser.peg.
|
|
var queryColumnsRequiringMainTable = map[queryColumn]struct{}{
|
|
queryColumnSrcAddr: {},
|
|
queryColumnDstAddr: {},
|
|
queryColumnSrcPort: {},
|
|
queryColumnDstPort: {},
|
|
queryColumnDstASPath: {},
|
|
}
|
|
|
|
func requireMainTable(qcs []queryColumn, qf queryFilter) bool {
|
|
if qf.MainTableRequired {
|
|
return true
|
|
}
|
|
for _, qc := range qcs {
|
|
if _, ok := queryColumnsRequiringMainTable[qc]; ok {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type queryFilter struct {
|
|
Filter string
|
|
ReverseFilter string
|
|
MainTableRequired bool
|
|
}
|
|
|
|
func (qf queryFilter) String() string {
|
|
return qf.Filter
|
|
}
|
|
func (qf queryFilter) MarshalText() ([]byte, error) {
|
|
return []byte(qf.Filter), nil
|
|
}
|
|
func (qf *queryFilter) UnmarshalText(input []byte) error {
|
|
if strings.TrimSpace(string(input)) == "" {
|
|
*qf = queryFilter{}
|
|
return nil
|
|
}
|
|
meta := &filter.Meta{}
|
|
direct, err := filter.Parse("", input, filter.GlobalStore("meta", meta))
|
|
if err != nil {
|
|
return fmt.Errorf("cannot parse filter: %s", filter.HumanError(err))
|
|
}
|
|
meta = &filter.Meta{ReverseDirection: true}
|
|
reverse, err := filter.Parse("", input, filter.GlobalStore("meta", meta))
|
|
if err != nil {
|
|
return fmt.Errorf("cannot parse reverse filter: %s", filter.HumanError(err))
|
|
}
|
|
*qf = queryFilter{
|
|
Filter: direct.(string),
|
|
ReverseFilter: reverse.(string),
|
|
MainTableRequired: meta.MainTableRequired,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// toSQLSelect transforms a column into an expression to use in SELECT
|
|
func (qc queryColumn) toSQLSelect() string {
|
|
var strValue string
|
|
switch qc {
|
|
case queryColumnExporterAddress, queryColumnSrcAddr, queryColumnDstAddr:
|
|
strValue = fmt.Sprintf("replaceRegexpOne(IPv6NumToString(%s), '^::ffff:', '')", qc)
|
|
case queryColumnSrcAS, queryColumnDstAS, queryColumnDst1stAS, queryColumnDst2ndAS, queryColumnDst3rdAS:
|
|
strValue = fmt.Sprintf(`concat(toString(%s), ': ', dictGetOrDefault('asns', 'name', %s, '???'))`,
|
|
qc, qc)
|
|
case queryColumnEType:
|
|
strValue = fmt.Sprintf(`if(EType = %d, 'IPv4', if(EType = %d, 'IPv6', '???'))`,
|
|
helpers.ETypeIPv4, helpers.ETypeIPv6)
|
|
case queryColumnProto:
|
|
strValue = `dictGetOrDefault('protocols', 'name', Proto, '???')`
|
|
case queryColumnInIfSpeed, queryColumnOutIfSpeed, queryColumnSrcPort, queryColumnDstPort, queryColumnForwardingStatus, queryColumnInIfBoundary, queryColumnOutIfBoundary:
|
|
strValue = fmt.Sprintf("toString(%s)", qc)
|
|
case queryColumnDstASPath:
|
|
strValue = `arrayStringConcat(DstASPath, ' ')`
|
|
default:
|
|
strValue = qc.String()
|
|
}
|
|
return strValue
|
|
}
|
|
|
|
// reverseDirection reverse the direction of a column (src/dst, in/out)
|
|
func (qc queryColumn) reverseDirection() queryColumn {
|
|
value, ok := queryColumnMap.LoadKey(filter.ReverseColumnDirection(qc.String()))
|
|
if !ok {
|
|
panic("unknown reverse column")
|
|
}
|
|
return value
|
|
}
|
|
|
|
// fixQueryColumnName fix capitalization of the provided column name
|
|
func fixQueryColumnName(name string) string {
|
|
name = strings.ToLower(name)
|
|
for _, target := range queryColumnMap.Values() {
|
|
if strings.ToLower(target) == name {
|
|
return target
|
|
}
|
|
}
|
|
return ""
|
|
}
|