| 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 |
| } |