mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
WIP net/frr: Add BGP password support (#2800)
Add BGP password support [https://github.com/opnsense/plugins/pull/2645] Try to figure out which entries belong to FRR before removing them, so neighbour changes won't be left on the machine after apply. Flush our desired configuration into /usr/local/etc/frr/sa_policies.conf for easy reading and testing. Since we don't know if passwords have changed, we will have to drop SA's first. When this is a bit bumpy, we may also try to alter the existing SA's, this shouldn't be too hard to add later on. Co-authored-by: Michael <m.muenz@gmail.com>
This commit is contained in:
@@ -14,6 +14,7 @@ Plugin Changelog
|
||||
1.26
|
||||
|
||||
* Fix Model migration errors
|
||||
* Add BGP password authentication
|
||||
|
||||
1.25
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ class BgpController extends ApiMutableModelControllerBase
|
||||
"description",
|
||||
"address",
|
||||
"remoteas",
|
||||
"password",
|
||||
"localip",
|
||||
"updatesource",
|
||||
"nexthopself",
|
||||
"multihop",
|
||||
|
||||
+14
@@ -22,6 +22,20 @@
|
||||
<type>text</type>
|
||||
<help>Neighbor AS.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>neighbor.password</id>
|
||||
<label>BGP MD5 Password</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>Set a password for BGP authentication.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>neighbor.localip</id>
|
||||
<label>Local Initiater IP</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>Set the local IP connecting to the neighbor. This is only required for BGP authentication.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>neighbor.updatesource</id>
|
||||
<label>Update-Source Interface</label>
|
||||
|
||||
@@ -57,6 +57,12 @@
|
||||
<MinimumValue>1</MinimumValue>
|
||||
<MaximumValue>4294967295</MaximumValue>
|
||||
</remoteas>
|
||||
<password type="TextField">
|
||||
<Required>N</Required>
|
||||
</password>
|
||||
<localip type="NetworkField">
|
||||
<Required>N</Required>
|
||||
</localip>
|
||||
<updatesource type="InterfaceField">
|
||||
<default></default>
|
||||
<Required>N</Required>
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
#!/usr/local/bin/python3
|
||||
"""
|
||||
Copyright (c) 2022 Ad Schellevis <ad@opnsense.org>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
from configparser import ConfigParser
|
||||
|
||||
if __name__ == '__main__':
|
||||
frr_sad = {}
|
||||
frr_sa_database = "/usr/local/etc/frr/sa_policies.conf"
|
||||
# stage 1, read required FRR policies
|
||||
if os.path.exists(frr_sa_database):
|
||||
cnf = ConfigParser()
|
||||
cnf.read(frr_sa_database)
|
||||
for section in cnf.sections():
|
||||
if cnf.has_option(section, 'src') and cnf.has_option(section, 'dst'):
|
||||
policy_key = "%s %s" % (cnf.get(section, 'src'), cnf.get(section, 'dst'))
|
||||
frr_sad[policy_key] = {}
|
||||
for prop in cnf.items(section):
|
||||
frr_sad[policy_key][prop[0]] = prop[1]
|
||||
|
||||
# stage 2, red current installed policies which seems to originate from FRR
|
||||
registered_policies = []
|
||||
current_policy = None
|
||||
for line in subprocess.run(["/sbin/setkey", "-D"], capture_output=True, text=True).stdout.split('\n'):
|
||||
parts = line.strip().split()
|
||||
if not line.startswith('\t') and len(parts) > 1:
|
||||
current_policy = {"src": parts[0], "dst": parts[1]}
|
||||
elif len(parts) > 2 and parts[0] == 'A:' and parts[1] == 'tcp-md5':
|
||||
# Let's assume we're the only ones registering these types of entries
|
||||
registered_policies.append(current_policy)
|
||||
|
||||
# flush changes to temp file and load with setkey
|
||||
temp_filename = None
|
||||
with tempfile.NamedTemporaryFile(mode='wt', delete=False) as fo:
|
||||
temp_filename = fo.name
|
||||
for policy in registered_policies:
|
||||
fo.write("delete -4 %(src)s %(dst)s tcp 0x1000;\n" % policy)
|
||||
for new_policy in frr_sad:
|
||||
fo.write('add -4 %(src)s %(dst)s %(protocol)s %(spi)s -A %(aalgo)s "%(key)s";\n' % frr_sad[new_policy])
|
||||
|
||||
if temp_filename:
|
||||
subprocess.run(["/sbin/setkey", "-f", fo.name], capture_output=True, text=True)
|
||||
@@ -18,3 +18,6 @@ chown -R $user:$group /var/run/frr
|
||||
# logfile (if used)
|
||||
touch /var/log/frr.log
|
||||
chown $user:$group /var/log/frr.log
|
||||
|
||||
# register Security Associations
|
||||
/usr/local/opnsense/scripts/frr/register_sas
|
||||
|
||||
@@ -4,6 +4,7 @@ ospfd.conf:/usr/local/etc/frr/ospfd.conf
|
||||
ospfd_carp.conf:/usr/local/etc/frr/ospfd_carp.conf
|
||||
ospf6d.conf:/usr/local/etc/frr/ospf6d.conf
|
||||
ripd.conf:/usr/local/etc/frr/ripd.conf
|
||||
sa_policies.conf:/usr/local/etc/frr/sa_policies.conf
|
||||
frr:/etc/rc.conf.d/frr
|
||||
zebra.conf:/usr/local/etc/frr/zebra.conf
|
||||
vtysh.conf:/usr/local/etc/frr/vtysh.conf
|
||||
|
||||
@@ -57,6 +57,9 @@ router bgp {{ OPNsense.quagga.bgp.asnumber }}
|
||||
{% if 'bfd' in neighbor and neighbor.bfd == '1' %}
|
||||
neighbor {{ neighbor.address }} bfd
|
||||
{% endif %}
|
||||
{% if 'password' in neighbor and neighbor.password != '' %}
|
||||
neighbor {{ neighbor.address }} password {{ neighbor.password }}
|
||||
{% endif %}
|
||||
{% if ':' not in neighbor.address and 'updatesource' in neighbor and neighbor.updatesource != '' %}
|
||||
neighbor {{ neighbor.address }} update-source {{ physical_interface(neighbor.updatesource) }}
|
||||
{% endif %}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
{% if helpers.exists('OPNsense.quagga.bgp.enabled') and OPNsense.quagga.bgp.enabled == '1' %}
|
||||
{% if helpers.exists('OPNsense.quagga.bgp.neighbors.neighbor') %}
|
||||
{% for neighbor in helpers.toList('OPNsense.quagga.bgp.neighbors.neighbor') %}
|
||||
{% if neighbor.enabled == '1' and neighbor.password|default('') != '' %}
|
||||
[policy_{{neighbor['@uuid']}}_in]
|
||||
src={{ neighbor.address }}
|
||||
dst={{ neighbor.localip }}
|
||||
protocol=tcp
|
||||
spi=0x1000
|
||||
aalgo=tcp-md5
|
||||
key={{ neighbor.password }}
|
||||
|
||||
[policy_{{neighbor['@uuid']}}_out]
|
||||
src={{ neighbor.localip }}
|
||||
dst={{ neighbor.address }}
|
||||
protocol=tcp
|
||||
spi=0x1000
|
||||
aalgo=tcp-md5
|
||||
key={{ neighbor.password }}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user