blob: 291494d0bceb9631e899bee16e99f09d8f951f3d [file] [log] [blame]
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"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
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 {
sem chan struct{}
}
func NewRIPE(limit int) Provider {
return &ripe{
sem: make(chan struct{}, limit),
}
}
func (r *ripe) Query(ctx context.Context, as uint64) (*pb.IRRQueryResponse, error) {
r.sem <- struct{}{}
defer func() {
<-r.sem
}()
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, status.Errorf(codes.Unavailable, "could not run GET to RIPE: %v", err)
}
defer res.Body.Close()
bytes, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, status.Errorf(codes.Unavailable, "could not read response from RIPE: %v", err)
}
data := ripeResponse{}
err = json.Unmarshal(bytes, &data)
if err != nil {
return nil, status.Errorf(codes.Unavailable, "could not decode response from RIPE: %v", err)
}
if len(data.Objects.Object) != 1 {
return nil, status.Error(codes.NotFound, "could not retrieve 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
}