diff options
-rw-r--r-- | Jenkinsfile | 14 | ||||
-rw-r--r-- | interface-definitions/system-syslog.xml.in | 14 | ||||
-rw-r--r-- | op-mode-definitions/traceroute.xml | 46 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 6 | ||||
-rw-r--r-- | python/vyos/ifconfig/vxlan.py | 29 | ||||
-rw-r--r-- | python/vyos/ifconfig/wireguard.py | 3 | ||||
-rwxr-xr-x | scripts/build-command-templates | 5 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-l2tpv3.py | 35 | ||||
-rwxr-xr-x | src/conf_mode/ntp.py | 3 | ||||
-rwxr-xr-x | src/validators/fqdn | 27 |
10 files changed, 117 insertions, 65 deletions
diff --git a/Jenkinsfile b/Jenkinsfile index ed98477f2..7a79b0f43 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,7 +36,7 @@ def isCustomBuild() { def gitURI = 'git@github.com:vyos/' + getGitRepoName() def httpURI = 'https://github.com/vyos/' + getGitRepoName() - return ! ((getGitRepoURL() == gitURI) || (getGitRepoURL() == httpURI)) + return !((getGitRepoURL() == gitURI) || (getGitRepoURL() == httpURI)) || env.CHANGE_ID } def setDescription() { @@ -74,7 +74,13 @@ node('Docker') { script { // create container name on demand def branchName = getGitBranchName() - if (branchName == "master") { + // Adjust PR target branch name so we can re-map it to the proper + // Docker image. CHANGE_ID is set only for pull requests, so it is + // safe to access the pullRequest global variable + if (env.CHANGE_ID) { + branchName = "${env.CHANGE_TARGET}".toLowerCase() + } + if (branchName.equals("master")) { branchName = "current" } env.DOCKER_IMAGE = "vyos/vyos-build:" + branchName @@ -92,7 +98,6 @@ pipeline { } options { disableConcurrentBuilds() - skipDefaultCheckout() timeout(time: 30, unit: 'MINUTES') timestamps() } @@ -101,8 +106,7 @@ pipeline { steps { script { dir('build') { - git branch: getGitBranchName(), - url: getGitRepoURL() + checkout scm } } } diff --git a/interface-definitions/system-syslog.xml.in b/interface-definitions/system-syslog.xml.in index 2079ec0ea..194cdb851 100644 --- a/interface-definitions/system-syslog.xml.in +++ b/interface-definitions/system-syslog.xml.in @@ -181,13 +181,17 @@ <properties> <help>Logging to a remote host</help> <constraint> - <validator name="ip-address" /> - <regex>(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)</regex> + <validator name="ip-address"/> + <validator name="fqdn"/> </constraint> - <constraintErrorMessage>Invalid host FQDN or IP address</constraintErrorMessage> + <constraintErrorMessage>Invalid host (FQDN or IP address)</constraintErrorMessage> <valueHelp> - <format>x.x.x.x or host.domain.tld</format> - <description>Remote host name or IP address</description> + <format>ipv4</format> + <description>Remote syslog server IPv4 address</description> + </valueHelp> + <valueHelp> + <format>hostname</format> + <description>Remote syslog server FQDN</description> </valueHelp> </properties> <children> diff --git a/op-mode-definitions/traceroute.xml b/op-mode-definitions/traceroute.xml index 85f6047c1..d16e9e3b8 100644 --- a/op-mode-definitions/traceroute.xml +++ b/op-mode-definitions/traceroute.xml @@ -12,9 +12,8 @@ <list><hostname> <x.x.x.x> <h:h:h:h:h:h:h:h></list> </completionHelp> </properties> - <command>/usr/bin/traceroute $2</command> + <command>traceroute $2</command> </tagNode> - <tagNode name="ipv4"> <properties> <help>Track network path to <hostname|IPv4 address></help> @@ -22,9 +21,8 @@ <list><hostname> <x.x.x.x></list> </completionHelp> </properties> - <command>/usr/bin/traceroute -4 $3</command> + <command>traceroute -4 $3</command> </tagNode> - <tagNode name="ipv6"> <properties> <help>Track network path to <hostname|IPv6 address></help> @@ -32,11 +30,47 @@ <list><hostname> <h:h:h:h:h:h:h:h></list> </completionHelp> </properties> - <command>/usr/bin/traceroute -6 $3</command> + <command>traceroute -6 $3</command> + </tagNode> + <tagNode name="vrf"> + <properties> + <help>Track network path to specified node via given VRF instance</help> + <completionHelp> + <path>vrf name</path> + </completionHelp> + </properties> + <children> + <tagNode name=""> + <properties> + <help>Track network path to specified node</help> + <completionHelp> + <list><hostname> <x.x.x.x> <h:h:h:h:h:h:h:h></list> + </completionHelp> + </properties> + <command>sudo ip vrf exec "$3" traceroute "$4"</command> + </tagNode> + <tagNode name="ipv4"> + <properties> + <help>Track network path to <hostname|IPv4 address></help> + <completionHelp> + <list><hostname> <x.x.x.x></list> + </completionHelp> + </properties> + <command>sudo ip vrf exec "$3" traceroute -4 "$5"</command> + </tagNode> + <tagNode name="ipv6"> + <properties> + <help>Track network path to <hostname|IPv6 address></help> + <completionHelp> + <list><hostname> <h:h:h:h:h:h:h:h></list> + </completionHelp> + </properties> + <command>sudo ip vrf exec "$3" traceroute -6 "$5"</command> + </tagNode> + </children> </tagNode> </children> </node> - <node name="monitor"> <children> <tagNode name="traceroute"> diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index a750bda3f..b002e0171 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -741,12 +741,6 @@ class Interface(Control): with open(self._dhcpv6_cfg_file, 'w') as f: f.write(dhcpv6_text) - # https://bugs.launchpad.net/ubuntu/+source/ifupdown/+bug/1447715 - # - # wee need to wait for IPv6 DAD to finish once and interface is added - # this suxx :-( - sleep(5) - # no longer accept router announcements on this interface self._write_sysfs('/proc/sys/net/ipv6/conf/{}/accept_ra' .format(self.config['ifname']), 0) diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py index bc2ec508b..86702b2cd 100644 --- a/python/vyos/ifconfig/vxlan.py +++ b/python/vyos/ifconfig/vxlan.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see <http://www.gnu.org/licenses/>. - +from vyos import ConfigError from vyos.ifconfig.interface import Interface @@ -54,20 +54,23 @@ class VXLANIf(Interface): super().__init__(ifname, **kargs) def _create(self): - # we assume that by default a multicast interface is created - group = 'group {}'.format(self.config['group']) - - # if remote host is specified we ignore the multicast address + cmd = '' if self.config['remote']: - group = 'remote {}'.format(self.config['remote']) - - # an underlay device is not always specified - dev = '' - if self.config['dev']: - dev = 'dev {}'.format(self.config['dev']) + # an underlay device is only mandatory with multicast, not unicast + dev = '' + if self.config['dev']: + dev = 'dev {}'.format(self.config['dev']) + # iproute2 command for unicast + cmd = 'ip link add {ifname} type vxlan id {vni} remote {remote} {dev_optional} dstport {port}'.format( + **self.config, dev_optional=dev) + else: + if not self.config['dev']: + raise ConfigError( + f'VXLAN "{self.config["ifname"]}" is missing mandatory underlay interface for a multicast network.') + # iproute2 command for multicast + cmd = 'ip link add {ifname} type vxlan id {vni} group {group} dev {dev} dstport {port}'.format( + **self.config) - cmd = 'ip link add {ifname} type vxlan id {vni} {group} {dev} dstport {port}'.format( - **config) self._cmd(cmd) @staticmethod diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py index 2926e72e1..411c3e146 100644 --- a/python/vyos/ifconfig/wireguard.py +++ b/python/vyos/ifconfig/wireguard.py @@ -16,6 +16,7 @@ import os +import vyos from vyos.ifconfig.interface import Interface class WireGuardIf(Interface): @@ -101,7 +102,7 @@ class WireGuardIf(Interface): wgdump = vyos.interfaces.wireguard_dump().get( self.config['ifname'], None) - c = Config() + c = vyos.config.Config() c.set_level(["interfaces", "wireguard", self.config['ifname']]) description = c.return_effective_value(["description"]) ips = c.return_effective_values(["address"]) diff --git a/scripts/build-command-templates b/scripts/build-command-templates index dbf4ad9c5..c6534a6d8 100755 --- a/scripts/build-command-templates +++ b/scripts/build-command-templates @@ -264,6 +264,11 @@ def process_node(n, tmpl_dir): if node_type == "tagNode": props["tag"] = "True" + if node_type != "leafNode": + if "multi" in props: + raise ValueError("<multi/> tag is only allowed in <leafNode>") + if "valueless" in props: + raise ValueError("<valueless/> is only allowed in <leafNode>") nodedef_path = os.path.join(make_path(my_tmpl_dir), "node.def") if not os.path.exists(nodedef_path): diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py index 1b9425f64..3bc3faca8 100755 --- a/src/conf_mode/interfaces-l2tpv3.py +++ b/src/conf_mode/interfaces-l2tpv3.py @@ -42,6 +42,13 @@ default_config_data = { 'tunnel_id': '' } +def check_kmod(): + modules = ['l2tp_eth', 'l2tp_netlink', 'l2tp_ip', 'l2tp_ip6'] + for module in modules: + if not os.path.exists(f'/sys/module/{module}'): + if os.system(f'modprobe {module}') != 0: + raise ConfigError(f'Loading Kernel module {module} failed') + def get_config(): l2tpv3 = deepcopy(default_config_data) conf = Config() @@ -152,35 +159,8 @@ def verify(l2tpv3): def generate(l2tpv3): - if l2tpv3['deleted']: - # bail out early - return None - - # initialize kernel module if not loaded - if not os.path.isdir('/sys/module/l2tp_eth'): - if os.system('modprobe l2tp_eth') != 0: - raise ConfigError("failed loading l2tp_eth kernel module") - - if not os.path.isdir('/sys/module/l2tp_netlink'): - if os.system('modprobe l2tp_netlink') != 0: - raise ConfigError("failed loading l2tp_netlink kernel module") - - if not os.path.isdir('/sys/module/l2tp_ip'): - if os.system('modprobe l2tp_ip') != 0: - raise ConfigError("failed loading l2tp_ip kernel module") - - if l2tpv3['encapsulation'] == 'ip': - if not os.path.isdir('/sys/module/l2tp_ip'): - if os.system('modprobe l2tp_ip') != 0: - raise ConfigError("failed loading l2tp_ip kernel module") - - if not os.path.isdir('/sys/module/l2tp_ip6 '): - if os.system('modprobe l2tp_ip6 ') != 0: - raise ConfigError("failed loading l2tp_ip6 kernel module") - return None - def apply(l2tpv3): # L2TPv3 interface needs to be created/deleted on-block, instead of # passing a ton of arguments, I just use a dict that is managed by @@ -230,6 +210,7 @@ def apply(l2tpv3): if __name__ == '__main__': try: + check_kmod() c = get_config() verify(c) generate(c) diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py index 8f32e6e81..f706d502f 100755 --- a/src/conf_mode/ntp.py +++ b/src/conf_mode/ntp.py @@ -42,8 +42,6 @@ restrict default noquery nopeer notrap nomodify restrict 127.0.0.1 restrict -6 ::1 -# Do not listen on any interface address by default -interface ignore wildcard # # Configurable section # @@ -65,6 +63,7 @@ restrict {{ n.address }} mask {{ n.netmask }} nomodify notrap nopeer {% if listen_address -%} # NTP should listen on configured addresses only +interface ignore wildcard {% for a in listen_address -%} interface listen {{ a }} {% endfor -%} diff --git a/src/validators/fqdn b/src/validators/fqdn new file mode 100755 index 000000000..9f4ed764f --- /dev/null +++ b/src/validators/fqdn @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 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/>. + +from re import match +from sys import argv,exit + +if len(argv) == 2: + # pattern copied from: https://www.regextester.com/103452 + pattern = "(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)" + if match(pattern, argv[1]): + exit(0) + else: + exit(1) + |