blob: f4558448c6a05a8361e235a651f048636a2d1d15 [file] [log] [blame]
package main
import (
"context"
"crypto/x509"
"flag"
"fmt"
"sort"
"strings"
pb "code.hackerspace.pl/hscloud/bgpwtf/cccampix/proto"
"github.com/golang/glog"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
var (
flagVerifier string
flagIdentity string
flagRouterID string
flagV6 bool
flagLocalIP string
)
func init() {
flag.Set("logtostderr", "true")
}
func main() {
flag.StringVar(&flagVerifier, "verifier", "", "Verifier endpoint")
flag.StringVar(&flagIdentity, "identity", "", "Router identity")
flag.StringVar(&flagRouterID, "router_id", "", "Router ID")
flag.StringVar(&flagLocalIP, "local_ip", "", "Local IP")
flag.BoolVar(&flagV6, "v6", false, "V6")
flag.Parse()
if flagVerifier == "" {
glog.Exit("verifier must be set")
}
if flagIdentity == "" {
glog.Exit("identity must be set")
}
if flagRouterID == "" {
glog.Exit("router_id must be set")
}
cpool, _ := x509.SystemCertPool()
creds := credentials.NewClientTLSFromCert(cpool, "")
conn, err := grpc.Dial(flagVerifier, grpc.WithTransportCredentials(creds))
if err != nil {
glog.Exitf("Dial: %v", err)
}
ctx := context.Background()
verifier := pb.NewVerifierClient(conn)
req := &pb.RouterHeartbeatRequest{
Name: flagIdentity,
}
res, err := verifier.RouterHeartbeat(ctx, req)
if err != nil {
glog.Exitf("RouterHeartbeat: %v", err)
}
var config string
if flagV6 {
config = `
log syslog all;
router id %s;
debug protocols { states, interfaces, events };
timeformat base iso long;
timeformat log iso long;
timeformat protocol iso long;
timeformat route iso long;
protocol device {}
function net_martians() {
return net ~ [ fc00::/7+, fec0::/10+, ::/128-, ::/0{0,15}, ::/0{49,128} ];
}
function generic_in() {
if net_martians() then return false;
if bgp_path.len > 64 then return false;
if net.len > 64 then return false;
if net.len < 12 then return false;
return true;
}
`
config = fmt.Sprintf(config, flagRouterID)
} else {
config = `
log syslog all;
router id %s;
debug protocols { states, interfaces, events };
timeformat base iso long;
timeformat log iso long;
timeformat protocol iso long;
timeformat route iso long;
protocol device {}
function net_martians() {
return net ~ [ 169.254.0.0/16+, 172.16.0.0/12+, 192.168.0.0/16+, 10.0.0.0/8+,
127.0.0.0/8+, 224.0.0.0/4+, 240.0.0.0/4+, 0.0.0.0/32-, 0.0.0.0/0{25,32}, 0.0.0.0/0{0,7} ];
}
function generic_in() {
if net_martians() then return false;
if bgp_path.len > 64 then return false;
if net.len > 24 then return false;
if net.len < 8 then return false;
return true;
}
`
config = fmt.Sprintf(config, flagRouterID)
}
sort.Slice(res.AsConfigs, func(i, j int) bool {
return res.AsConfigs[i].Asn < res.AsConfigs[j].Asn
})
for _, asc := range res.AsConfigs {
sort.Slice(asc.Routers, func(i, j int) bool {
return asc.Routers[i].Password < asc.Routers[j].Password
})
for i, router := range asc.Routers {
addr := ""
if flagV6 {
addr = router.Ipv6
} else {
addr = router.Ipv4
}
if addr == "" {
continue
}
peerid := fmt.Sprintf("PEER_%d_%d", asc.Asn, i)
prefixes := []string{}
for _, prefix := range asc.Prefixes {
if flagV6 && !strings.Contains(prefix.Prefix, ":") {
continue
}
if !flagV6 && !strings.Contains(prefix.Prefix, ".") {
continue
}
parts := strings.Split(prefix.Prefix, "/")
addr := parts[0]
bits := parts[1]
filter := fmt.Sprintf("%s/%s{%s,%d}", addr, bits, bits, prefix.MaxLength)
if fmt.Sprintf("%d", prefix.MaxLength) == bits {
filter = fmt.Sprintf("%s/%s", addr, bits)
}
prefixes = append(prefixes, filter)
}
if len(prefixes) == 0 {
continue
}
allowed := strings.Join(prefixes, ",")
part := `
filter %s_in {
if !generic_in() then reject;
if net ~ [ %s ] then accept;
reject;
}
`
part = fmt.Sprintf(part, peerid, allowed)
config += part
part = `
filter %s_out {
accept;
}
`
part = fmt.Sprintf(part, peerid)
config += part
part = `
protocol bgp %s {
local %s as 208521;
neighbor %s as %d;
import filter %s_in;
}
`
part = fmt.Sprintf(part, peerid, flagLocalIP, addr, asc.Asn, peerid)
config += part
}
}
fmt.Println(config)
}