| 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; |
| password "%s"; |
| } |
| ` |
| part = fmt.Sprintf(part, peerid, flagLocalIP, addr, asc.Asn, peerid, router.Password) |
| config += part |
| } |
| } |
| |
| fmt.Println(config) |
| } |