From 94fd6db6186ea78bb98bb7bbd5092ef7da92ac36 Mon Sep 17 00:00:00 2001 From: uvok cheetah Date: Tue, 19 Mar 2024 19:37:36 +0100 Subject: Add my bird role --- roles/uvok_bird/README.md | 38 ++++ roles/uvok_bird/defaults/main.yml | 10 + roles/uvok_bird/handlers/main.yml | 9 + roles/uvok_bird/meta/main.yml | 51 +++++ roles/uvok_bird/tasks/main.yml | 19 ++ roles/uvok_bird/templates/clearnet.conf.j2 | 289 +++++++++++++++++++++++++++++ roles/uvok_bird/tests/inventory | 2 + roles/uvok_bird/tests/test.yml | 6 + roles/uvok_bird/vars/main.yml | 2 + 9 files changed, 426 insertions(+) create mode 100644 roles/uvok_bird/README.md create mode 100644 roles/uvok_bird/defaults/main.yml create mode 100644 roles/uvok_bird/handlers/main.yml create mode 100644 roles/uvok_bird/meta/main.yml create mode 100644 roles/uvok_bird/tasks/main.yml create mode 100644 roles/uvok_bird/templates/clearnet.conf.j2 create mode 100644 roles/uvok_bird/tests/inventory create mode 100644 roles/uvok_bird/tests/test.yml create mode 100644 roles/uvok_bird/vars/main.yml (limited to 'roles') diff --git a/roles/uvok_bird/README.md b/roles/uvok_bird/README.md new file mode 100644 index 0000000..fd1fe7c --- /dev/null +++ b/roles/uvok_bird/README.md @@ -0,0 +1,38 @@ +Role Name +========= + +Start up my bird setup. + +Requirements +------------ + +Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. + +Role Variables +-------------- + +A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. + +Dependencies +------------ + +None + +Example Playbook +---------------- + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + + - hosts: servers + roles: + - { role: username.rolename, x: 42 } + +License +------- + +MIT + +Author Information +------------------ + +uvok (https://blog.uvokchee.de/). \ No newline at end of file diff --git a/roles/uvok_bird/defaults/main.yml b/roles/uvok_bird/defaults/main.yml new file mode 100644 index 0000000..927c6b8 --- /dev/null +++ b/roles/uvok_bird/defaults/main.yml @@ -0,0 +1,10 @@ +--- +# defaults file for bird +uvok_bird_opts: + config_dir: "/tmp/bird/" + clearnet: false + dn42: false + use_fallback: false + preferred_ip: "::1" + prefixes: [] + babel_if_name: diff --git a/roles/uvok_bird/handlers/main.yml b/roles/uvok_bird/handlers/main.yml new file mode 100644 index 0000000..9ace21c --- /dev/null +++ b/roles/uvok_bird/handlers/main.yml @@ -0,0 +1,9 @@ +--- +# handlers file for uvok_bird + +- name: Check config + command: birdc configure check + listen: configure bird +- name: apply config + command: birdc configure soft + listen: configure bird diff --git a/roles/uvok_bird/meta/main.yml b/roles/uvok_bird/meta/main.yml new file mode 100644 index 0000000..a5088bd --- /dev/null +++ b/roles/uvok_bird/meta/main.yml @@ -0,0 +1,51 @@ +galaxy_info: + author: uvok + description: Start up my bird setup. Probably won't fit your needs. + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Choose a valid license ID from https://spdx.org - some suggested licenses: + # - BSD-3-Clause (default) + # - MIT + # - GPL-2.0-or-later + # - GPL-3.0-only + # - Apache-2.0 + # - CC-BY-4.0 + license: MIT + + min_ansible_version: "2.16" + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + # platforms: + # - name: Fedora + # versions: + # - all + # - 25 + # - name: SomePlatform + # versions: + # - all + # - 1.0 + # - 7 + # - 99.99 + + galaxy_tags: [] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. + +dependencies: [] + # List your role dependencies here, one per line. Be sure to remove the '[]' above, + # if you add dependencies to this list. diff --git a/roles/uvok_bird/tasks/main.yml b/roles/uvok_bird/tasks/main.yml new file mode 100644 index 0000000..c3ef063 --- /dev/null +++ b/roles/uvok_bird/tasks/main.yml @@ -0,0 +1,19 @@ +--- +# tasks file for uvok_bird +- name: Ensure bird directory exists + ansible.builtin.file: + path: '{{ uvok_bird_opts.config_dir }}' + state: directory + mode: '0750' + owner: 'bird' + group: 'bird' +- name: Install template + template: + src: clearnet.conf.j2 + dest: '{{ uvok_bird_opts.config_dir }}/clearnet.conf' + mode: '0640' + owner: 'bird' + group: 'bird' + when: + - uvok_bird_opts.clearnet + notify: configure bird diff --git a/roles/uvok_bird/templates/clearnet.conf.j2 b/roles/uvok_bird/templates/clearnet.conf.j2 new file mode 100644 index 0000000..9f75798 --- /dev/null +++ b/roles/uvok_bird/templates/clearnet.conf.j2 @@ -0,0 +1,289 @@ +# {{ ansible_managed }} + +define CLEARNET_PREFIP = {{ uvok_bird_opts.preferred_ip }}; + +# trs=transit +ipv6 table t_myas_unfiltered; +ipv6 table t_myas_trs; +ipv6 table t_myas_babel; + +roa6 table clear_roa_v6; + +protocol rpki roa_clearnet1 { + roa6 { table clear_roa_v6; }; + remote 10.2.0.1; + port 8282; + refresh 3600; + retry 600; + expire 7200; +} + +protocol rpki roa_clearnet2 { + roa6 { table clear_roa_v6; }; + remote 10.2.0.10; + port 8282; + refresh 3600; + retry 600; + expire 7200; +} + +define BOGON_ASNS = [ + 0, # RFC 7607 + 23456, # RFC 4893 AS_TRANS + 64496..64511, # RFC 5398 and documentation/example ASNs + 64512..65534, # RFC 6996 Private ASNs + 65535, # RFC 7300 Last 16 bit ASN + 65536..65551, # RFC 5398 and documentation/example ASNs + 65552..131071, # RFC IANA reserved ASNs + 4200000000..4294967294, # RFC 6996 Private ASNs + 4294967295 ]; # RFC 7300 Last 32 bit ASN + +define BOGON_PREFIXES = [ ::/0, # Default route + ::/8+, # RFC 4291 IPv4-compatible, loopback, et al + 0100::/64+, # RFC 6666 Discard-Only + 2001:2::/48+, # RFC 5180 BMWG + 2001:10::/28+, # RFC 4843 ORCHID + 2001:db8::/32+, # RFC 3849 documentation + 2002::/16+, # RFC 7526 6to4 anycast relay + 3ffe::/16+, # RFC 3701 old 6bone + fc00::/7+, # RFC 4193 unique local unicast + fe80::/10+, # RFC 4291 link local unicast + fec0::/10+, # RFC 3879 old site local unicast + ff00::/8+ # RFC 4291 multicast + ]; + +function reject_bogon_asns() +int set bogon_asns; +{ + bogon_asns = BOGON_ASNS; + + if ( bgp_path ~ bogon_asns ) then { + print "Reject: bogon AS_PATH: ", net, " ", bgp_path; + clearnet_add_filter(FILTER_BOGON_ASN); + } +} + +function reject_bogon_prefixes() +prefix set bogon_prefixes; +{ + bogon_prefixes = BOGON_PREFIXES; + if (net ~ bogon_prefixes) then { + print "Reject: Bogon prefix: ", net, " ", bgp_path; + clearnet_add_filter(FILTER_BOGON_PREFIX); + } +} + +define PROBLEM_PREFIXES = [ +]; + +function reject_problem_prefixes() +prefix set problem_prefixes; +{ + problem_prefixes = PROBLEM_PREFIXES; + if (net ~ problem_prefixes) then { + print "Reject: Problematic prefix: ", net, " ", bgp_path; + clearnet_add_filter(FILTER_PROBLEM_PREFIX); + } +} + +function reject_long_aspaths() +{ + if ( bgp_path.len > 50 ) then { + clearnet_add_filter(FILTER_LONG_ASPATH); + } +} + +function reject_small_prefixes() +{ + if (net.len > 55 && net.type = NET_IP6) then { + print "Reject: Too small prefix: ", net, " ", bgp_path; + clearnet_add_filter(FILTER_SMALL_V6_PREFIX); + } +} + +function reject_roa_rpki() +{ + if ( roa_check(clear_roa_v6, net, bgp_path.last_nonaggregated) = ROA_INVALID ) then { + clearnet_add_filter(FILTER_ROA_RPKI); + } +} + +function clearnet_common_import() { + reject_bogon_asns(); + reject_bogon_prefixes(); + reject_long_aspaths(); + reject_small_prefixes(); + reject_problem_prefixes(); + reject_roa_rpki(); + honor_graceful_shutdown(); +} + +filter myas_export +{ + if (proto = "myprefix") then { + accept; + } + reject; +} + +# route collector +filter myas_f_rc +{ +# export IXP routes after all +# if ( clearnet_is_ixp() ) then reject; + if (source = RTS_BGP) then accept; + if (proto = "myprefix") then accept; + reject; +}; + +protocol static myprefix { +{% for prefix in uvok_bird_opts.prefixes %} + route {{ prefix }} reject; +{% endfor %}; + + ipv6 { + # needs to be in unfiltered - because that's where I'm exporting from + table t_myas_unfiltered; + import all; + export none; + }; +} + +protocol direct { + ipv6 { table t_myas_babel; }; + interface "myas_int"; +}; + +template bgp pt_clearnet { + local as CLEARNET_ASN; + + graceful restart on; + long lived graceful restart on; + + prefer older on; + + # Neighbor as must be first route as + enforce first as on; + # faster updates + enable extended messages on; + + # defaults anyway + enable route refresh on; + interpret communities on; + direct; + + # higher better + default bgp_local_pref 100; + + # my value - lower better + default bgp_med 100; + + ipv6 { + # start by importing into the unfiltered table + table t_myas_unfiltered; + + # for inspection who's evil + import keep filtered; + # for RPKI / ROA + import table on; + + import filter { + clearnet_import_transit(); + clearnet_common_import(); + accept; + }; + + export filter myas_export; + }; +} + +# route collector +template bgp pt_rc from pt_clearnet { + multihop; + + # yes, use unfiltered table for export + # I wanna shame garbish announcers publically! ;) + ipv6 { + add paths tx; + import none; + export filter myas_f_rc; + }; +} + +{% if uvok_bird_opts.babel_if_name %} +protocol babel p_myas_babel { + ipv6 { + table t_myas_babel; + import where source ~ [RTS_DEVICE, RTS_BABEL]; + export where source ~ [RTS_DEVICE, RTS_BABEL]; + }; + + interface "{{ uvok_bird_opts.babel_if_name }}" { + }; +} +{% endif %} + +# pipe babel table => bgp table for next-hop resolution? +protocol pipe { + table t_myas_babel; + peer table t_myas_trs; + import none; + export where source ~ [RTS_BABEL]; +} + +# EXPORT FROM unfilteed TO filtered trs table +protocol pipe { + table t_myas_unfiltered; + peer table t_myas_trs; + import none; + export filter { + if ( bgp_large_community ~ [(CLEARNET_ASN, LC_FILTERED, *)] ) then { + reject; + } + accept; + }; +} + +protocol kernel p_myas_i { +# scan time 20; + kernel table 150; + + ipv6 { + table t_myas_babel; + import none; + export filter { + if (source != RTS_BABEL) then { + print "SHOULD NOT HAPPEN: export babel to kernel: ", net, " from", source; + reject; + } + krt_prefsrc = CLEARNET_PREFIP; + accept; + }; + }; +}; + +protocol kernel pk_myas_out { + kernel table 100; + + ipv6 { + table t_myas_trs; + import none; + export filter { + krt_prefsrc = CLEARNET_PREFIP; + if (source = RTS_BGP) then { + accept; + } +{% if uvok_bird_opts.use_fallback %} + if (proto = "myas_def_fallb") then { + accept; + } +{% endif %} + reject; + }; + }; +}; + +include "/etc/bird/clear_peers/*.conf"; +{% if uvok_bird_opts.use_fallback %} +include "clear_fallback.conf"; +{% endif %} diff --git a/roles/uvok_bird/tests/inventory b/roles/uvok_bird/tests/inventory new file mode 100644 index 0000000..878877b --- /dev/null +++ b/roles/uvok_bird/tests/inventory @@ -0,0 +1,2 @@ +localhost + diff --git a/roles/uvok_bird/tests/test.yml b/roles/uvok_bird/tests/test.yml new file mode 100644 index 0000000..316407d --- /dev/null +++ b/roles/uvok_bird/tests/test.yml @@ -0,0 +1,6 @@ +--- +- name: "Test play?" + hosts: localhost + remote_user: root + roles: + - uvok_bird diff --git a/roles/uvok_bird/vars/main.yml b/roles/uvok_bird/vars/main.yml new file mode 100644 index 0000000..f543c41 --- /dev/null +++ b/roles/uvok_bird/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for uvok_bird -- cgit v1.2.3