blob: 457b567a6b112db287411476e07431afce858dce [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
flagUpstream bool
)
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.BoolVar(&flagUpstream, "upstream", false, "Is an upstream router")
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;
define ourASN = %d;
define filteredNumber = 65666;
define customerNumber = 65667;
define martian = 1;
define prefixTooLong64 = 2;
define prefixTooLong24 = 3;
define pathBogon = 4;
define pathTooLong = 5;
define pathFirstNotPeer = 6;
define prefixFiltered = 9;
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 {
bgp_large_community.add((ourASN, filteredNumber, martian));
return false;
}
if bgp_path.len > 64 then {
bgp_large_community.add((ourASN, filteredNumber, pathTooLong));
return false;
}
if net.len > 64 then {
bgp_large_community.add((ourASN, filteredNumber, prefixTooLong64));
return false;
}
return true;
}
`
config = fmt.Sprintf(config, flagRouterID, 208521)
} 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;
define ourASN = %d;
define filteredNumber = 65666;
define customerNumber = 65667;
define martian = 1;
define prefixTooLong64 = 2;
define prefixTooLong24 = 3;
define pathBogon = 4;
define pathTooLong = 5;
define pathFirstNotPeer = 6;
define prefixFiltered = 9;
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 {
bgp_large_community.add((ourASN, filteredNumber, martian));
return false;
}
if bgp_path.len > 64 then {
bgp_large_community.add((ourASN, filteredNumber, pathTooLong));
return false;
}
if net.len > 24 then {
bgp_large_community.add((ourASN, filteredNumber, prefixTooLong24));
return false;
}
return true;
}
`
config = fmt.Sprintf(config, flagRouterID, 208521)
}
if flagUpstream {
config += `
protocol kernel {
scan time 60;
import none;
export all;
}
filter UPSTREAM_C3NOC_IN {
if net_martians() then reject;
if bgp_path.len > 64 then reject;
accept;
}
filter UPSTREAM_C3NOC_OUT {
accept;
}
`
if flagV6 {
config += `
protocol bgp UPSTREAM_C3NOC {
import filter UPSTREAM_C3NOC_IN;
export filter UPSTREAM_C3NOC_OUT;
description "UPSTREAM AS13020";
local 2a0d:eb02:4242:4242::7 as 208521;
neighbor 2a0d:eb02:4242:4242::250 as 13020;
}
`
} else {
config += `
protocol bgp UPSTREAM_C3NOC {
import filter UPSTREAM_C3NOC_IN;
export filter UPSTREAM_C3NOC_OUT;
local 185.236.243.7 as 208521;
neighbor 185.236.243.250 as 13020;
}
`
}
}
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 bgp_path.first != %d then {
bgp_large_community.add((ourASN, filteredNumber, pathFirstNotPeer));
reject;
}
if bgp_path.last != %d then {
bgp_large_community.add((ourASN, filteredNumber, pathFirstNotPeer));
reject;
}
if ! (net ~ [ %s ]) then {
bgp_large_community.add((ourASN, filteredNumber, prefixFiltered));
reject;
}
bgp_large_community.add((ourASN, customerNumber, 2137));
accept;
}
`
part = fmt.Sprintf(part, peerid, asc.Asn, asc.Asn, allowed)
config += part
part = `
filter %s_out {
if (ourASN, customerNumber, 2137) ~ bgp_large_community then reject;
accept;
}
`
part = fmt.Sprintf(part, peerid)
config += part
part = `
protocol bgp %s {
local %s as 208521;
description "PEER AS%d R%d";
neighbor %s as %d;
import filter %s_in;
import keep filtered on;
export filter %s_out;
password "%s";
}
`
part = fmt.Sprintf(part, peerid, flagLocalIP, asc.Asn, i, addr, asc.Asn, peerid, peerid, router.Password)
config += part
}
}
fmt.Println(config)
}