mirror of https://gerrit.hackerspace.pl/hscloud
298 lines
6.4 KiB
Go
298 lines
6.4 KiB
Go
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)
|
|
}
|