diff options
Diffstat (limited to 'src/validators')
48 files changed, 963 insertions, 0 deletions
| diff --git a/src/validators/as-number-list b/src/validators/as-number-list new file mode 100644 index 0000000..432d441 --- /dev/null +++ b/src/validators/as-number-list @@ -0,0 +1,29 @@ +#!/bin/sh +# +# Copyright (C) 2022 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/>. + +if [ $# -lt 1 ]; then +      echo "Illegal number of parameters" +      exit 1 +fi + +for var in "$@"; do +    ${vyos_validators_dir}/numeric --range 1-4294967294 $var +    if [ $? -ne 0 ]; then +        exit 1 +    fi +done + +exit 0 diff --git a/src/validators/base64 b/src/validators/base64 new file mode 100644 index 0000000..e2b1e73 --- /dev/null +++ b/src/validators/base64 @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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 base64 +from sys import argv + +if __name__ == '__main__': +    if len(argv) != 2: +        exit(1) +    try: +        base64.b64decode(argv[1]) +    except: +        exit(1) +    exit(0) diff --git a/src/validators/bgp-extended-community b/src/validators/bgp-extended-community new file mode 100644 index 0000000..d666655 --- /dev/null +++ b/src/validators/bgp-extended-community @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# 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 argparse import ArgumentParser +from sys import exit + +from vyos.template import is_ipv4 + +COMM_MAX_2_OCTET: int = 65535 +COMM_MAX_4_OCTET: int = 4294967295 + +if __name__ == '__main__': +    # add an argument with community +    parser: ArgumentParser = ArgumentParser() +    parser.add_argument('community', type=str) +    args = parser.parse_args() + +    for community in args.community.split(): +        if community.count(':') != 1: +            print("Invalid community format") +            exit(1) +        try: +            # try to extract community parts from an argument +            comm_left: str = community.split(':')[0] +            comm_right: int = int(community.split(':')[1]) + +            # check if left part is an IPv4 address +            if is_ipv4(comm_left) and 0 <= comm_right <= COMM_MAX_2_OCTET: +                continue +            # check if a left part is a number +            if 0 <= int(comm_left) <= COMM_MAX_2_OCTET \ +                    and 0 <= comm_right <= COMM_MAX_4_OCTET: +                continue + +            raise Exception() + +        except Exception: +            # fail if something was wrong +            print("Invalid community format") +            exit(1)
\ No newline at end of file diff --git a/src/validators/bgp-large-community b/src/validators/bgp-large-community new file mode 100644 index 0000000..3863983 --- /dev/null +++ b/src/validators/bgp-large-community @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# 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 argparse import ArgumentParser +from sys import exit + +from vyos.template import is_ipv4 + +COMM_MAX_4_OCTET: int = 4294967295 + +if __name__ == '__main__': +    # add an argument with community +    parser: ArgumentParser = ArgumentParser() +    parser.add_argument('community', type=str) +    args = parser.parse_args() +    community: str = args.community +    if community.count(':') != 2: +        print("Invalid community format") +        exit(1) +    try: +        # try to extract community parts from an argument +        comm_part1: int = int(community.split(':')[0]) +        comm_part2: int = int(community.split(':')[1]) +        comm_part3: int = int(community.split(':')[2]) + +        # check compatibilities of left and right parts +        if 0 <= comm_part1 <= COMM_MAX_4_OCTET \ +                and 0 <= comm_part2 <= COMM_MAX_4_OCTET \ +                and 0 <= comm_part3 <= COMM_MAX_4_OCTET: +            exit(0) + +    except Exception: +        # fail if something was wrong +        print("Invalid community format") +        exit(1) + +    # fail if none of validators catched the value +    print("Invalid community format") +    exit(1)
\ No newline at end of file diff --git a/src/validators/bgp-large-community-list b/src/validators/bgp-large-community-list new file mode 100644 index 0000000..9ba5b27 --- /dev/null +++ b/src/validators/bgp-large-community-list @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021-2023 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 re +import sys + +pattern = '(.*):(.*):(.*)' +allowedChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '+', '*', '?', '^', '$', '(', ')', '[', ']', '{', '}', '|', '\\', ':', '-' } + +if __name__ == '__main__': +    if len(sys.argv) != 2: +        sys.exit(1) + +    value = sys.argv[1].split(':') +    if not len(value) == 3: +        sys.exit(1) + +    if not (re.match(pattern, sys.argv[1]) and set(sys.argv[1]).issubset(allowedChars)): +        sys.exit(1) + +    sys.exit(0) diff --git a/src/validators/bgp-rd-rt b/src/validators/bgp-rd-rt new file mode 100644 index 0000000..b2b69c9 --- /dev/null +++ b/src/validators/bgp-rd-rt @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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 argparse import ArgumentParser +from vyos.template import is_ipv4 + +parser = ArgumentParser() +group = parser.add_mutually_exclusive_group() +group.add_argument('--route-distinguisher', action='store', help='Validate BGP route distinguisher') +group.add_argument('--route-target', action='store', help='Validate one BGP route-target') +group.add_argument('--route-target-multi', action='store', help='Validate multiple, whitespace separated BGP route-targets') +args = parser.parse_args() + +def is_valid(rt): +    """ Verify BGP RD/RT - both can be verified using the same logic """ +    # every RD/RT (route distinguisher/route target) needs to have a colon and +    # must consists of two parts +    value = rt.split(':') +    if len(value) != 2: +        return False + +    # An RD/RT must either be only numbers, or the first part must be an IPv4 +    # address +    if (is_ipv4(value[0]) or value[0].isdigit()) and value[1].isdigit(): +        return True +    return False + +if __name__ == '__main__': +    if args.route_distinguisher: +        if not is_valid(args.route_distinguisher): +            exit(1) + +    elif args.route_target: +        if not is_valid(args.route_target): +            exit(1) + +    elif args.route_target_multi: +        for rt in args.route_target_multi.split(' '): +            if not is_valid(rt): +                exit(1) + +    else: +        parser.print_help() +        exit(1) + +    exit(0) diff --git a/src/validators/bgp-regular-community b/src/validators/bgp-regular-community new file mode 100644 index 0000000..d43a71e --- /dev/null +++ b/src/validators/bgp-regular-community @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 + +# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# 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 argparse import ArgumentParser +from sys import exit + +from vyos.template import is_ipv4 + +COMM_MAX_2_OCTET: int = 65535 + +if __name__ == '__main__': +    # add an argument with community +    parser: ArgumentParser = ArgumentParser() +    parser.add_argument('community', type=str) +    args = parser.parse_args() +    community: str = args.community +    if community.count(':') != 1: +        print("Invalid community format") +        exit(1) +    try: +        # try to extract community parts from an argument +        comm_left: int = int(community.split(':')[0]) +        comm_right: int = int(community.split(':')[1]) + +        # check compatibilities of left and right parts +        if 0 <= comm_left <= COMM_MAX_2_OCTET \ +                and 0 <= comm_right <= COMM_MAX_2_OCTET: +            exit(0) +    except Exception: +        # fail if something was wrong +        print("Invalid community format") +        exit(1) + +    # fail if none of validators catched the value +    print("Invalid community format") +    exit(1)
\ No newline at end of file diff --git a/src/validators/ddclient-protocol b/src/validators/ddclient-protocol new file mode 100644 index 0000000..ce5efbd --- /dev/null +++ b/src/validators/ddclient-protocol @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Copyright (C) 2023 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/>. + +ddclient -list-protocols | grep -vE 'cloudns|porkbun' | grep -qw $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid protocol, please choose from the supported list of protocols" +    exit 1 +fi + +exit 0 diff --git a/src/validators/fqdn b/src/validators/fqdn new file mode 100644 index 0000000..a65d2d5 --- /dev/null +++ b/src/validators/fqdn @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +${vyos_libexec_dir}/validate-value --regex "[A-Za-z0-9][-.A-Za-z0-9]*" --value "$1" diff --git a/src/validators/interface-address b/src/validators/interface-address new file mode 100644 index 0000000..4c20395 --- /dev/null +++ b/src/validators/interface-address @@ -0,0 +1,3 @@ +#!/bin/sh + +ipaddrcheck --is-ipv4-host $1 || ipaddrcheck --is-ipv6-host $1  diff --git a/src/validators/ip-address b/src/validators/ip-address new file mode 100644 index 0000000..11d6df0 --- /dev/null +++ b/src/validators/ip-address @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-any-single $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IP address" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ip-cidr b/src/validators/ip-cidr new file mode 100644 index 0000000..60d2ac2 --- /dev/null +++ b/src/validators/ip-cidr @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-any-cidr $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IP CIDR" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ip-host b/src/validators/ip-host new file mode 100644 index 0000000..77c578f --- /dev/null +++ b/src/validators/ip-host @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-any-host $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IP host" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ip-prefix b/src/validators/ip-prefix new file mode 100644 index 0000000..e5a64fe --- /dev/null +++ b/src/validators/ip-prefix @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-any-net $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IP prefix" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ip-protocol b/src/validators/ip-protocol new file mode 100644 index 0000000..c4c8825 --- /dev/null +++ b/src/validators/ip-protocol @@ -0,0 +1,42 @@ +#!/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/>. + +import re +from sys import argv,exit + +if __name__ == '__main__': +    if len(argv) != 2: +        exit(1) + +    input = argv[1] +    try: +        # IP protocol can be in the range 0 - 255, thus the range must end with 256 +        if int(input) in range(0, 256): +            exit(0) +    except ValueError: +        pass + +    pattern = "!?\\b(all|ip|hopopt|icmp|igmp|ggp|ipencap|st|tcp|egp|igp|pup|udp|" \ +              "tcp_udp|hmp|xns-idp|rdp|iso-tp4|dccp|xtp|ddp|idpr-cmtp|ipv6|" \ +              "ipv6-route|ipv6-frag|idrp|rsvp|gre|esp|ah|skip|ipv6-icmp|icmpv6|" \ +              "ipv6-nonxt|ipv6-opts|rspf|vmtp|eigrp|ospf|ax.25|ipip|etherip|" \ +              "encap|99|pim|ipcomp|vrrp|l2tp|isis|sctp|fc|mobility-header|" \ +              "udplite|mpls-in-ip|manet|hip|shim6|wesp|rohc)\\b" +    if re.match(pattern, input): +        exit(0) + +    print(f'Error: {input} is not a valid IP protocol') +    exit(1) diff --git a/src/validators/ipv4 b/src/validators/ipv4 new file mode 100644 index 0000000..8676d58 --- /dev/null +++ b/src/validators/ipv4 @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv4 $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not IPv4" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv4-address b/src/validators/ipv4-address new file mode 100644 index 0000000..058db08 --- /dev/null +++ b/src/validators/ipv4-address @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv4-single $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IPv4 address" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv4-address-exclude b/src/validators/ipv4-address-exclude new file mode 100644 index 0000000..80ad17d --- /dev/null +++ b/src/validators/ipv4-address-exclude @@ -0,0 +1,7 @@ +#!/bin/sh +arg="$1" +if [ "${arg:0:1}" != "!" ]; then +  exit 1 +fi +path=$(dirname "$0") +${path}/ipv4-address "${arg:1}" diff --git a/src/validators/ipv4-host b/src/validators/ipv4-host new file mode 100644 index 0000000..74b8c36 --- /dev/null +++ b/src/validators/ipv4-host @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv4-host $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IPv4 host" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv4-multicast b/src/validators/ipv4-multicast new file mode 100644 index 0000000..3f28c51 --- /dev/null +++ b/src/validators/ipv4-multicast @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv4-multicast $1 && ipaddrcheck --is-ipv4-single $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IPv4 multicast address" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv4-prefix b/src/validators/ipv4-prefix new file mode 100644 index 0000000..7e1e0e8 --- /dev/null +++ b/src/validators/ipv4-prefix @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv4-net $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IPv4 prefix" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv4-prefix-exclude b/src/validators/ipv4-prefix-exclude new file mode 100644 index 0000000..4f7de40 --- /dev/null +++ b/src/validators/ipv4-prefix-exclude @@ -0,0 +1,7 @@ +#!/bin/sh +arg="$1" +if [ "${arg:0:1}" != "!" ]; then +  exit 1 +fi +path=$(dirname "$0") +${path}/ipv4-prefix "${arg:1}" diff --git a/src/validators/ipv4-range b/src/validators/ipv4-range new file mode 100644 index 0000000..6492bfc --- /dev/null +++ b/src/validators/ipv4-range @@ -0,0 +1,40 @@ +#!/bin/bash + +# snippet from https://stackoverflow.com/questions/10768160/ip-address-converter +ip2dec () { +    local a b c d ip=$@ +    IFS=. read -r a b c d <<< "$ip" +    printf '%d\n' "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))" +} + +error_exit() { +  echo "Error: $1 is not a valid IPv4 address range" +  exit 1 +} + +# Only run this if there is a hypen present in $1 +if [[ "$1" =~ "-" ]]; then +  # This only works with real bash (<<<) - split IP addresses into array with +  # hyphen as delimiter +  readarray -d - -t strarr <<< $1 + +  ipaddrcheck --is-ipv4-single ${strarr[0]} +  if [ $? -gt 0 ]; then +    error_exit $1 +  fi + +  ipaddrcheck --is-ipv4-single ${strarr[1]} +  if [ $? -gt 0 ]; then +    error_exit $1 +  fi + +  start=$(ip2dec ${strarr[0]}) +  stop=$(ip2dec ${strarr[1]}) +  if [ $start -ge $stop ]; then +    error_exit $1 +  fi + +  exit 0 +fi + +error_exit $1 diff --git a/src/validators/ipv4-range-exclude b/src/validators/ipv4-range-exclude new file mode 100644 index 0000000..3787b4d --- /dev/null +++ b/src/validators/ipv4-range-exclude @@ -0,0 +1,7 @@ +#!/bin/sh +arg="$1" +if [ "${arg:0:1}" != "!" ]; then +  exit 1 +fi +path=$(dirname "$0") +${path}/ipv4-range "${arg:1}" diff --git a/src/validators/ipv4-range-mask b/src/validators/ipv4-range-mask new file mode 100644 index 0000000..9373328 --- /dev/null +++ b/src/validators/ipv4-range-mask @@ -0,0 +1,27 @@ +#!/bin/bash + +error_exit() { +  echo "Error: $1 is not a valid IPv4 address range or these IPs are not under /$2" +  exit 1 +} + +# Check if address range is under the same netmask +# -m - mask +# -r - IP range in format x.x.x.x-y.y.y.y +while getopts m:r: flag +do +    case "${flag}" in +        m) mask=${OPTARG};; +        r) range=${OPTARG} +    esac +done + +if [[ "${range}" =~ "-" ]]&&[[ ! -z ${mask} ]]; then +  ipaddrcheck --range-prefix-length ${mask} --is-ipv4-range ${range} +  if [ $? -gt 0 ]; then +    error_exit ${range} ${mask} +  fi +  exit 0 +fi + +error_exit ${range} ${mask} diff --git a/src/validators/ipv6 b/src/validators/ipv6 new file mode 100644 index 0000000..4ae130e --- /dev/null +++ b/src/validators/ipv6 @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv6 $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not IPv6" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv6-address b/src/validators/ipv6-address new file mode 100644 index 0000000..1fca776 --- /dev/null +++ b/src/validators/ipv6-address @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv6-single $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IPv6 address" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv6-address-exclude b/src/validators/ipv6-address-exclude new file mode 100644 index 0000000..be1d3db --- /dev/null +++ b/src/validators/ipv6-address-exclude @@ -0,0 +1,7 @@ +#!/bin/sh +arg="$1" +if [ "${arg:0:1}" != "!" ]; then +  exit 1 +fi +path=$(dirname "$0") +${path}/ipv6-address "${arg:1}" diff --git a/src/validators/ipv6-eui64-prefix b/src/validators/ipv6-eui64-prefix new file mode 100644 index 0000000..d7f2626 --- /dev/null +++ b/src/validators/ipv6-eui64-prefix @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +# Validator used to check if given IPv6 prefix is of size /64 required by EUI64 + +from sys import argv +from sys import exit + +if __name__ == '__main__': +    if len(argv) != 2: +        exit(1) + +    prefix = argv[1] +    if prefix.split('/')[1] == '64': +        exit(0) + +    exit(1) diff --git a/src/validators/ipv6-exclude b/src/validators/ipv6-exclude new file mode 100644 index 0000000..893eeab --- /dev/null +++ b/src/validators/ipv6-exclude @@ -0,0 +1,7 @@ +#!/bin/sh +arg="$1" +if [ "${arg:0:1}" != "!" ]; then +  exit 1 +fi +path=$(dirname "$0") +${path}/ipv6 "${arg:1}" diff --git a/src/validators/ipv6-host b/src/validators/ipv6-host new file mode 100644 index 0000000..7085809 --- /dev/null +++ b/src/validators/ipv6-host @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv6-host $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IPv6 host" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv6-link-local b/src/validators/ipv6-link-local new file mode 100644 index 0000000..6ac3ea7 --- /dev/null +++ b/src/validators/ipv6-link-local @@ -0,0 +1,12 @@ +#!/usr/bin/python3 + +import sys +from vyos.utils.network import is_ipv6_link_local + +if __name__ == '__main__': +    if len(sys.argv)>1: +        addr = sys.argv[1] +        if not is_ipv6_link_local(addr): +            sys.exit(1) + +    sys.exit(0) diff --git a/src/validators/ipv6-multicast b/src/validators/ipv6-multicast new file mode 100644 index 0000000..5aa7d73 --- /dev/null +++ b/src/validators/ipv6-multicast @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv6-multicast $1 && ipaddrcheck --is-ipv6-single $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IPv6 multicast address" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv6-prefix b/src/validators/ipv6-prefix new file mode 100644 index 0000000..890dda7 --- /dev/null +++ b/src/validators/ipv6-prefix @@ -0,0 +1,10 @@ +#!/bin/sh + +ipaddrcheck --is-ipv6-net $1 + +if [ $? -gt 0 ]; then +    echo "Error: $1 is not a valid IPv6 prefix" +    exit 1 +fi + +exit 0
\ No newline at end of file diff --git a/src/validators/ipv6-prefix-exclude b/src/validators/ipv6-prefix-exclude new file mode 100644 index 0000000..6fa4f1d --- /dev/null +++ b/src/validators/ipv6-prefix-exclude @@ -0,0 +1,7 @@ +#!/bin/sh +arg="$1" +if [ "${arg:0:1}" != "!" ]; then +  exit 1 +fi +path=$(dirname "$0") +${path}/ipv6-prefix "${arg:1}" diff --git a/src/validators/ipv6-range b/src/validators/ipv6-range new file mode 100644 index 0000000..7080860 --- /dev/null +++ b/src/validators/ipv6-range @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +from ipaddress import IPv6Address +from sys import argv, exit + +if __name__ == '__main__': +    if len(argv) > 1: +        # try to pass validation and raise an error if failed +        try: +            ipv6_range = argv[1] +            range_left = ipv6_range.split('-')[0] +            range_right = ipv6_range.split('-')[1] +            if not IPv6Address(range_left) < IPv6Address(range_right): +                raise ValueError(f'left element {range_left} must be less than right element {range_right}') +        except Exception as err: +            print(f'Error: {ipv6_range} is not a valid IPv6 range: {err}') +            exit(1) +    else: +        print('Error: an IPv6 range argument must be provided') +        exit(1) diff --git a/src/validators/ipv6-range-exclude b/src/validators/ipv6-range-exclude new file mode 100644 index 0000000..912b55a --- /dev/null +++ b/src/validators/ipv6-range-exclude @@ -0,0 +1,7 @@ +#!/bin/sh +arg="$1" +if [ "${arg:0:1}" != "!" ]; then +  exit 1 +fi +path=$(dirname "$0") +${path}/ipv6-range "${arg:1}" diff --git a/src/validators/ipv6-srv6-segments b/src/validators/ipv6-srv6-segments new file mode 100644 index 0000000..e72a4f9 --- /dev/null +++ b/src/validators/ipv6-srv6-segments @@ -0,0 +1,13 @@ +#!/bin/sh +segments="$1" +export IFS="/" + +for ipv6addr in $segments; do +    ipaddrcheck --is-ipv6-single $ipv6addr +    if [ $? -gt 0 ]; then +        echo "Error: $1 is not a valid IPv6 address" +        exit 1 +    fi +done +exit 0 + diff --git a/src/validators/mac-address b/src/validators/mac-address new file mode 100644 index 0000000..bb859a6 --- /dev/null +++ b/src/validators/mac-address @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +${vyos_libexec_dir}/validate-value --regex "([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})" --value "$1" diff --git a/src/validators/mac-address-exclude b/src/validators/mac-address-exclude new file mode 100644 index 0000000..c449130 --- /dev/null +++ b/src/validators/mac-address-exclude @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +${vyos_libexec_dir}/validate-value --regex "!([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})" --value "$1" diff --git a/src/validators/numeric-exclude b/src/validators/numeric-exclude new file mode 100644 index 0000000..676a240 --- /dev/null +++ b/src/validators/numeric-exclude @@ -0,0 +1,8 @@ +#!/bin/sh +path=$(dirname "$0") +num="${@: -1}" +if [ "${num:0:1}" != "!" ]; then +   ${path}/numeric $@ +else +    ${path}/numeric ${@:1:$#-1} ${num:1} +fi diff --git a/src/validators/port-multi b/src/validators/port-multi new file mode 100644 index 0000000..ed6ff68 --- /dev/null +++ b/src/validators/port-multi @@ -0,0 +1,52 @@ +#!/usr/bin/python3 + +from sys import argv +from sys import exit +import re + +from vyos.utils.file import read_file + +services_file = '/etc/services' + +def get_services(): +    names = [] +    service_data = read_file(services_file, "") +    for line in service_data.split("\n"): +        if not line or line[0] == '#': +            continue +        tmp = line.split() +        names.append(tmp[0]) +        if len(tmp) > 2: +            # Add port aliases to service list, too +            names.extend(tmp[2:]) +    # remove duplicate entries (e.g. echo) from list +    names = list(dict.fromkeys(names)) +    return names + +if __name__ == '__main__': +    if len(argv)>1: +        ports = argv[1].split(",") +        services = get_services() + +        for port in ports: +            if port and port[0] == '!': +                port = port[1:] +            if re.match('^[0-9]{1,5}-[0-9]{1,5}$', port): +                port_1, port_2 = port.split('-') +                if int(port_1) not in range(1, 65536) or int(port_2) not in range(1, 65536): +                    print(f'Error: {port} is not a valid port range') +                    exit(1) +                if int(port_1) > int(port_2): +                    print(f'Error: {port} is not a valid port range') +                    exit(1) +            elif port.isnumeric(): +                if int(port) not in range(1, 65536): +                    print(f'Error: {port} is not a valid port') +                    exit(1) +            elif port not in services: +                print(f'Error: {port} is not a valid service name') +                exit(1) +    else: +        exit(2) + +    exit(0) diff --git a/src/validators/port-range b/src/validators/port-range new file mode 100644 index 0000000..526c639 --- /dev/null +++ b/src/validators/port-range @@ -0,0 +1,40 @@ +#!/usr/bin/python3 + +import sys +import re + +from vyos.utils.file import read_file + +services_file = '/etc/services' + +def get_services(): +    names = [] +    service_data = read_file(services_file, "") +    for line in service_data.split("\n"): +        if not line or line[0] == '#': +            continue +        names.append(line.split(None, 1)[0]) +    return names + +def error(port_range): +    print(f'Error: {port_range} is not a valid port or port range') +    sys.exit(1) + +if __name__ == '__main__': +    if len(sys.argv)>1: +        port_range = sys.argv[1] +        if re.match('^[0-9]{1,5}-[0-9]{1,5}$', port_range): +            port_1, port_2 = port_range.split('-') +            if int(port_1) not in range(1, 65536) or int(port_2) not in range(1, 65536): +                error(port_range) +            if int(port_1) > int(port_2): +                error(port_range) +        elif port_range.isnumeric() and int(port_range) not in range(1, 65536): +            error(port_range) +        elif not port_range.isnumeric() and port_range not in get_services(): +            print(f'Error: {port_range} is not a valid service name') +            sys.exit(1) +    else: +        sys.exit(2) + +    sys.exit(0) diff --git a/src/validators/script b/src/validators/script new file mode 100644 index 0000000..eb176d2 --- /dev/null +++ b/src/validators/script @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2018-2023 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 +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 sys +import shlex + +from vyos.utils.file import file_is_persistent + +if __name__ == '__main__': +    if len(sys.argv) < 2: +        sys.exit('Please specify script file to check') + +    # if the "script" is a script+ stowaway arguments, this removes the aguements +    script = shlex.split(sys.argv[1])[0] + +    if not os.path.exists(script): +        sys.exit(f'File {script} does not exist') + +    if not (os.path.isfile(script) and os.access(script, os.X_OK)): +        sys.exit(f'File {script} is not an executable file') + +    # File outside the config dir is just a warning +    if not file_is_persistent(script): +        sys.exit(0)( +            f'Warning: file {script} is outside the "/config" directory\n' +            'It will not be automatically migrated to a new image on system update' +        ) diff --git a/src/validators/sysctl b/src/validators/sysctl new file mode 100644 index 0000000..9b5bba3 --- /dev/null +++ b/src/validators/sysctl @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Copyright (C) 2021 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/>. + +declare -a array +eval "array=($(/sbin/sysctl -N -a))" + +if [[ ! " ${array[@]} " =~ " $1 " ]]; then +    # passed sysctl option is invalid +    exit 1 +fi +exit 0 diff --git a/src/validators/timezone b/src/validators/timezone new file mode 100644 index 0000000..e55af8d --- /dev/null +++ b/src/validators/timezone @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019-2023 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 argparse +import sys + +from vyos.utils.process import cmd + + +if __name__ == '__main__': +    parser = argparse.ArgumentParser() +    parser.add_argument("--validate", action="store", required=True, help="Check if timezone is valid") +    args = parser.parse_args() + +    tz_data = cmd('timedatectl list-timezones') +    tz_data = tz_data.split('\n') + +    if args.validate not in tz_data: +        sys.exit("the timezone can't be found in the timezone list") +    sys.exit() diff --git a/src/validators/vrf-name b/src/validators/vrf-name new file mode 100644 index 0000000..29167c6 --- /dev/null +++ b/src/validators/vrf-name @@ -0,0 +1,41 @@ +#!/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/>. + +import re +from sys import argv, exit + +if __name__ == '__main__': +    if len(argv) != 2: +        exit(1) + +    vrf = argv[1] +    length = len(vrf) + +    if length not in range(1, 16): +        exit(1) + +    # Treat loopback interface "lo" explicitly. Adding "lo" explicitly to the +    # following regex pattern would deny any VRF name starting with lo - thuse +    # local-vrf would be illegal - and that we do not want. +    if vrf == "lo": +        exit(1) + +    pattern = r'^(?!(bond|br|dum|eth|lan|eno|ens|enp|enx|gnv|ipoe|l2tp|l2tpeth|\ +       vtun|ppp|pppoe|peth|tun|vti|vxlan|wg|wlan|wwan|\d)\d*(\.\d+)?(v.+)?).*$' +    if not re.match(pattern, vrf): +        exit(1) + +    exit(0) diff --git a/src/validators/wireless-phy b/src/validators/wireless-phy new file mode 100644 index 0000000..513a902 --- /dev/null +++ b/src/validators/wireless-phy @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Copyright (C) 2018-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/>. + +if [ ! -d /sys/class/ieee80211 ]; then +    echo No IEEE 802.11 physical interfaces detected +    exit 1 +fi + +if [ ! -e /sys/class/ieee80211/$1 ]; then +    echo Device interface "$1" does not exist +    exit 1 +fi | 
