bgpwtf/cccampix: draw the rest of the fucking owl
Change-Id: I49fd5906e69512e8f2d414f406edc0179522f225
diff --git a/bgpwtf/cccampix/verifier/processor_rpki.go b/bgpwtf/cccampix/verifier/processor_rpki.go
new file mode 100644
index 0000000..b00aed2
--- /dev/null
+++ b/bgpwtf/cccampix/verifier/processor_rpki.go
@@ -0,0 +1,130 @@
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+
+ "code.hackerspace.pl/hscloud/bgpwtf/cccampix/verifier/model"
+ "github.com/golang/glog"
+)
+
+type rpki struct {
+ octorpki string
+}
+
+func newRPKI(octorpki string) (processor, error) {
+ return &rpki{
+ octorpki: octorpki,
+ }, nil
+}
+
+func (p *rpki) Name() string {
+ return "RPKI"
+}
+
+func (p *rpki) NextRun(now time.Time) time.Time {
+ return now.Add(1 * time.Minute)
+}
+
+type octorpkiRes struct {
+ Metadata struct {
+ Counts int64 `json:"counts"`
+ Generated int64 `json:"counts"`
+ Valid int64 `json:"counts"`
+ } `json:"metadata"`
+
+ ROAs []octorpkiROA `json:"roas"`
+}
+
+type octorpkiROA struct {
+ Prefix string `json:"prefix"`
+ MaxLength int64 `json:"maxLength"`
+ ASN string `json:"asn"`
+ TA string `json:"ta"`
+}
+
+func (p *rpki) RunAll(ctx context.Context, m model.Model) error {
+ peers, err := m.GetCheckablePeers(ctx)
+ if err != nil {
+ return err
+ }
+
+ wantASNs := make(map[string]bool)
+ for _, peer := range peers {
+ wantASNs[fmt.Sprintf("AS%d", peer.ASN)] = true
+ }
+
+ // Get RPKI data dump from OctoRPKI.
+ url := fmt.Sprintf("http://%s/output.json", p.octorpki)
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return fmt.Errorf("NewRequest(GET %q): %v", url, err)
+ }
+ req = req.WithContext(ctx)
+ client := http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return fmt.Errorf("GET %q: %v", url, err)
+ }
+ defer resp.Body.Close()
+
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return fmt.Errorf("GET %q: %v", url, err)
+ }
+
+ if strings.HasPrefix(string(data), "File not ready yet") {
+ return fmt.Errorf("OctoRPKI not yet ready")
+ }
+
+ var res octorpkiRes
+ if err := json.Unmarshal(data, &res); err != nil {
+ return fmt.Errorf("Could not decode OctoRPKI output: %v", err)
+ }
+
+ // Make list of prefixes we should honor.
+ prefixes := make(map[int64][]*model.AllowedPrefix)
+ for _, roa := range res.ROAs {
+ if !wantASNs[strings.ToUpper(roa.ASN)] {
+ continue
+ }
+
+ asn, err := strconv.ParseInt(roa.ASN[2:], 10, 64)
+ if err != nil {
+ glog.Errorf("Invalid ASN: %s %q", roa.ASN, roa.ASN)
+ continue
+ }
+
+ if _, ok := prefixes[asn]; !ok {
+ prefixes[asn] = []*model.AllowedPrefix{}
+ }
+
+ _, prefix, err := net.ParseCIDR(roa.Prefix)
+ if err != nil {
+ glog.Errorf("Invalid prefix: %s %q", roa.ASN, roa.Prefix)
+ continue
+ }
+
+ prefixes[asn] = append(prefixes[asn], &model.AllowedPrefix{
+ Prefix: *prefix,
+ MaxLength: roa.MaxLength,
+ TA: roa.TA,
+ })
+ }
+
+ for asn, p := range prefixes {
+ err := m.UpdateAllowedPrefixes(ctx, asn, p)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}