-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes T1298 use vti tunnel with ipsec and dhcp.
* make dhcp interface work for vti interfaces * clean up code, loger timeout use python api * change vti tunnel ip on new dhcp lease * only change ip on up and do not get non dhcp ip * fix error in function, include up-host and down-host
- Loading branch information
Showing
6 changed files
with
266 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# Copyright (C) 2019 VyOS maintainers and contributors | ||
# | ||
# This program is free software; you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License version 2 or later as | ||
# published by the Free Software Foundation. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
# | ||
# | ||
|
||
import os | ||
import re | ||
import sys | ||
import subprocess | ||
import argparse | ||
import syslog | ||
import time | ||
import vici | ||
|
||
import vyos.config | ||
|
||
config_file = "/etc/ipsec.conf"; | ||
secrets_file = "/etc/ipsec.secrets"; | ||
|
||
|
||
def parse_cli_args(): | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("--interface", type=str) | ||
parser.add_argument("--new_ip", type=str) | ||
parser.add_argument("--old_ip", type=str) | ||
parser.add_argument("--reason", type=str) | ||
args = parser.parse_args() | ||
return args | ||
|
||
|
||
def ipsec_conf_r(): | ||
header = '' | ||
footer = '' | ||
finheader = 0 | ||
connlist = list() | ||
conndict = dict() | ||
curconn = '' | ||
|
||
with open(config_file) as f: | ||
for line in f: | ||
if re.search('^\s*$', line) and finheader: | ||
continue | ||
if re.search('\#conn.*', line): | ||
curconn = '' | ||
continue | ||
if re.search('(peer-.*-tunnel.*)', line): | ||
finheader = 1 | ||
connid = re.search(r'(peer-.*-tunnel.*)', line).group(1) | ||
curconn = connid | ||
if connid not in connlist: | ||
conndict[connid] = dict() | ||
conndict[connid]['_dhcp_iface'] = None | ||
conndict[connid]['_lip'] = None | ||
conndict[connid]['_lines'] = list() | ||
elif re.search('dhcp-interface=(.*)', line) and curconn != '': | ||
conndict[connid]['_dhcp_iface'] = re.search(r'dhcp-interface=(.*)', line).group(1) | ||
elif re.search('left=(.*)', line) and curconn != '': | ||
conndict[connid]['_lip'] = re.search(r'left=(.*)', line).group(1) | ||
elif not finheader: | ||
header = header + line | ||
elif curconn != '': | ||
conndict[connid]['_lines'].append(line) | ||
elif curconn == '': | ||
footer = footer + line; | ||
connlist.append(conndict) | ||
return connlist, header, footer | ||
|
||
|
||
def ipsec_conf_w(connlist, header, footer, interface, new_ip): | ||
try: | ||
with open(config_file, 'w') as f: | ||
f.write('{0}\n'.format(header)) | ||
for connid in connlist: | ||
connname = next(iter(connid)) | ||
f.write('conn {0}\n'.format(connname)) | ||
if connid[connname]['_dhcp_iface']: | ||
if connid[connname]['_dhcp_iface'] == interface: | ||
if not new_ip: | ||
new_ip = '' | ||
connid[connname]['_lip'] = new_ip | ||
f.write('\t#dhcp-interface={0}\n'.format(connid[connname]['_dhcp_iface'])) | ||
f.write('\tleft={0}\n'.format(connid[connname]['_lip'])) | ||
for line in connid[connname]['_lines']: | ||
f.write('{0}'.format(line)) | ||
f.write('#conn {0}\n\n'.format(connname)) | ||
f.write('{0}\n'.format(footer)) | ||
except EnvironmentError as e: | ||
sys.exit('Can\'t open {0}: {1}'.format(config_file, e)) | ||
|
||
|
||
def ipsec_sec_r(): | ||
lines = [] | ||
|
||
with open(secrets_file) as f: | ||
lines = [line for line in f] | ||
return lines | ||
|
||
|
||
def ipsec_sec_w(lines, interface, new_ip): | ||
try: | ||
with open(secrets_file, 'w') as f: | ||
for line in lines: | ||
if re.search('(.*)\#dhcp-interface=(.*)\#', line) and \ | ||
re.search('(.*)\#dhcp-interface=(.*)\#', line).group(2) == interface: | ||
secretline = re.search('(.*)\#dhcp-interface=(.*)\#', line).group(1) | ||
if not new_ip: | ||
new_ip = "#" | ||
secline = re.search('(.*?) (.*?) : PSK (.*?) #dhcp', line) | ||
line = '{0} {1} : PSK {2} #dhcp-interface={3}#\n'.format(new_ip, | ||
secline.group(2), secline.group(3), interface) | ||
f.write('{0}'.format(line)) | ||
except EnvironmentError as e: | ||
sys.exit('Can\'t open {0}: {1}'.format(config_file, e)) | ||
|
||
|
||
def conn_list(): | ||
v = vici.Session() | ||
config = vyos.config.Config() | ||
config_conns = config.list_effective_nodes("vpn ipsec site-to-site peer") | ||
connup = [] | ||
|
||
|
||
v = vici.Session() | ||
for conn in v.list_sas(): | ||
for key in conn: | ||
for c_conn in config_conns: | ||
if c_conn in key: | ||
if config.return_effective_value("vpn ipsec site-to-site peer {0} dhcp-interface".format(c_conn)): | ||
connup.append(key) | ||
|
||
return connup | ||
|
||
|
||
def run(*popenargs, input=None, check=False, **kwargs): | ||
if input is not None: | ||
if 'stdin' in kwargs: | ||
raise ValueError('stdin and input arguments may not both be used.') | ||
kwargs['stdin'] = subprocess.PIPE | ||
|
||
process = subprocess.Popen(*popenargs, **kwargs) | ||
try: | ||
stdout, stderr = process.communicate(input) | ||
except: | ||
process.kill() | ||
process.wait() | ||
raise | ||
retcode = process.poll() | ||
if check and retcode: | ||
raise subprocess.CalledProcessError( | ||
retcode, process.args, output=stdout, stderr=stderr) | ||
return retcode, stdout, stderr | ||
|
||
|
||
def term_conn(active_conn): | ||
v = vici.Session() | ||
for conn in active_conn: | ||
try: | ||
list(v.terminate({"ike": conn, "force": "true"})) | ||
except: | ||
pass | ||
|
||
|
||
def reload_conn(): | ||
run(["/usr/sbin/ipsec", "rereadall"], stderr=subprocess.DEVNULL, | ||
stdout=subprocess.DEVNULL) | ||
run(["/usr/sbin/ipsec", "update"], stderr=subprocess.DEVNULL, | ||
stdout=subprocess.DEVNULL) | ||
|
||
|
||
def init_conn(active_conn, updated_conn): | ||
v = vici.Session() | ||
for conn in active_conn: | ||
if conn not in updated_conn: | ||
list(v.initiate({"child": conn, "timeout": "10000"})) | ||
|
||
|
||
def main(): | ||
args = parse_cli_args() | ||
syslog.openlog('ipsec-dhclient-hook') | ||
|
||
syslog.syslog(syslog.LOG_NOTICE, 'Receive DHCP address updated to {0} from {1}' | ||
', reason: {2}.'.format(args.new_ip, args.old_ip, args.reason)) | ||
|
||
if args.old_ip == args.new_ip and args.reason != 'BOUND' or args.reason == 'REBOOT' or args.reason == 'EXPIRE': | ||
syslog.syslog(syslog.LOG_NOTICE, 'No ipsec update needed.') | ||
sys.exit(0) | ||
|
||
syslog.syslog(syslog.LOG_NOTICE, 'DHCP address updated to {0} from {1}: ' | ||
' Updating ipsec configuration, reason: {2}.'.format(args.new_ip, args.old_ip, args.reason)) | ||
|
||
connlist, header, footer = ipsec_conf_r() | ||
ipsec_conf_w(connlist, header, footer, args.interface, args.new_ip) | ||
|
||
lines = ipsec_sec_r() | ||
ipsec_sec_w(lines, args.interface, args.new_ip) | ||
|
||
if args.new_ip: | ||
active_conn = conn_list() | ||
term_conn(active_conn) | ||
reload_conn() | ||
time.sleep(5) | ||
updated_conn = conn_list() | ||
init_conn(active_conn, updated_conn) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Oops, something went wrong.