bgpwtf/cccampix: add IRR daemon
We add a small IRR service for getting a parsed RPSL from IRRs. For now,
we only support RIPE and ARIN, and only the following attributes:
- remarks
- import
- export
Since RPSL/RFC2622 is fucking insane, there is no guarantee that the
parser, especially the import/export parser, is correct. But it should
be good enough for our use. We even throw in some tests for good
measure.
$ grpcurl -format text -plaintext -d 'as: "26625"' 127.0.0.1:4200 ix.IRR.Query
source: SOURCE_ARIN
attributes: <
import: <
expressions: <
peering: "AS6083"
actions: "pref=10"
>
filter: "ANY"
>
>
attributes: <
import: <
expressions: <
peering: "AS12491"
actions: "pref=10"
>
filter: "ANY"
>
>
Change-Id: I8b240ffe2cd3553a25ce33dbd3917c0aef64e804
diff --git a/bgpwtf/cccampix/irr/provider/ripe.go b/bgpwtf/cccampix/irr/provider/ripe.go
new file mode 100644
index 0000000..5b09b9f
--- /dev/null
+++ b/bgpwtf/cccampix/irr/provider/ripe.go
@@ -0,0 +1,81 @@
+package provider
+
+// Support for the RIPE IRR.
+// We use the RIPE REST DB API.
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+
+ pb "code.hackerspace.pl/hscloud/bgpwtf/cccampix/proto"
+)
+
+type ripeResponse struct {
+ Objects struct {
+ Object []ripeObject `json:"object"`
+ } `json:"objects"`
+}
+
+type ripeObject struct {
+ Type string `json:"type"`
+ Attributes struct {
+ Attribute []ripeAttribute `json:"attribute"`
+ } `json:"attributes"`
+}
+
+type ripeAttribute struct {
+ Name string `json:"name"`
+ Value string `json:"value"`
+}
+
+type ripe struct {
+}
+
+func NewRIPE() Provider {
+ return &ripe{}
+}
+
+func (r *ripe) Query(ctx context.Context, as uint64) (*pb.IRRQueryResponse, error) {
+ req, err := http.NewRequest("GET", fmt.Sprintf("http://rest.db.ripe.net/ripe/aut-num/AS%d.json", as), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ req = req.WithContext(ctx)
+ client := http.DefaultClient
+
+ res, err := client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("could not run GET to RIPE: %v", err)
+ }
+ defer res.Body.Close()
+ bytes, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ return nil, fmt.Errorf("could not read response from RIPE: %v", err)
+ }
+
+ data := ripeResponse{}
+ err = json.Unmarshal(bytes, &data)
+ if err != nil {
+ return nil, fmt.Errorf("could not decode response from RIPE: %v", err)
+ }
+
+ if len(data.Objects.Object) != 1 {
+ return nil, fmt.Errorf("could not retriev aut-num from RIPE")
+ }
+
+ attributes := make([]rpslRawAttribute, len(data.Objects.Object[0].Attributes.Attribute))
+
+ for i, attr := range data.Objects.Object[0].Attributes.Attribute {
+ attributes[i].name = attr.Name
+ attributes[i].value = attr.Value
+ }
+
+ return &pb.IRRQueryResponse{
+ Source: pb.IRRQueryResponse_SOURCE_RIPE,
+ Attributes: parseAttributes(attributes),
+ }, nil
+}