console/filter: add completion endpoint

This commit is contained in:
Vincent Bernat
2022-05-26 15:58:52 +02:00
parent dc39c2dc14
commit 4114568600
12 changed files with 366 additions and 25 deletions

View File

@@ -85,7 +85,7 @@ func TestHTTPEndpoints(t *testing.T, serverAddr net.Addr, cases HTTPEndpointCase
tc.StatusCode = 200 tc.StatusCode = 200
} }
if resp.StatusCode != tc.StatusCode { if resp.StatusCode != tc.StatusCode {
t.Fatalf("GET %s: got status code %d, not %d", tc.URL, t.Errorf("GET %s: got status code %d, not %d", tc.URL,
resp.StatusCode, tc.StatusCode) resp.StatusCode, tc.StatusCode)
} }
if tc.JSONOutput != nil { if tc.JSONOutput != nil {

View File

@@ -132,8 +132,8 @@ guaranteed, so an URL may stop working after a few upgrades.
The filter language looks like SQL with a few variations. Fields The filter language looks like SQL with a few variations. Fields
listed as dimensions can usually be used. Accepted operators are `=`, listed as dimensions can usually be used. Accepted operators are `=`,
`!=`, `<`, `<=`, `>`, `>=`, `IN`, `LIKE`, `ILIKE`, when they make `!=`, `<`, `<=`, `>`, `>=`, `IN`, `NOTIN`, `LIKE`, `UNLIKE`, `ILIKE`,
sense. Here are a few examples: `IUNLIKE`, when they make sense. Here are a few examples:
- `InIfBoundary = external` only selects flows whose incoming - `InIfBoundary = external` only selects flows whose incoming
interface was classified as external. The value should not be interface was classified as external. The value should not be

View File

@@ -1,7 +1,9 @@
package console package console
import ( import (
"fmt"
"net/http" "net/http"
"strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -11,7 +13,7 @@ import (
// filterValidateHandlerInput describes the input for the /filter/validate endpoint. // filterValidateHandlerInput describes the input for the /filter/validate endpoint.
type filterValidateHandlerInput struct { type filterValidateHandlerInput struct {
Filter string `json:"filter"` Filter string `json:"filter" binding:"required"`
} }
// filterValidateHandlerOutput describes the output for the /filter/validate endpoint. // filterValidateHandlerOutput describes the output for the /filter/validate endpoint.
@@ -41,3 +43,185 @@ func (c *Component) filterValidateHandlerFunc(gc *gin.Context) {
Errors: filter.AllErrors(err), Errors: filter.AllErrors(err),
}) })
} }
// filterCompleteHandlerInput describes the input of the /filter/complete endpoint.
type filterCompleteHandlerInput struct {
What string `json:"what" binding:"required,oneof=column operator value"`
Column string `json:"column" binding:"required_unless=What column"`
Prefix string `json:"prefix"`
}
// filterCompleteHandlerOutput describes the output of the /filter/complete endpoint.
type filterCompleteHandlerOutput struct {
Completions []filterCompletion `json:"completions"`
}
type filterCompletion struct {
Label string `json:"label"`
Detail string `json:"detail,omitempty"`
Quoted bool `json:"quoted"` // should the return value be quoted?
}
func (c *Component) filterCompleteHandlerFunc(gc *gin.Context) {
ctx := c.t.Context(gc.Request.Context())
var input filterCompleteHandlerInput
if err := gc.ShouldBindJSON(&input); err != nil {
gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())})
return
}
completions := []filterCompletion{}
switch input.What {
case "column":
_, err := filter.Parse("", []byte{}, filter.Entrypoint("ConditionExpr"))
if err != nil {
for _, candidate := range filter.Expected(err) {
if !strings.HasSuffix(candidate, `"i`) {
continue
}
candidate = candidate[1 : len(candidate)-2]
completions = append(completions, filterCompletion{
Label: candidate,
Detail: "column name",
})
}
}
case "operator":
_, err := filter.Parse("",
[]byte(fmt.Sprintf("%s ", input.Column)),
filter.Entrypoint("ConditionExpr"))
if err != nil {
for _, candidate := range filter.Expected(err) {
if !strings.HasPrefix(candidate, `"`) {
continue
}
candidate = strings.TrimSuffix(
strings.TrimSuffix(candidate[1:len(candidate)-1], `"i`),
`"`)
if candidate != "--" && candidate != "/*" {
completions = append(completions, filterCompletion{
Label: candidate,
Detail: "condition operator",
})
}
}
}
case "value":
var column, detail string
switch strings.ToLower(input.Column) {
case "inifboundary", "outifboundary":
completions = append(completions, filterCompletion{
Label: "internal",
Detail: "network boundary",
}, filterCompletion{
Label: "external",
Detail: "network boundary",
}, filterCompletion{
Label: "undefined",
Detail: "network boundary",
})
case "etype":
completions = append(completions, filterCompletion{
Label: "IPv4",
Detail: "ethernet type",
}, filterCompletion{
Label: "IPv6",
Detail: "ethernet type",
})
case "proto":
// Do not complete from Clickhouse, we want a subset of options
completions = append(completions,
filterCompletion{"TCP", "protocol", true},
filterCompletion{"UDP", "protocol", true},
filterCompletion{"SCTP", "protocol", true},
filterCompletion{"ICMP", "protocol", true},
filterCompletion{"IPv6-ICMP", "protocol", true},
filterCompletion{"GRE", "protocol", true},
filterCompletion{"ESP", "protocol", true},
filterCompletion{"AH", "protocol", true},
filterCompletion{"IPIP", "protocol", true},
filterCompletion{"VRRP", "protocol", true},
filterCompletion{"L2TP", "protocol", true},
filterCompletion{"IGMP", "protocol", true},
filterCompletion{"PIM", "protocol", true},
filterCompletion{"IPv4", "protocol", true},
filterCompletion{"IPv6", "protocol", true})
case "srcas", "dstas":
// Query "asns" dictionary if we have at last 3 letters as a prefix
if len(input.Prefix) >= 3 {
sqlQuery := `
SELECT concat('AS', toString(asn)) AS label, detail
FROM asns
WHERE positionCaseInsensitive(name, $1) >= 1
ORDER BY positionCaseInsensitive(name, $1) ASC, asn ASC
LIMIT 20`
results := []struct {
Label string `ch:"label"`
Detail string `ch:"detail"`
}{}
if err := c.d.ClickHouseDB.Conn.Select(ctx, &results, sqlQuery, input.Prefix); err != nil {
c.r.Err(err).Msg("unable to query database")
break
}
for _, result := range results {
completions = append(completions, filterCompletion{
Label: result.Label,
Detail: result.Detail,
Quoted: false,
})
}
}
input.Prefix = "" // We have handled this internally
case "exportername":
column = "ExporterName"
detail = "exporter name"
case "exportergroup":
column = "ExporterGroup"
detail = "exporter group"
case "inifname", "outifname":
column = "IfName"
detail = "interface name"
case "inifdescription", "outifdescription":
column = "IfDescription"
detail = "interface description"
case "inifconnectivity", "outifconnectivity":
column = "IfConnectivity"
detail = "connectivity type"
case "inifprovider", "outifprovider":
column = "IfProvider"
detail = "provider name"
}
if column != "" {
// Query "exporter" table
sqlQuery := fmt.Sprintf(`
SELECT %s AS label
FROM exporters
WHERE positionCaseInsensitive(%s, $1) >= 1
GROUP BY %s
ORDER BY positionCaseInsensitive(%s, $1) ASC, %s ASC
LIMIT 20`, column, column, column, column, column)
results := []struct {
Label string `ch:"label"`
}{}
if err := c.d.ClickHouseDB.Conn.Select(ctx, &results, sqlQuery, input.Prefix); err != nil {
c.r.Err(err).Msg("unable to query database")
break
}
for _, result := range results {
completions = append(completions, filterCompletion{
Label: result.Label,
Detail: detail,
Quoted: true,
})
}
input.Prefix = ""
}
}
filteredCompletions := []filterCompletion{}
for _, completion := range completions {
if strings.HasPrefix(strings.ToLower(completion.Label), strings.ToLower(input.Prefix)) {
filteredCompletions = append(filteredCompletions, completion)
}
}
gc.JSON(http.StatusOK, filterCompleteHandlerOutput{filteredCompletions})
return
}

View File

@@ -48,3 +48,20 @@ func AllErrors(err error) Errors {
} }
return errs return errs
} }
// Expected returns a list of expected strings from the first error.
func Expected(err error) []string {
el, ok := err.(errList)
if !ok {
return nil
}
if len(el) == 0 {
return nil
}
switch e := el[0].(type) {
case *parserError:
return e.expected
default:
return nil
}
}

View File

@@ -35,3 +35,11 @@ OR`))
t.Errorf("AllErrors() (-got, +want):\n%s", diff) t.Errorf("AllErrors() (-got, +want):\n%s", diff)
} }
} }
func TestExpected(t *testing.T) {
_, err := Parse("", []byte{}, Entrypoint("ConditionBoundaryExpr"))
expected := []string{`"InIfBoundary"i`, `"OutIfBoundary"i`}
if diff := helpers.Diff(Expected(err), expected); diff != "" {
t.Errorf("AllErrors() (-got, +want):\n%s", diff)
}
}

View File

@@ -89,7 +89,7 @@ ConditionBoundaryExpr "condition on boundary" ←
column:("InIfBoundary"i { return "InIfBoundary", nil } column:("InIfBoundary"i { return "InIfBoundary", nil }
/ "OutIfBoundary"i { return "OutIfBoundary", nil }) _ / "OutIfBoundary"i { return "OutIfBoundary", nil }) _
operator:("=" / "!=") _ operator:("=" / "!=") _
boundary:("external"i / "internal"i) { boundary:("external"i / "internal"i / "undefined"i) {
return fmt.Sprintf("%s %s %s", toString(column), toString(operator), return fmt.Sprintf("%s %s %s", toString(column), toString(operator),
quote(strings.ToLower(toString(boundary)))), nil quote(strings.ToLower(toString(boundary)))), nil
} }
@@ -208,17 +208,20 @@ Unsigned64 "unsigned 64-bit integer" ← [0-9]+ !IdentStart {
LikeOperator "LIKE operators" ← LikeOperator "LIKE operators" ←
KW_LIKE KW_LIKE
/ KW_ILIKE / KW_ILIKE
/ (KW_NOT _ KW_LIKE) { return "NOT LIKE", nil } / KW_UNLIKE
/ (KW_NOT _ KW_ILIKE) { return "NOT ILIKE", nil } / KW_IUNLIKE
InOperator "IN operators" ← InOperator "IN operators" ←
KW_IN KW_IN
/ (KW_NOT _ KW_IN) { return "NOT IN", nil } / KW_NOTIN
KW_AND "AND operator" ← "AND"i !IdentStart { return "AND", nil } KW_AND "AND operator" ← "AND"i !IdentStart { return "AND", nil }
KW_OR "OR operator" ← "OR"i !IdentStart { return "OR", nil } KW_OR "OR operator" ← "OR"i !IdentStart { return "OR", nil }
KW_NOT "NOT operator" ← "NOT"i !IdentStart { return "NOT", nil } KW_NOT "NOT operator" ← "NOT"i !IdentStart { return "NOT", nil }
KW_LIKE "LIKE operator" ← "LIKE"i !IdentStart { return "LIKE", nil } KW_LIKE "LIKE operator" ← "LIKE"i !IdentStart { return "LIKE", nil }
KW_ILIKE "ILIKE operator" ← "ILIKE"i !IdentStart { return "ILIKE", nil } KW_ILIKE "ILIKE operator" ← "ILIKE"i !IdentStart { return "ILIKE", nil }
KW_IN "IN operator" ← "IN"i !IdentStart { return "IN", nil } KW_IN "IN operator" ← "IN"i !IdentStart { return "IN", nil }
KW_UNLIKE "UNLIKE operator" ← "UNLIKE"i !IdentStart { return "NOT LIKE", nil }
KW_IUNLIKE "IUNLIKE operator" ← "IUNLIKE"i !IdentStart { return "NOT ILIKE", nil }
KW_NOTIN "NOTIN operator" ← "NOTIN"i !IdentStart { return "NOT IN", nil }
SingleLineComment "comment" ← "--" ( !EOL SourceChar )* SingleLineComment "comment" ← "--" ( !EOL SourceChar )*
MultiLineComment ← "/*" ( !"*/" SourceChar )* ("*/" / EOF { MultiLineComment ← "/*" ( !"*/" SourceChar )* ("*/" / EOF {

View File

@@ -19,9 +19,8 @@ func TestValidFilter(t *testing.T) {
{`ExporterName="something\"`, `ExporterName = 'something\\'`}, {`ExporterName="something\"`, `ExporterName = 'something\\'`},
{`ExporterName!="something"`, `ExporterName != 'something'`}, {`ExporterName!="something"`, `ExporterName != 'something'`},
{`ExporterName LIKE "something%"`, `ExporterName LIKE 'something%'`}, {`ExporterName LIKE "something%"`, `ExporterName LIKE 'something%'`},
{`ExporterName NOT LIKE "something%"`, `ExporterName NOT LIKE 'something%'`}, {`ExporterName UNLIKE "something%"`, `ExporterName NOT LIKE 'something%'`},
{`ExporterName ILIKE "something%"`, `ExporterName ILIKE 'something%'`}, {`ExporterName IUNLIKE "something%"`, `ExporterName NOT ILIKE 'something%'`},
{`ExporterName not ILIKE "something%"`, `ExporterName NOT ILIKE 'something%'`},
{`ExporterName="something with spaces"`, `ExporterName = 'something with spaces'`}, {`ExporterName="something with spaces"`, `ExporterName = 'something with spaces'`},
{`ExporterName="something with 'quotes'"`, `ExporterName = 'something with \'quotes\''`}, {`ExporterName="something with 'quotes'"`, `ExporterName = 'something with \'quotes\''`},
{`ExporterAddress=203.0.113.1`, `ExporterAddress = IPv6StringToNum('203.0.113.1')`}, {`ExporterAddress=203.0.113.1`, `ExporterAddress = IPv6StringToNum('203.0.113.1')`},
@@ -34,8 +33,8 @@ func TestValidFilter(t *testing.T) {
{`SrcAS=AS12322`, `SrcAS = 12322`}, {`SrcAS=AS12322`, `SrcAS = 12322`},
{`SrcAS=as12322`, `SrcAS = 12322`}, {`SrcAS=as12322`, `SrcAS = 12322`},
{`SrcAS IN(12322, 29447)`, `SrcAS IN (12322, 29447)`}, {`SrcAS IN(12322, 29447)`, `SrcAS IN (12322, 29447)`},
{`SrcAS NOT IN(12322, 29447)`, `SrcAS NOT IN (12322, 29447)`}, {`SrcAS NOTIN(12322, 29447)`, `SrcAS NOT IN (12322, 29447)`},
{`SrcAS NOT IN (AS12322, 29447)`, `SrcAS NOT IN (12322, 29447)`}, {`SrcAS NOTIN (AS12322, 29447)`, `SrcAS NOT IN (12322, 29447)`},
{`DstAS=12322`, `DstAS = 12322`}, {`DstAS=12322`, `DstAS = 12322`},
{`SrcCountry='FR'`, `SrcCountry = 'FR'`}, {`SrcCountry='FR'`, `SrcCountry = 'FR'`},
{`DstCountry='FR'`, `DstCountry = 'FR'`}, {`DstCountry='FR'`, `DstCountry = 'FR'`},

View File

@@ -4,6 +4,7 @@ import (
"testing" "testing"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/golang/mock/gomock"
"akvorado/common/clickhousedb" "akvorado/common/clickhousedb"
"akvorado/common/daemon" "akvorado/common/daemon"
@@ -14,7 +15,7 @@ import (
func TestFilterHandlers(t *testing.T) { func TestFilterHandlers(t *testing.T) {
r := reporter.NewMock(t) r := reporter.NewMock(t)
ch, _ := clickhousedb.NewMock(t, r) ch, mockConn := clickhousedb.NewMock(t, r)
h := http.NewMock(t, r) h := http.NewMock(t, r)
c, err := New(r, Configuration{}, Dependencies{ c, err := New(r, Configuration{}, Dependencies{
Daemon: daemon.NewMock(t), Daemon: daemon.NewMock(t),
@@ -26,6 +27,48 @@ func TestFilterHandlers(t *testing.T) {
} }
helpers.StartStop(t, c) helpers.StartStop(t, c)
mockConn.EXPECT().
Select(gomock.Any(), gomock.Any(), `
SELECT ExporterName AS label
FROM exporters
WHERE positionCaseInsensitive(ExporterName, $1) >= 1
GROUP BY ExporterName
ORDER BY positionCaseInsensitive(ExporterName, $1) ASC, ExporterName ASC
LIMIT 20`,
"th2-").
SetArg(1, []struct {
Label string `ch:"label"`
}{
{"th2-router1"},
{"th2-router2"},
{"th2-router3"}}).
Return(nil)
mockConn.EXPECT().
Select(gomock.Any(), gomock.Any(), `
SELECT concat('AS', toString(asn)) AS label, detail
FROM asns
WHERE positionCaseInsensitive(name, $1) >= 1
ORDER BY positionCaseInsensitive(name, $1) ASC, asn ASC
LIMIT 20`,
"goog").
SetArg(1, []struct {
Label string `ch:"label"`
Detail string `ch:"detail"`
}{
{"AS15169", "Google"},
{"AS16550", "Google Private Cloud"},
{"AS16591", "Google Fiber"},
{"AS19527", "Google"},
{"AS26910", "GOOGLE-CLOUD-2"},
{"AS36040", "Google"},
{"AS36384", "Google"},
{"AS36385", "Google IT"},
{"AS36492", "Google"},
{"AS36987", "Google Kenya"},
{"AS41264", "Google Switzerland"},
}).
Return(nil)
helpers.TestHTTPEndpoints(t, h.Address, helpers.HTTPEndpointCases{ helpers.TestHTTPEndpoints(t, h.Address, helpers.HTTPEndpointCases{
{ {
URL: "/api/v0/console/filter/validate", URL: "/api/v0/console/filter/validate",
@@ -47,6 +90,83 @@ func TestFilterHandlers(t *testing.T) {
"message": "string literal not terminated", "message": "string literal not terminated",
}}, }},
}, },
}, {
URL: "/api/v0/console/filter/complete",
StatusCode: 200,
JSONInput: gin.H{"what": "column", "prefix": "dSt"},
JSONOutput: gin.H{"completions": []gin.H{
{"label": "DstAS", "detail": "column name", "quoted": false},
{"label": "DstAddr", "detail": "column name", "quoted": false},
{"label": "DstCountry", "detail": "column name", "quoted": false},
{"label": "DstPort", "detail": "column name", "quoted": false},
}},
}, {
URL: "/api/v0/console/filter/complete",
StatusCode: 200,
JSONInput: gin.H{"what": "operator", "column": "ExporterName"},
JSONOutput: gin.H{"completions": []gin.H{
{"label": "!=", "detail": "condition operator", "quoted": false},
{"label": "=", "detail": "condition operator", "quoted": false},
{"label": "ILIKE", "detail": "condition operator", "quoted": false},
{"label": "IUNLIKE", "detail": "condition operator", "quoted": false},
{"label": "LIKE", "detail": "condition operator", "quoted": false},
{"label": "UNLIKE", "detail": "condition operator", "quoted": false},
}},
}, {
URL: "/api/v0/console/filter/complete",
StatusCode: 200,
JSONInput: gin.H{"what": "value", "column": "outifboundary"},
JSONOutput: gin.H{"completions": []gin.H{
{"label": "internal", "detail": "network boundary", "quoted": false},
{"label": "external", "detail": "network boundary", "quoted": false},
{"label": "undefined", "detail": "network boundary", "quoted": false},
}},
}, {
URL: "/api/v0/console/filter/complete",
StatusCode: 200,
JSONInput: gin.H{"what": "value", "column": "etype"},
JSONOutput: gin.H{"completions": []gin.H{
{"label": "IPv4", "detail": "ethernet type", "quoted": false},
{"label": "IPv6", "detail": "ethernet type", "quoted": false},
}},
}, {
URL: "/api/v0/console/filter/complete",
StatusCode: 200,
JSONInput: gin.H{"what": "value", "column": "proto", "prefix": "I"},
JSONOutput: gin.H{"completions": []gin.H{
{"label": "ICMP", "detail": "protocol", "quoted": true},
{"label": "IPv6-ICMP", "detail": "protocol", "quoted": true},
{"label": "IPIP", "detail": "protocol", "quoted": true},
{"label": "IGMP", "detail": "protocol", "quoted": true},
{"label": "IPv4", "detail": "protocol", "quoted": true},
{"label": "IPv6", "detail": "protocol", "quoted": true},
}},
}, {
URL: "/api/v0/console/filter/complete",
StatusCode: 200,
JSONInput: gin.H{"what": "value", "column": "exportername", "prefix": "th2-"},
JSONOutput: gin.H{"completions": []gin.H{
{"label": "th2-router1", "detail": "exporter name", "quoted": true},
{"label": "th2-router2", "detail": "exporter name", "quoted": true},
{"label": "th2-router3", "detail": "exporter name", "quoted": true},
}},
}, {
URL: "/api/v0/console/filter/complete",
StatusCode: 200,
JSONInput: gin.H{"what": "value", "column": "srcAS", "prefix": "goog"},
JSONOutput: gin.H{"completions": []gin.H{
{"label": "AS15169", "detail": "Google", "quoted": false},
{"label": "AS16550", "detail": "Google Private Cloud", "quoted": false},
{"label": "AS16591", "detail": "Google Fiber", "quoted": false},
{"label": "AS19527", "detail": "Google", "quoted": false},
{"label": "AS26910", "detail": "GOOGLE-CLOUD-2", "quoted": false},
{"label": "AS36040", "detail": "Google", "quoted": false},
{"label": "AS36384", "detail": "Google", "quoted": false},
{"label": "AS36385", "detail": "Google IT", "quoted": false},
{"label": "AS36492", "detail": "Google", "quoted": false},
{"label": "AS36987", "detail": "Google Kenya", "quoted": false},
{"label": "AS41264", "detail": "Google Switzerland", "quoted": false},
}},
}, },
}) })
} }

View File

@@ -84,6 +84,7 @@ func (c *Component) Start() error {
c.d.HTTP.GinRouter.POST("/api/v0/console/graph", c.graphHandlerFunc) c.d.HTTP.GinRouter.POST("/api/v0/console/graph", c.graphHandlerFunc)
c.d.HTTP.GinRouter.POST("/api/v0/console/sankey", c.sankeyHandlerFunc) c.d.HTTP.GinRouter.POST("/api/v0/console/sankey", c.sankeyHandlerFunc)
c.d.HTTP.GinRouter.POST("/api/v0/console/filter/validate", c.filterValidateHandlerFunc) c.d.HTTP.GinRouter.POST("/api/v0/console/filter/validate", c.filterValidateHandlerFunc)
c.d.HTTP.GinRouter.POST("/api/v0/console/filter/complete", c.filterCompleteHandlerFunc)
c.t.Go(func() error { c.t.Go(func() error {
ticker := time.NewTicker(10 * time.Second) ticker := time.NewTicker(10 * time.Second)

9
go.mod
View File

@@ -45,9 +45,9 @@ require (
github.com/eapache/queue v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect github.com/go-playground/validator/v10 v10.11.0 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
@@ -62,7 +62,7 @@ require (
github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.1 // indirect github.com/klauspost/compress v1.15.1 // indirect
github.com/leodido/go-urn v1.2.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -84,6 +84,7 @@ require (
go.opentelemetry.io/otel/trace v1.4.1 // indirect go.opentelemetry.io/otel/trace v1.4.1 // indirect
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/text v0.3.7 // indirect
) )
replace github.com/slayercat/gosnmp => github.com/slayercat/gosnmp v1.24.1-0.20220124233957-4b805977d286 replace github.com/slayercat/gosnmp => github.com/slayercat/gosnmp v1.24.1-0.20220124233957-4b805977d286

18
go.sum
View File

@@ -171,12 +171,15 @@ github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw=
github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -355,8 +358,9 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
@@ -417,6 +421,7 @@ github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9F
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -458,8 +463,9 @@ github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShE
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
@@ -558,6 +564,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s= golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s=
@@ -761,6 +768,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View File

@@ -5,7 +5,7 @@ proto,name,description
3,GGP,Gateway-to-Gateway 3,GGP,Gateway-to-Gateway
4,IPv4,IPv4 encapsulation 4,IPv4,IPv4 encapsulation
5,ST,Stream 5,ST,Stream
6,TCP,Transmission Control 6,TCP,Transmission Control Protocol
7,CBT,CBT 7,CBT,CBT
8,EGP,Exterior Gateway Protocol 8,EGP,Exterior Gateway Protocol
10,BBN-RCC-MON,BBN RCC Monitoring 10,BBN-RCC-MON,BBN RCC Monitoring
@@ -14,7 +14,7 @@ proto,name,description
14,EMCON,EMCON 14,EMCON,EMCON
15,XNET,Cross Net Debugger 15,XNET,Cross Net Debugger
16,CHAOS,Chaos 16,CHAOS,Chaos
17,UDP,User Datagram 17,UDP,User Datagram Protocol
18,MUX,Multiplexing 18,MUX,Multiplexing
19,DCN-MEAS,DCN Measurement Subsystems 19,DCN-MEAS,DCN Measurement Subsystems
20,HMP,Host Monitoring 20,HMP,Host Monitoring
1 proto name description
5 3 GGP Gateway-to-Gateway
6 4 IPv4 IPv4 encapsulation
7 5 ST Stream
8 6 TCP Transmission Control Transmission Control Protocol
9 7 CBT CBT
10 8 EGP Exterior Gateway Protocol
11 10 BBN-RCC-MON BBN RCC Monitoring
14 14 EMCON EMCON
15 15 XNET Cross Net Debugger
16 16 CHAOS Chaos
17 17 UDP User Datagram User Datagram Protocol
18 18 MUX Multiplexing
19 19 DCN-MEAS DCN Measurement Subsystems
20 20 HMP Host Monitoring