blob: 68a1f51bde81463dd5eb0aabf06aa3c160b43817 [file] [log] [blame]
package provider
import (
"strings"
pb "code.hackerspace.pl/hscloud/bgpwtf/cccampix/proto"
)
// A raw, unparsed RPSL name/value pair.
type rpslRawAttribute struct {
name string
value string
}
// parseAttributes converts raw RPSL attributes into parsed, structured protos.
func parseAttributes(attrs []rpslRawAttribute) []*pb.IRRAttribute {
res := []*pb.IRRAttribute{}
for _, attr := range attrs {
switch attr.name {
case "remarks":
res = append(res, &pb.IRRAttribute{
Value: &pb.IRRAttribute_Remarks{attr.value},
})
case "import":
ie := parseImportExport(attr.value)
if ie != nil {
res = append(res, &pb.IRRAttribute{
Value: &pb.IRRAttribute_Import{ie},
})
}
case "export":
ie := parseImportExport(attr.value)
if ie != nil {
res = append(res, &pb.IRRAttribute{
Value: &pb.IRRAttribute_Export{ie},
})
}
}
}
return res
}
// parseImportExport tries to parse the RPSL subset for import/export
// attributes.
// It's a hand-written single-pass parser which makes it not very good.
// See rpsl_test.go for examples.
func parseImportExport(expression string) *pb.IRRAttribute_ImportExport {
popToken := func(s string) (string, string) {
s = strings.TrimSpace(s)
fields := strings.Fields(s)
if len(fields) < 2 {
return "", s
}
return fields[0], strings.TrimSpace(s[len(fields[0]):])
}
res := &pb.IRRAttribute_ImportExport{}
expr := expression
var t string
t, expr = popToken(expr)
for {
switch t {
case "":
break
case "protocol":
t, expr = popToken(expr)
res.ProtocolFrom = t
t, expr = popToken(expr)
continue
case "into":
t, expr = popToken(expr)
res.ProtocolInto = t
t, expr = popToken(expr)
continue
case "from":
fallthrough
case "to":
t, expr = popToken(expr)
peering := t
actions := []string{}
router_us := ""
router_them := ""
t2, expr2 := popToken(expr)
for {
switch t2 {
case "at":
t2, expr2 = popToken(expr2)
router_us = t2
t2, expr2 = popToken(expr2)
continue
case "action":
parts := strings.SplitN(expr2, ";", 2)
if len(parts) != 2 {
// malformed action, no ';' found - bail
return nil
}
actions = append(actions, parts[0])
expr2 = strings.TrimSpace(parts[1])
t2, expr2 = popToken(expr2)
continue
case "":
fallthrough
case "accept":
fallthrough
case "announce":
t = t2
expr = expr2
break
default:
if router_them == "" {
router_them = t2
t2, expr2 = popToken(expr2)
continue
}
t = t2
expr = expr2
break
}
break
}
res.Expressions = append(res.Expressions, &pb.IRRAttribute_ImportExport_Expression{
Peering: peering,
RouterUs: router_us,
RouterThem: router_them,
Actions: actions,
})
continue
case "accept":
fallthrough
case "announce":
res.Filter = expr
t = ""
continue
default:
return nil
}
break
}
return res
}