blob: 291494d0bceb9631e899bee16e99f09d8f951f3d [file] [log] [blame]
Sergiusz Bazanski6eaaaf92019-08-02 01:25:31 +02001package provider
2
3// Support for the RIPE IRR.
4// We use the RIPE REST DB API.
5
6import (
7 "context"
8 "encoding/json"
9 "fmt"
10 "io/ioutil"
11 "net/http"
12
13 pb "code.hackerspace.pl/hscloud/bgpwtf/cccampix/proto"
Sergiusz Bazanski2316ac02019-08-03 23:49:19 +020014 "google.golang.org/grpc/codes"
15 "google.golang.org/grpc/status"
Sergiusz Bazanski6eaaaf92019-08-02 01:25:31 +020016)
17
18type ripeResponse struct {
19 Objects struct {
20 Object []ripeObject `json:"object"`
21 } `json:"objects"`
22}
23
24type ripeObject struct {
25 Type string `json:"type"`
26 Attributes struct {
27 Attribute []ripeAttribute `json:"attribute"`
28 } `json:"attributes"`
29}
30
31type ripeAttribute struct {
32 Name string `json:"name"`
33 Value string `json:"value"`
34}
35
36type ripe struct {
Sergiusz Bazanski2316ac02019-08-03 23:49:19 +020037 sem chan struct{}
Sergiusz Bazanski6eaaaf92019-08-02 01:25:31 +020038}
39
Sergiusz Bazanski2316ac02019-08-03 23:49:19 +020040func NewRIPE(limit int) Provider {
41 return &ripe{
42 sem: make(chan struct{}, limit),
43 }
Sergiusz Bazanski6eaaaf92019-08-02 01:25:31 +020044}
45
46func (r *ripe) Query(ctx context.Context, as uint64) (*pb.IRRQueryResponse, error) {
Sergiusz Bazanski2316ac02019-08-03 23:49:19 +020047 r.sem <- struct{}{}
48 defer func() {
49 <-r.sem
50 }()
51
Sergiusz Bazanski6eaaaf92019-08-02 01:25:31 +020052 req, err := http.NewRequest("GET", fmt.Sprintf("http://rest.db.ripe.net/ripe/aut-num/AS%d.json", as), nil)
53 if err != nil {
54 return nil, err
55 }
56
57 req = req.WithContext(ctx)
58 client := http.DefaultClient
59
60 res, err := client.Do(req)
61 if err != nil {
Sergiusz Bazanski2316ac02019-08-03 23:49:19 +020062 return nil, status.Errorf(codes.Unavailable, "could not run GET to RIPE: %v", err)
Sergiusz Bazanski6eaaaf92019-08-02 01:25:31 +020063 }
64 defer res.Body.Close()
65 bytes, err := ioutil.ReadAll(res.Body)
66 if err != nil {
Sergiusz Bazanski2316ac02019-08-03 23:49:19 +020067 return nil, status.Errorf(codes.Unavailable, "could not read response from RIPE: %v", err)
Sergiusz Bazanski6eaaaf92019-08-02 01:25:31 +020068 }
69
70 data := ripeResponse{}
71 err = json.Unmarshal(bytes, &data)
72 if err != nil {
Sergiusz Bazanski2316ac02019-08-03 23:49:19 +020073 return nil, status.Errorf(codes.Unavailable, "could not decode response from RIPE: %v", err)
Sergiusz Bazanski6eaaaf92019-08-02 01:25:31 +020074 }
75
76 if len(data.Objects.Object) != 1 {
Sergiusz Bazanski2316ac02019-08-03 23:49:19 +020077 return nil, status.Error(codes.NotFound, "could not retrieve aut-num from RIPE")
Sergiusz Bazanski6eaaaf92019-08-02 01:25:31 +020078 }
79
80 attributes := make([]rpslRawAttribute, len(data.Objects.Object[0].Attributes.Attribute))
81
82 for i, attr := range data.Objects.Object[0].Attributes.Attribute {
83 attributes[i].name = attr.Name
84 attributes[i].value = attr.Value
85 }
86
87 return &pb.IRRQueryResponse{
88 Source: pb.IRRQueryResponse_SOURCE_RIPE,
89 Attributes: parseAttributes(attributes),
90 }, nil
91}