#!/usr/bin/perl -w
use strict;

use Net::IP::XS qw(ip_is_ipv4 ip_is_ipv6);

use Data::Dumper;

my $MY_ASN=25819;
my $SIX_IFACE='enp9s0';
my $MY_SIX_V4_ADDR='206.81.80.184';
my $MY_SIX_V4_NET='206.81.80.184/22';

my $C9H_IPV4_NET0='23.181.112.0/24';
my $C9H_IPV6_NET0='2602:fc6d::/40';

my $addr =
  {
   6 => {
	 my_six_addr => '2001:504:16::64db',
	 my_six_net => '2001:504:16::/64',
	 c9h_net0 => '2602:fc6d::/40',
	},
   4 => {
	 my_six_addr => '206.81.80.184',
	 my_six_net => '206.81.80.0/22',
	 c9h_net0 => '23.181.112.0/24',
	},
  };

my $static_route =
  {
   4 => {
	 '206.81.80.0/22'    => "enp9s0",
	 $C9H_IPV4_NET0      => "enp11s0",
	 '74.120.12.128/28'  => "enp1s0",
	},
   6 => {
	 '2001:504:16::/64'  => "enp9s0",
	 $C9H_IPV6_NET0      => "enp10s0",
	 '2607:ff08:f5::/48' => "enp1s0",
	}
  };

my %peer_ip = (
	       "32150" => {
			   name => 'Danga',
			   ip => {
				  4 => [ qw(
					       206.81.80.233
					  ) ],
				  6 => [ qw(
					     2001:504:16::7d96
					  ) ],
				 },
			   pfx => {
				   4 => 10000,
				   6 => 1000,
				  },
			   },
	       "714" => {
			   name => 'Apple',
			   ip => {
				  4 => [ qw(
					     206.81.80.204
					     206.81.80.205 ) ],
				  6 => [ qw(
					     2001:504:16::2ca
					     2001:504:16::205:0:2ca ) ],
				  },
			   pfx => {
				   4 => 10000,
				   6 => 1000,
				  },
			  },
	       "19165" => {
			   name => 'WebPass',
			   ip => {
				  4 => [ qw(
					     206.81.80.212 ) ],
				  6 => [ qw(
					     2001:504:16::4add ) ],
				  },
			   pfx => {
				   4 => 30,
				   6 => 5,
				  },
			  },
	       "33108" => {
			  name => "SIX route server",
			  ip => {
				 4 => [ qw(
					    206.81.80.2
					    206.81.80.3 ) ],
				 6 => [ qw( 2001:504:16::2
					    2001:504:16::3 ) ],
				},
			  pfx => {
				  4 => 150000,
				  6 => 50000
				 },
			 },
	       "6456" => {
			  name => "alt.net",
			  ip => {
				 4 => [ qw(
					    206.81.80.10
					    206.81.81.41 ) ],
				 6 => [ qw( 2001:504:16::297:0:1938
					    2001:504:16::1938 ) ],
				},
			  pfx => {
				  4 => 20,
				  6 => 20
				 },
			 },
	       "6939" => {
			  name => "HE",
			  ip => { 4 => [ qw( 206.81.80.40 ) ],
				  6 => [ qw( 2001:504:16::1b1b ) ],
				  },
			  pfx => { 4 => 176000,
				   6 => 146000,
				 },
			 },
	       "15133" => {
			   name => "Verizon Digital Media",
			   ip => {
				  4 => [ qw( 206.81.81.28
					     206.81.80.152 ) ],
				  6 => [ qw( 2001:504:16::284:0:3b1d
					     2001:504:16::3b1d ) ],
				 },
			   pfx => {
				   4 => 5000,
				   6 => 5000,
				  },
			  },
	      );


my $function =
  {
   4 => '',
   6 => '',
  };

my $agnostic_block = qq`

protocol kernel {
  scan time 60;
  import none;
#  export all;   # Actually insert routes into the kernel routing table
}

protocol device {
  scan time 60;
}
`;

my $static =
  {
   4 => '',
   6 => '',
  };

my $filter_content =
  {
   4 => '',
   6 => '',
  };

open( my($filter4fd), q{<}, 'bird-filter4.conf' ) or die "could not open bird-filter4.conf for reading: $!";

$filter_content->{4} = join('',<$filter4fd>);

close $filter4fd;

open( my($filter6fd), q{<}, 'bird-filter6.conf' ) or die "could not open bird-filter6.conf for reading: $!";

$filter_content->{6} = join('',<$filter6fd>);

close $filter6fd;


#
# each run should have a semi-consistent ordering
#
my( $v4_bgp, $v6_bgp );

my $bgp_conf =
  {
   4 => undef,
   6 => undef,
  };

my $idx = 0;
foreach my $ip_version ( 4, 6 ){
  # static routes
  $static->{$ip_version} .= qq[protocol static {$/];
  foreach my $net ( sort keys %{$static_route->{$ip_version}} ){
    $static->{$ip_version} .=
      qq{  route $net via "$static_route->{$ip_version}->{$net}";$/};
  }
  $static->{$ip_version} .= qq[}$/];

  $function->{$ip_version} = qq`
function six_export_policy() {
    if net ~ [$addr->{$ip_version}->{c9h_net0}] then {
        if bgp_path.first = 25819 then {
            if bgp_path.last = 25819 then {
                return true;
            }
        }
    }
    return false;
}
`;

  $bgp_conf->{$ip_version} = qq`
# https://blog.kintone.io/entry/bird

template bgp six {
  local as $MY_ASN;
  direct;
  import all;

  export limit 20 action disable;
  export where six_export_policy();

  source address $addr->{$ip_version}->{my_six_addr};
}
`;


  foreach my $peer_as ( sort keys %peer_ip ){
    my $peer = $peer_ip{$peer_as};

    foreach my $peer_ip ( @{$peer->{ip}->{$ip_version}} ) {
      my $ip = new Net::IP::XS ("$peer_ip") or die (Net::IP::XS::Error());

      my $peer_name = $peer->{name};
      $peer_name =~ s/[\. ]/_/g;
      $bgp_conf->{$ip_version} .=  qq`
protocol bgp ${peer_name} from six {
    neighbor ${peer_ip} as ${peer_as};
}
`;
      $idx++;
    }
  }
  my $filename;
  if($ip_version == 4){
    $filename = 'bird.conf';
  }elsif($ip_version == 6){
    $filename = 'bird6.conf';
  }
  open( my( $birdconffd ),  q{>}, $filename )  or die "could not create $filename";
  print $birdconffd
  (
   "router id $addr->{4}->{my_six_addr};$/",
   $/,
   #   qq{include "/etc/bird/bird-filter.conf"},
   $filter_content->{$ip_version},
   $/,
   $agnostic_block,
   $function->{$ip_version},
   $static->{$ip_version},
   $bgp_conf->{$ip_version}
  );
  close $birdconffd;
}
