diff options
92 files changed, 3432 insertions, 483 deletions
| diff --git a/data/op-mode-standardized.json b/data/op-mode-standardized.json index 7c5524675..abf562984 100644 --- a/data/op-mode-standardized.json +++ b/data/op-mode-standardized.json @@ -2,6 +2,7 @@  "accelppp.py",  "bgp.py",  "bridge.py", +"config_mgmt.py",  "conntrack.py",  "container.py",  "cpu.py", @@ -21,5 +22,6 @@  "storage.py",  "uptime.py",  "version.py", -"vrf.py" +"vrf.py", +"zone.py"  ] diff --git a/data/templates/high-availability/keepalived.conf.j2 b/data/templates/high-availability/keepalived.conf.j2 index ebff52e1f..6ea5f91d0 100644 --- a/data/templates/high-availability/keepalived.conf.j2 +++ b/data/templates/high-availability/keepalived.conf.j2 @@ -2,9 +2,30 @@  # Do not edit this file, all your changes will be lost  # on next commit or reboot +# Global definitions configuration block  global_defs {      dynamic_interfaces      script_user root +{% if vrrp.global_parameters.startup_delay is vyos_defined %} +    vrrp_startup_delay {{ vrrp.global_parameters.startup_delay }} +{% endif %} +{% if vrrp.global_parameters.garp is vyos_defined %} +{%     if vrrp.global_parameters.garp.interval is vyos_defined %} +    vrrp_garp_interval {{ vrrp.global_parameters.garp.interval }} +{%     endif %} +{%     if vrrp.global_parameters.garp.master_delay is vyos_defined %} +    vrrp_garp_master_delay {{ vrrp.global_parameters.garp.master_delay }} +{%     endif %} +{%     if vrrp.global_parameters.garp.master_refresh is vyos_defined %} +    vrrp_garp_master_refresh {{ vrrp.global_parameters.garp.master_refresh }} +{%     endif %} +{%     if vrrp.global_parameters.garp.master_refresh_repeat is vyos_defined %} +    vrrp_garp_master_refresh_repeat {{ vrrp.global_parameters.garp.master_refresh_repeat }} +{%     endif %} +{%     if vrrp.global_parameters.garp.master_repeat is vyos_defined %} +    vrrp_garp_master_repeat {{ vrrp.global_parameters.garp.master_repeat }} +{%     endif %} +{% endif %}      notify_fifo /run/keepalived/keepalived_notify_fifo      notify_fifo_script /usr/libexec/vyos/system/keepalived-fifo.py  } @@ -28,6 +49,23 @@ vrrp_instance {{ name }} {      virtual_router_id {{ group_config.vrid }}      priority {{ group_config.priority }}      advert_int {{ group_config.advertise_interval }} +{%         if group_config.garp is vyos_defined %} +{%             if group_config.garp.interval is vyos_defined %} +    garp_interval {{ group_config.garp.interval }} +{%             endif %} +{%             if group_config.garp.master_delay is vyos_defined %} +    garp_master_delay {{ group_config.garp.master_delay }} +{%             endif %} +{%             if group_config.garp.master_repeat is vyos_defined %} +    garp_master_repeat {{ group_config.garp.master_repeat }} +{%             endif %} +{%             if group_config.garp.master_refresh is vyos_defined %} +    garp_master_refresh {{ group_config.garp.master_refresh }} +{%             endif %} +{%             if group_config.garp.master_refresh_repeat is vyos_defined %} +    garp_master_refresh_repeat {{ group_config.garp.master_refresh_repeat }} +{%             endif %} +{%         endif %}  {%         if group_config.track.exclude_vrrp_interface is vyos_defined %}      dont_track_primary  {%         endif %} diff --git a/data/templates/ocserv/ocserv_config.j2 b/data/templates/ocserv/ocserv_config.j2 index 3194354e6..aa1073bca 100644 --- a/data/templates/ocserv/ocserv_config.j2 +++ b/data/templates/ocserv/ocserv_config.j2 @@ -10,6 +10,10 @@ udp-port = {{ listen_ports.udp }}  run-as-user = nobody  run-as-group = daemon +{% if accounting.mode.radius is vyos_defined %} +acct = "radius [config=/run/ocserv/radiusclient.conf]" +{% endif %} +  {% if "radius" in authentication.mode %}  auth = "radius [config=/run/ocserv/radiusclient.conf{{ ',groupconfig=true' if authentication.radius.groupconfig is vyos_defined else '' }}]"  {% elif "local" in authentication.mode %} diff --git a/data/templates/ocserv/radius_conf.j2 b/data/templates/ocserv/radius_conf.j2 index b6612fee5..1ab322f69 100644 --- a/data/templates/ocserv/radius_conf.j2 +++ b/data/templates/ocserv/radius_conf.j2 @@ -1,20 +1,34 @@  ### generated by vpn_openconnect.py ###  nas-identifier VyOS -{% for srv in server %} -{%     if not "disable" in server[srv] %} -{%         if "port" in server[srv] %} -authserver {{ srv }}:{{ server[srv]["port"] }} + +#### Accounting +{% if accounting.mode.radius is vyos_defined %} +{%     for acctsrv, srv_conf in accounting.radius.server.items() if 'disable' not in srv_conf %} +{%         if srv_conf.port is vyos_defined %} +acctserver {{ acctsrv }}:{{ srv_conf.port }}  {%         else %} -authserver {{ srv }} +acctserver {{ acctsrv }}  {%         endif %} -{%     endif %} -{% endfor %} -radius_timeout {{ timeout }} -{% if source_address %} -bindaddr {{ source_address }} -{% else %} +{%     endfor %} +{% endif %} + +#### Authentication +{% if authentication.mode.radius is vyos_defined %} +{%     for authsrv, srv_conf in authentication.radius.server.items() if 'disable' not in srv_conf %} +{%         if srv_conf.port is vyos_defined %} +authserver {{ authsrv }}:{{ srv_conf.port }} +{%         else %} +authserver {{ authsrv }} +{%         endif %} +{%     endfor %} +radius_timeout {{ authentication['radius']['timeout'] }} +{%     if source_address %} +bindaddr {{ authentication['radius']['source_address'] }} +{%     else %}  bindaddr * +{%     endif %}  {% endif %} +  servers /run/ocserv/radius_servers  dictionary /etc/radcli/dictionary  default_realm diff --git a/data/templates/pppoe/peer.j2 b/data/templates/pppoe/peer.j2 index 6221abb9b..f433a9b03 100644 --- a/data/templates/pppoe/peer.j2 +++ b/data/templates/pppoe/peer.j2 @@ -36,10 +36,13 @@ maxfail 0  plugin rp-pppoe.so {{ source_interface }}  {% if access_concentrator is vyos_defined %} -rp_pppoe_ac '{{ access_concentrator }}' +pppoe-ac "{{ access_concentrator }}"  {% endif %}  {% if service_name is vyos_defined %} -rp_pppoe_service '{{ service_name }}' +pppoe-service "{{ service_name }}" +{% endif %} +{% if host_uniq is vyos_defined %} +pppoe-host-uniq "{{ host_uniq }}"  {% endif %}  persist diff --git a/data/templates/snmp/etc.snmpd.conf.j2 b/data/templates/snmp/etc.snmpd.conf.j2 index 47bf6878f..793facc3f 100644 --- a/data/templates/snmp/etc.snmpd.conf.j2 +++ b/data/templates/snmp/etc.snmpd.conf.j2 @@ -26,6 +26,9 @@ monitor  -r 10 -e linkDownTrap "Generate linkDown" ifOperStatus == 2  # interface (with different ifIndex) - this is the case on e.g. ppp interfaces  interface_replace_old yes +# T4902: exclude container storage from monitoring +ignoreDisk /usr/lib/live/mount/persistence/container +  ########################  # configurable section #  ######################## @@ -59,28 +62,47 @@ agentaddress unix:/run/snmpd.socket{{ ',' ~ options | join(',') if options is vy  {%         if comm_config.client is vyos_defined %}  {%             for client in comm_config.client %}  {%                 if client | is_ipv4 %} -{{ comm_config.authorization }}community {{ comm }} {{ client }} +{{ comm_config.authorization }}community {{ comm }} {{ client }} -V RESTRICTED  {%                 elif client | is_ipv6 %} -{{ comm_config.authorization }}community6 {{ comm }} {{ client }} +{{ comm_config.authorization }}community6 {{ comm }} {{ client }} -V RESTRICTED  {%                 endif %}  {%             endfor %}  {%         endif %}  {%         if comm_config.network is vyos_defined %}  {%             for network in comm_config.network %}  {%                 if network | is_ipv4 %} -{{ comm_config.authorization }}community {{ comm }} {{ network }} +{{ comm_config.authorization }}community {{ comm }} {{ network }} -V RESTRICTED  {%                 elif network | is_ipv6 %} -{{ comm_config.authorization }}community6 {{ comm }} {{ network }} +{{ comm_config.authorization }}community6 {{ comm }} {{ network }} -V RESTRICTED  {%                 endif %}  {%             endfor %}  {%         endif %}  {%         if comm_config.client is not vyos_defined and comm_config.network is not vyos_defined %} -{{ comm_config.authorization }}community {{ comm }} -{{ comm_config.authorization }}community6 {{ comm }} +{{ comm_config.authorization }}community {{ comm }} -V RESTRICTED +{{ comm_config.authorization }}community6 {{ comm }} -V RESTRICTED  {%         endif %}  {%     endfor %}  {% endif %} +# Default RESTRICTED view +view RESTRICTED    included .1 80 +{% if 'ip-route-table' not in oid_enable %} +# ipRouteTable oid: excluded +view RESTRICTED    excluded  .1.3.6.1.2.1.4.21 +{% endif %} +{% if 'ip-net-to-media-table' not in oid_enable %} +# ipNetToMediaTable oid: excluded +view RESTRICTED    excluded  .1.3.6.1.2.1.4.22 +{% endif %} +{% if 'ip-net-to-physical-phys-address' not in oid_enable %} +# ipNetToPhysicalPhysAddress oid: excluded +view RESTRICTED    excluded  .1.3.6.1.2.1.4.35 +{% endif %} +{% if 'ip-forward' not in oid_enable %} +# ipForward oid: excluded +view RESTRICTED    excluded  .1.3.6.1.2.1.4.24 +{% endif %} +  {% if contact is vyos_defined %}  # system contact information  SysContact {{ contact }} diff --git a/data/templates/snmp/override.conf.j2 b/data/templates/snmp/override.conf.j2 index 5d787de86..443ee64db 100644 --- a/data/templates/snmp/override.conf.j2 +++ b/data/templates/snmp/override.conf.j2 @@ -1,5 +1,4 @@  {% set vrf_command = 'ip vrf exec ' ~ vrf ~ ' ' if vrf is vyos_defined else '' %} -{% set oid_route_table = ' ' if oid_enable is vyos_defined('route-table') else '-I -ipCidrRouteTable,inetCidrRouteTable' %}  [Unit]  StartLimitIntervalSec=0  After=vyos-router.service @@ -8,7 +7,7 @@ After=vyos-router.service  Environment=  Environment="MIBDIRS=/usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf:/usr/share/vyos/mibs"  ExecStart= -ExecStart={{ vrf_command }}/usr/sbin/snmpd -LS0-5d -Lf /dev/null -u Debian-snmp -g Debian-snmp {{ oid_route_table }} -f -p /run/snmpd.pid +ExecStart={{ vrf_command }}/usr/sbin/snmpd -LS0-5d -Lf /dev/null -u Debian-snmp -g Debian-snmp -f -p /run/snmpd.pid  Restart=always  RestartSec=10 diff --git a/debian/vyos-1x.install b/debian/vyos-1x.install index edd090993..11b488b22 100644 --- a/debian/vyos-1x.install +++ b/debian/vyos-1x.install @@ -3,6 +3,7 @@ etc/ipsec.d  etc/logrotate.d  etc/netplug  etc/opennhrp +etc/modprobe.d  etc/ppp  etc/rsyslog.d  etc/securetty @@ -17,6 +18,7 @@ etc/vyos  lib/  opt/  usr/sbin +usr/bin/config-mgmt  usr/bin/initial-setup  usr/bin/vyos-config-file-query  usr/bin/vyos-config-to-commands diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in index 4bac305d1..b61664125 100644 --- a/interface-definitions/container.xml.in +++ b/interface-definitions/container.xml.in @@ -274,6 +274,26 @@                    </valueHelp>                  </properties>                </leafNode> +              <leafNode name="mode"> +                <properties> +                  <help>Volume access mode ro/rw</help> +                  <completionHelp> +                    <list>ro rw</list> +                  </completionHelp> +                  <valueHelp> +                    <format>ro</format> +                    <description>Volume mounted into the container as read-only</description> +                  </valueHelp> +                  <valueHelp> +                    <format>rw</format> +                    <description>Volume mounted into the container as read-write</description> +                  </valueHelp> +                  <constraint> +                    <regex>(ro|rw)</regex> +                  </constraint> +                </properties> +                <defaultValue>rw</defaultValue> +              </leafNode>              </children>            </tagNode>          </children> diff --git a/interface-definitions/high-availability.xml.in b/interface-definitions/high-availability.xml.in index d67a142d1..6cb40247a 100644 --- a/interface-definitions/high-availability.xml.in +++ b/interface-definitions/high-availability.xml.in @@ -11,12 +11,33 @@            <help>Virtual Router Redundancy Protocol settings</help>          </properties>          <children> +          <node name="global-parameters"> +            <properties> +              <help>VRRP global parameters</help> +            </properties> +            <children> +              #include <include/vrrp/garp.xml.i> +              <leafNode name="startup-delay"> +                <properties> +                  <help>Time VRRP startup process (in seconds)</help> +                  <valueHelp> +                    <format>u32:1-600</format> +                    <description>Interval in seconds</description> +                  </valueHelp> +                  <constraint> +                    <validator name="numeric" argument="--range 1-600"/> +                  </constraint> +                </properties> +              </leafNode> +            </children> +          </node>            <tagNode name="group">              <properties>                <help>VRRP group</help>              </properties>              <children>                #include <include/generic-interface-broadcast.xml.i> +              #include <include/vrrp/garp.xml.i>                <leafNode name="advertise-interval">                  <properties>                    <help>Advertise interval</help> @@ -211,16 +232,15 @@                  <properties>                    <help>Virtual IP address</help>                    <valueHelp> -                    <format>ipv4</format> -                    <description>IPv4 virtual address</description> +                    <format>ipv4net</format> +                    <description>IPv4 address and prefix length</description>                    </valueHelp>                    <valueHelp> -                    <format>ipv6</format> -                    <description>IPv6 virtual address</description> +                    <format>ipv6net</format> +                    <description>IPv6 address and prefix length</description>                    </valueHelp>                    <constraint> -                    <validator name="ipv4-host"/> -                    <validator name="ipv6-host"/> +                    <validator name="ip-host"/>                    </constraint>                  </properties>                  <children> diff --git a/interface-definitions/include/generic-description.xml.i b/interface-definitions/include/generic-description.xml.i index b030c2495..63e5e174e 100644 --- a/interface-definitions/include/generic-description.xml.i +++ b/interface-definitions/include/generic-description.xml.i @@ -7,7 +7,7 @@        <description>Description</description>      </valueHelp>      <constraint> -      <regex>[[:ascii:]]{1,256}</regex> +      <regex>[[:ascii:]]{0,256}</regex>      </constraint>      <constraintErrorMessage>Description too long (limit 256 characters)</constraintErrorMessage>    </properties> diff --git a/interface-definitions/include/listen-address-ipv4-single.xml.i b/interface-definitions/include/listen-address-ipv4-single.xml.i new file mode 100644 index 000000000..81e947953 --- /dev/null +++ b/interface-definitions/include/listen-address-ipv4-single.xml.i @@ -0,0 +1,17 @@ +<!-- include start from listen-address-ipv4-single.xml.i --> +<leafNode name="listen-address"> +  <properties> +    <help>Local IPv4 addresses to listen on</help> +    <completionHelp> +      <script>${vyos_completion_dir}/list_local_ips.sh --ipv4</script> +    </completionHelp> +    <valueHelp> +      <format>ipv4</format> +      <description>IPv4 address to listen for incoming connections</description> +    </valueHelp> +    <constraint> +      <validator name="ipv4-address"/> +    </constraint> +  </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/radius-acct-server-ipv4.xml.i b/interface-definitions/include/radius-acct-server-ipv4.xml.i new file mode 100644 index 000000000..9365aa8e9 --- /dev/null +++ b/interface-definitions/include/radius-acct-server-ipv4.xml.i @@ -0,0 +1,26 @@ +<!-- include start from radius-acct-server-ipv4.xml.i --> +<node name="radius"> +  <properties> +    <help>RADIUS accounting for users OpenConnect VPN sessions OpenConnect authentication mode radius</help> +  </properties> +  <children> +    <tagNode name="server"> +      <properties> +        <help>RADIUS server configuration</help> +        <valueHelp> +          <format>ipv4</format> +          <description>RADIUS server IPv4 address</description> +        </valueHelp> +        <constraint> +          <validator name="ipv4-address"/> +        </constraint> +      </properties> +      <children> +        #include <include/generic-disable-node.xml.i> +        #include <include/radius-server-key.xml.i> +        #include <include/radius-server-acct-port.xml.i> +      </children> +    </tagNode> +  </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/radius-server-ipv4.xml.i b/interface-definitions/include/radius-auth-server-ipv4.xml.i index ab4c8e10e..dc6f4d878 100644 --- a/interface-definitions/include/radius-server-ipv4.xml.i +++ b/interface-definitions/include/radius-auth-server-ipv4.xml.i @@ -1,4 +1,4 @@ -<!-- include start from radius-server-ipv4.xml.i --> +<!-- include start from radius-auth-server-ipv4.xml.i -->  <node name="radius">    <properties>      <help>RADIUS based user authentication</help> @@ -19,7 +19,7 @@        <children>          #include <include/generic-disable-node.xml.i>          #include <include/radius-server-key.xml.i> -        #include <include/radius-server-port.xml.i> +        #include <include/radius-server-auth-port.xml.i>        </children>      </tagNode>    </children> diff --git a/interface-definitions/include/radius-server-acct-port.xml.i b/interface-definitions/include/radius-server-acct-port.xml.i new file mode 100644 index 000000000..0b356fa18 --- /dev/null +++ b/interface-definitions/include/radius-server-acct-port.xml.i @@ -0,0 +1,15 @@ +<!-- include start from radius-server-acct-port.xml.i --> +<leafNode name="port"> +  <properties> +    <help>Accounting port</help> +    <valueHelp> +      <format>u32:1-65535</format> +      <description>Numeric IP port</description> +    </valueHelp> +    <constraint> +      <validator name="numeric" argument="--range 1-65535"/> +    </constraint> +  </properties> +  <defaultValue>1813</defaultValue> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/radius-server-port.xml.i b/interface-definitions/include/radius-server-auth-port.xml.i index c6b691a0f..660fa540f 100644 --- a/interface-definitions/include/radius-server-port.xml.i +++ b/interface-definitions/include/radius-server-auth-port.xml.i @@ -1,4 +1,4 @@ -<!-- include start from radius-server-port.xml.i --> +<!-- include start from radius-server-auth-port.xml.i -->  <leafNode name="port">    <properties>      <help>Authentication port</help> diff --git a/interface-definitions/include/radius-server-ipv4-ipv6.xml.i b/interface-definitions/include/radius-server-ipv4-ipv6.xml.i index 5b12bec62..c593512b4 100644 --- a/interface-definitions/include/radius-server-ipv4-ipv6.xml.i +++ b/interface-definitions/include/radius-server-ipv4-ipv6.xml.i @@ -23,7 +23,7 @@        <children>          #include <include/generic-disable-node.xml.i>          #include <include/radius-server-key.xml.i> -        #include <include/radius-server-port.xml.i> +        #include <include/radius-server-auth-port.xml.i>        </children>      </tagNode>      <leafNode name="source-address"> diff --git a/interface-definitions/include/version/snmp-version.xml.i b/interface-definitions/include/version/snmp-version.xml.i index 0416288f0..fa58672a5 100644 --- a/interface-definitions/include/version/snmp-version.xml.i +++ b/interface-definitions/include/version/snmp-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/snmp-version.xml.i --> -<syntaxVersion component='snmp' version='2'></syntaxVersion> +<syntaxVersion component='snmp' version='3'></syntaxVersion>  <!-- include end --> diff --git a/interface-definitions/include/vrrp/garp.xml.i b/interface-definitions/include/vrrp/garp.xml.i new file mode 100644 index 000000000..b56b490df --- /dev/null +++ b/interface-definitions/include/vrrp/garp.xml.i @@ -0,0 +1,78 @@ +<!-- include start from vrrp/garp.xml.i --> +<node name="garp"> +  <properties> +    <help>Gratuitous ARP parameters</help> +  </properties> +  <children> +    <leafNode name="interval"> +      <properties> +        <help>Interval between Gratuitous ARP</help> +        <valueHelp> +          <format><0.000-1000></format> +          <description>Interval in seconds, resolution microseconds</description> +        </valueHelp> +        <constraint> +          <validator name="numeric" argument="--range 0.000-1000 --float"/> +        </constraint> +      </properties> +      <defaultValue>0</defaultValue> +    </leafNode> +    <leafNode name="master-delay"> +      <properties> +        <help>Delay for second set of gratuitous ARPs after transition to master</help> +        <valueHelp> +          <format>u32:1-1000</format> +          <description>Delay in seconds</description> +        </valueHelp> +        <constraint> +          <validator name="numeric" argument="--range 1-1000"/> +        </constraint> +      </properties> +      <defaultValue>5</defaultValue> +    </leafNode> +    <leafNode name="master-refresh"> +      <properties> +        <help>Minimum time interval for refreshing gratuitous ARPs while beeing master</help> +        <valueHelp> +          <format>u32:0</format> +          <description>No refresh</description> +        </valueHelp> +        <valueHelp> +          <format>u32:1-255</format> +          <description>Interval in seconds</description> +        </valueHelp> +        <constraint> +          <validator name="numeric" argument="--range 1-255"/> +        </constraint> +      </properties> +      <defaultValue>5</defaultValue> +    </leafNode> +    <leafNode name="master-refresh-repeat"> +      <properties> +        <help>Number of gratuitous ARP messages to send at a time while beeing master</help> +        <valueHelp> +          <format>u32:1-255</format> +          <description>Number of gratuitous ARP messages</description> +        </valueHelp> +        <constraint> +          <validator name="numeric" argument="--range 1-255"/> +        </constraint> +      </properties> +      <defaultValue>1</defaultValue> +    </leafNode> +    <leafNode name="master-repeat"> +      <properties> +        <help>Number of gratuitous ARP messages to send at a time after transition to master</help> +        <valueHelp> +          <format>u32:1-255</format> +          <description>Number of gratuitous ARP messages</description> +        </valueHelp> +        <constraint> +          <validator name="numeric" argument="--range 1-255"/> +        </constraint> +      </properties> +      <defaultValue>5</defaultValue> +    </leafNode> +  </children> +</node> +<!-- include end --> diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in index 490f41471..c6fd7096b 100644 --- a/interface-definitions/interfaces-pppoe.xml.in +++ b/interface-definitions/interfaces-pppoe.xml.in @@ -37,6 +37,19 @@                <constraintErrorMessage>Timeout must be in range 0 to 86400</constraintErrorMessage>              </properties>            </leafNode> +          <leafNode name="host-uniq"> +            <properties> +              <help>PPPoE RFC2516 host-uniq tag</help> +              <valueHelp> +                <format>txt</format> +                <description>Host-uniq tag as byte string in HEX</description> +              </valueHelp> +              <constraint> +                <regex>([a-fA-F0-9][a-fA-F0-9]){1,18}</regex> +              </constraint> +              <constraintErrorMessage>Host-uniq must be specified as hex-adecimal byte-string (even number of HEX characters)</constraintErrorMessage> +            </properties> +          </leafNode>            <node name="ip">              <properties>                <help>IPv4 routing parameters</help> diff --git a/interface-definitions/interfaces-wireless.xml.in b/interface-definitions/interfaces-wireless.xml.in index aff5071b2..a9538d577 100644 --- a/interface-definitions/interfaces-wireless.xml.in +++ b/interface-definitions/interfaces-wireless.xml.in @@ -725,7 +725,7 @@                        <constraintErrorMessage>Invalid WPA pass phrase, must be 8 to 63 printable characters!</constraintErrorMessage>                      </properties>                    </leafNode> -                  #include <include/radius-server-ipv4.xml.i> +                  #include <include/radius-auth-server-ipv4.xml.i>                    <node name="radius">                      <children>                        <tagNode name="server"> diff --git a/interface-definitions/service-ipoe-server.xml.in b/interface-definitions/service-ipoe-server.xml.in index ef8569437..d778f9de0 100644 --- a/interface-definitions/service-ipoe-server.xml.in +++ b/interface-definitions/service-ipoe-server.xml.in @@ -220,7 +220,7 @@                    #include <include/accel-ppp/radius-additions-rate-limit.xml.i>                  </children>                </node> -              #include <include/radius-server-ipv4.xml.i> +              #include <include/radius-auth-server-ipv4.xml.i>                #include <include/accel-ppp/radius-additions.xml.i>              </children>            </node> diff --git a/interface-definitions/service-pppoe-server.xml.in b/interface-definitions/service-pppoe-server.xml.in index 47ad96582..68592b96b 100644 --- a/interface-definitions/service-pppoe-server.xml.in +++ b/interface-definitions/service-pppoe-server.xml.in @@ -20,7 +20,7 @@                #include <include/accel-ppp/auth-local-users.xml.i>                #include <include/accel-ppp/auth-mode.xml.i>                #include <include/accel-ppp/auth-protocols.xml.i> -              #include <include/radius-server-ipv4.xml.i> +              #include <include/radius-auth-server-ipv4.xml.i>                #include <include/accel-ppp/radius-additions.xml.i>                <node name="radius">                  <children> diff --git a/interface-definitions/snmp.xml.in b/interface-definitions/snmp.xml.in index 7ec60b2e7..10dd828a5 100644 --- a/interface-definitions/snmp.xml.in +++ b/interface-definitions/snmp.xml.in @@ -123,18 +123,31 @@            </leafNode>            <leafNode name="oid-enable">              <properties> -              <help>Enable specific OIDs</help> +              <help>Enable specific OIDs that by default are disable</help>                <completionHelp> -                <list>route-table</list> +                <list>ip-forward ip-route-table ip-net-to-media-table ip-net-to-physical-phys-address</list>                </completionHelp>                <valueHelp> -                <format>route-table</format> -                <description>Enable routing table OIDs (ipCidrRouteTable inetCidrRouteTable)</description> +                <format>ip-forward</format> +                <description>Enable ipForward: .1.3.6.1.2.1.4.24</description> +              </valueHelp> +              <valueHelp> +                <format>ip-route-table</format> +                <description>Enable ipRouteTable: .1.3.6.1.2.1.4.21</description> +              </valueHelp> +              <valueHelp> +                <format>ip-net-to-media-table</format> +                <description>Enable ipNetToMediaTable: .1.3.6.1.2.1.4.22</description> +              </valueHelp> +              <valueHelp> +                <format>ip-net-to-physical-phys-address</format> +                <description>Enable ipNetToPhysicalPhysAddress: .1.3.6.1.2.1.4.35</description>                </valueHelp>                <constraint> -                <regex>(route-table)</regex> +                <regex>(ip-forward|ip-route-table|ip-net-to-media-table|ip-net-to-physical-phys-address)</regex>                </constraint> -              <constraintErrorMessage>OID must be 'route-table'</constraintErrorMessage> +              <constraintErrorMessage>OID must be one of the liste options</constraintErrorMessage> +              <multi/>              </properties>            </leafNode>            #include <include/snmp/protocol.xml.i> diff --git a/interface-definitions/system-config-mgmt.xml.in b/interface-definitions/system-config-mgmt.xml.in new file mode 100644 index 000000000..1f852d284 --- /dev/null +++ b/interface-definitions/system-config-mgmt.xml.in @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<interfaceDefinition> +  <node name="system"> +    <children> +      <node name="config-management" owner="${vyos_conf_scripts_dir}/config_mgmt.py"> +        <properties> +          <help>Configuration management settings</help> +          <priority>400</priority> +        </properties> +        <children> +          <node name="commit-archive"> +            <properties> +              <help>Commit archive settings</help> +            </properties> +            <children> +              <leafNode name="location"> +                <properties> +                  <help>Commit archive location</help> +                  <valueHelp> +                    <format>uri</format> +                    <description>Uniform Resource Identifier</description> +                  </valueHelp> +                  <constraint> +                    <validator name="url --file-transport"/> +                  </constraint> +                  <multi/> +                </properties> +              </leafNode> +              <leafNode name="source-address"> +                <properties> +                  <help>Source address or interface for archive server connections</help> +                  <constraint> +                    <validator name="ipv4-address"/> +                    <validator name="ipv6-address"/> +                    #include <include/constraint/interface-name.xml.in> +                  </constraint> +                </properties> +              </leafNode> +            </children> +          </node> +          <leafNode name="commit-revisions"> +            <properties> +              <help>Commit revisions</help> +              <valueHelp> +                <format>u32:1-65535</format> +                <description>Number of config backups to keep</description> +              </valueHelp> +              <constraint> +                <validator name="numeric" argument="--range 1-65535"/> +              </constraint> +              <constraintErrorMessage>Number of revisions must be between 0 and 65535</constraintErrorMessage> +            </properties> +          </leafNode> +        </children> +      </node> +    </children> +  </node> +</interfaceDefinition> diff --git a/interface-definitions/vpn-ipsec.xml.in b/interface-definitions/vpn-ipsec.xml.in index 835f27ca1..9d20926ec 100644 --- a/interface-definitions/vpn-ipsec.xml.in +++ b/interface-definitions/vpn-ipsec.xml.in @@ -499,6 +499,45 @@                      </properties>                      <defaultValue>2</defaultValue>                    </leafNode> +                  <leafNode name="prf"> +                    <properties> +                      <help>Pseudo-Random Functions</help> +                      <completionHelp> +                        <list>prfmd5 prfsha1 prfaesxcbc prfaescmac prfsha256 prfsha384 prfsha512</list> +                      </completionHelp> +                      <valueHelp> +                        <format>prfmd5</format> +                        <description>MD5 PRF</description> +                      </valueHelp> +                      <valueHelp> +                        <format>prfsha1</format> +                        <description>SHA1 PRF</description> +                      </valueHelp> +                      <valueHelp> +                        <format>prfaesxcbc</format> +                        <description>AES XCBC PRF</description> +                      </valueHelp> +                      <valueHelp> +                        <format>prfaescmac</format> +                        <description>AES CMAC PRF</description> +                      </valueHelp> +                      <valueHelp> +                        <format>prfsha256</format> +                        <description>SHA2_256 PRF</description> +                      </valueHelp> +                      <valueHelp> +                        <format>prfsha384</format> +                        <description>SHA2_384 PRF</description> +                      </valueHelp> +                      <valueHelp> +                        <format>prfsha512</format> +                        <description>SHA2_512 PRF</description> +                      </valueHelp> +                      <constraint> +                        <regex>(prfmd5|prfsha1|prfaesxcbc|prfaescmac|prfsha256|prfsha384|prfsha512)</regex> +                      </constraint> +                    </properties> +                  </leafNode>                    #include <include/vpn-ipsec-encryption.xml.i>                    #include <include/vpn-ipsec-hash.xml.i>                  </children> @@ -918,7 +957,7 @@                    #include <include/name-server-ipv4-ipv6.xml.i>                  </children>                </tagNode> -              #include <include/radius-server-ipv4.xml.i> +              #include <include/radius-auth-server-ipv4.xml.i>                <node name="radius">                  <children>                    #include <include/radius-nas-identifier.xml.i> diff --git a/interface-definitions/vpn-l2tp.xml.in b/interface-definitions/vpn-l2tp.xml.in index 86aeb324e..0a92017bd 100644 --- a/interface-definitions/vpn-l2tp.xml.in +++ b/interface-definitions/vpn-l2tp.xml.in @@ -178,7 +178,7 @@                    #include <include/accel-ppp/ppp-mppe.xml.i>                    #include <include/accel-ppp/auth-mode.xml.i>                    #include <include/accel-ppp/auth-local-users.xml.i> -                  #include <include/radius-server-ipv4.xml.i> +                  #include <include/radius-auth-server-ipv4.xml.i>                    <node name="radius">                      <children>                        <tagNode name="server"> diff --git a/interface-definitions/vpn-openconnect.xml.in b/interface-definitions/vpn-openconnect.xml.in index 8b60f2e6e..a426f604d 100644 --- a/interface-definitions/vpn-openconnect.xml.in +++ b/interface-definitions/vpn-openconnect.xml.in @@ -8,6 +8,27 @@            <priority>901</priority>          </properties>          <children> +          <node name="accounting"> +            <properties> +              <help>Accounting for users OpenConnect VPN Sessions</help> +            </properties> +            <children> +              <node name="mode"> +                <properties> +                  <help>Accounting mode used by this server</help> +                </properties> +                <children> +                  <leafNode name="radius"> +                    <properties> +                      <help>Use RADIUS server for accounting</help> +                      <valueless/> +                    </properties> +                  </leafNode> +                </children> +              </node> +              #include <include/radius-acct-server-ipv4.xml.i> +            </children> +          </node>            <node name="authentication">              <properties>                <help>Authentication for remote access SSL VPN Server</help> @@ -137,7 +158,7 @@                    </tagNode>                  </children>                </node> -              #include <include/radius-server-ipv4.xml.i> +              #include <include/radius-auth-server-ipv4.xml.i>                <node name="radius">                  <children>                    #include <include/radius-timeout.xml.i> @@ -150,7 +171,7 @@                </node>              </children>            </node> -          #include <include/listen-address-ipv4.xml.i> +          #include <include/listen-address-ipv4-single.xml.i>            <leafNode name="listen-address">              <defaultValue>0.0.0.0</defaultValue>            </leafNode> diff --git a/interface-definitions/vpn-pptp.xml.in b/interface-definitions/vpn-pptp.xml.in index 5e52965fd..00ffd26f9 100644 --- a/interface-definitions/vpn-pptp.xml.in +++ b/interface-definitions/vpn-pptp.xml.in @@ -108,7 +108,7 @@                        </tagNode>                      </children>                    </node> -                  #include <include/radius-server-ipv4.xml.i> +                  #include <include/radius-auth-server-ipv4.xml.i>                    #include <include/accel-ppp/radius-additions.xml.i>                    #include <include/accel-ppp/radius-additions-rate-limit.xml.i>                  </children> diff --git a/interface-definitions/vpn-sstp.xml.in b/interface-definitions/vpn-sstp.xml.in index 195d581df..9e912063f 100644 --- a/interface-definitions/vpn-sstp.xml.in +++ b/interface-definitions/vpn-sstp.xml.in @@ -16,7 +16,7 @@                #include <include/accel-ppp/auth-local-users.xml.i>                #include <include/accel-ppp/auth-mode.xml.i>                #include <include/accel-ppp/auth-protocols.xml.i> -              #include <include/radius-server-ipv4.xml.i> +              #include <include/radius-auth-server-ipv4.xml.i>                #include <include/accel-ppp/radius-additions.xml.i>                <node name="radius">                  <children> diff --git a/mibs/IANA-ADDRESS-FAMILY-NUMBERS-MIB.txt b/mibs/IANA-ADDRESS-FAMILY-NUMBERS-MIB.txt new file mode 100644 index 000000000..7995fc4ad --- /dev/null +++ b/mibs/IANA-ADDRESS-FAMILY-NUMBERS-MIB.txt @@ -0,0 +1,166 @@ +  IANA-ADDRESS-FAMILY-NUMBERS-MIB DEFINITIONS ::= BEGIN + +  IMPORTS +      MODULE-IDENTITY, +      mib-2                               FROM SNMPv2-SMI +      TEXTUAL-CONVENTION                  FROM SNMPv2-TC; + +  ianaAddressFamilyNumbers MODULE-IDENTITY +      LAST-UPDATED "201309250000Z"  -- September 25, 2013 +      ORGANIZATION "IANA" +      CONTACT-INFO +          "Postal:    Internet Assigned Numbers Authority +                      Internet Corporation for Assigned Names +		      and Numbers +                      12025 Waterfront Drive, Suite 300 +                      Los Angeles, CA 90094-2536 +                      USA + +          Tel:    +1  310-301-5800 +          E-Mail: iana&iana.org" +      DESCRIPTION +          "The MIB module defines the AddressFamilyNumbers +          textual convention." + +      -- revision history + +      REVISION     "201309250000Z"  -- September 25, 2013 +      DESCRIPTION  "Fixed labels for 16389-16390." + +      REVISION     "201307160000Z"  -- July 16, 2013 +      DESCRIPTION  "Fixed labels for 16389-16390." + +      REVISION     "201306260000Z"  -- June 26, 2013 +      DESCRIPTION  "Added assignments 26-28." + +      REVISION     "201306180000Z"  -- June 18, 2013 +      DESCRIPTION  "Added assignments 16384-16390. Assignment  +                    25 added in 2007 revision." + +      REVISION     "200203140000Z"  -- March 14, 2002 +      DESCRIPTION  "AddressFamilyNumbers assignment 22 to  +                   fibreChannelWWPN. AddressFamilyNumbers  +                   assignment 23 to fibreChannelWWNN. +                   AddressFamilyNumers assignment 24 to gwid." + +      REVISION     "200009080000Z"  -- September 8, 2000 +      DESCRIPTION  "AddressFamilyNumbers assignment 19 to xtpOverIpv4.   +                   AddressFamilyNumbers assignment 20 to xtpOverIpv6.   +                   AddressFamilyNumbers assignment 21 to xtpNativeModeXTP." + +      REVISION     "200003010000Z"  -- March 1, 2000 +      DESCRIPTION  "AddressFamilyNumbers assignment 17 to distinguishedName.  +                   AddressFamilyNumbers assignment 18 to asNumber." + +      REVISION     "200002040000Z"  -- February 4, 2000 +      DESCRIPTION  "AddressFamilyNumbers assignment 16 to dns." + +      REVISION     "9908260000Z"  -- August 26, 1999 +      DESCRIPTION  "Initial version, published as RFC 2677." +      ::= { mib-2 72 } + +  AddressFamilyNumbers ::= TEXTUAL-CONVENTION +      STATUS       current +      DESCRIPTION +          "The definition of this textual convention with the +          addition of newly assigned values is published +          periodically by the IANA, in either the Assigned +          Numbers RFC, or some derivative of it specific to +          Internet Network Management number assignments. +          (The latest arrangements can be obtained by +          contacting the IANA.) + +          The enumerations are described as: + +          other(0),    -- none of the following +          ipV4(1),     -- IP Version 4 +          ipV6(2),     -- IP Version 6 +          nsap(3),     -- NSAP +          hdlc(4),     -- (8-bit multidrop) +          bbn1822(5), +          all802(6),   -- (includes all 802 media +                       --   plus Ethernet 'canonical format') +          e163(7), +          e164(8),     -- (SMDS, Frame Relay, ATM) +          f69(9),      -- (Telex) +          x121(10),    -- (X.25, Frame Relay) +          ipx(11),     -- IPX (Internet Protocol Exchange) +          appleTalk(12),  -- Apple Talk +          decnetIV(13),   -- DEC Net Phase IV +          banyanVines(14),  -- Banyan Vines +          e164withNsap(15), +                       -- (E.164 with NSAP format subaddress) +          dns(16),     -- (Domain Name System) +          distinguishedName(17), -- (Distinguished Name, per X.500) +          asNumber(18), -- (16-bit quantity, per the AS number space) +          xtpOverIpv4(19),  -- XTP over IP version 4 +          xtpOverIpv6(20),  -- XTP over IP version 6 +          xtpNativeModeXTP(21),  -- XTP native mode XTP +          fibreChannelWWPN(22),  -- Fibre Channel World-Wide Port Name  +          fibreChannelWWNN(23),  -- Fibre Channel World-Wide Node Name +          gwid(24),    -- Gateway Identifier  +          afi(25),  -- AFI for L2VPN information +          mplsTpSectionEndpointIdentifier(26),  -- MPLS-TP Section Endpoint Identifier +          mplsTpLspEndpointIdentifier(27),  -- MPLS-TP LSP Endpoint Identifier +          mplsTpPseudowireEndpointIdentifier(28),  -- MPLS-TP Pseudowire Endpoint Identifier +          eigrpCommonServiceFamily(16384),  -- EIGRP Common Service Family +          eigrpIpv4ServiceFamily(16385),  -- EIGRP IPv4 Service Family +          eigrpIpv6ServiceFamily(16386),  -- EIGRP IPv6 Service Family +          lispCanonicalAddressFormat(16387),  -- LISP Canonical Address Format (LCAF) +          bgpLs(16388),  -- BGP-LS +          fortyeightBitMacBitMac(16389),  -- 48-bit MAC +          sixtyfourBitMac(16390),  -- 64-bit MAC +          oui(16391),  -- OUI +          mac24(16392),  -- MAC/24 +          mac40(16393),  -- MAC/40 +          ipv664(16394),  -- IPv6/64 +          rBridgePortID(16395),  -- RBridge Port ID +          reserved(65535) + +          Requests for new values should be made to IANA via +          email (iana&iana.org)." +      SYNTAX  INTEGER { +                  other(0), +                  ipV4(1), +                  ipV6(2), +                  nsap(3), +                  hdlc(4), +                  bbn1822(5), +                  all802(6), +                  e163(7), +                  e164(8), +                  f69(9), +                  x121(10), +                  ipx(11), +                  appleTalk(12), +                  decnetIV(13), +                  banyanVines(14), +                  e164withNsap(15), +                  dns(16), +                  distinguishedName(17), -- (Distinguished Name, per X.500) +                  asNumber(18), -- (16-bit quantity, per the AS number space) +                  xtpOverIpv4(19), +                  xtpOverIpv6(20), +                  xtpNativeModeXTP(21), +                  fibreChannelWWPN(22), +                  fibreChannelWWNN(23), +                  gwid(24), +                  afi(25), +                  mplsTpSectionEndpointIdentifier(26), +                  mplsTpLspEndpointIdentifier(27), +                  mplsTpPseudowireEndpointIdentifier(28), +                  eigrpCommonServiceFamily(16384), +                  eigrpIpv4ServiceFamily(16385), +                  eigrpIpv6ServiceFamily(16386), +                  lispCanonicalAddressFormat(16387), +                  bgpLs(16388), +                  fortyeightBitMac(16389), +                  sixtyfourBitMac(16390), +                  oui(16391), +                  mac24(16392), +                  mac40(16393), +                  ipv664(16394), +                  rBridgePortID(16395), +                  reserved(65535) +              } +      END diff --git a/mibs/IANA-LANGUAGE-MIB.txt b/mibs/IANA-LANGUAGE-MIB.txt new file mode 100644 index 000000000..4b97bdd39 --- /dev/null +++ b/mibs/IANA-LANGUAGE-MIB.txt @@ -0,0 +1,126 @@ +IANA-LANGUAGE-MIB DEFINITIONS ::= BEGIN + +IMPORTS +    MODULE-IDENTITY, OBJECT-IDENTITY, mib-2 +        FROM SNMPv2-SMI; + +ianaLanguages MODULE-IDENTITY +    LAST-UPDATED "201405220000Z" -- May 22, 2014 +    ORGANIZATION "IANA" +    CONTACT-INFO +        "Internet Assigned Numbers Authority (IANA) + +         Postal: ICANN +                 12025 Waterfront Drive, Suite 300 +                 Los Angeles, CA 90094-2536 + +         Tel:    +1 310-301-5800 +         E-Mail: iana&iana.org" +    DESCRIPTION +        "The MIB module registers object identifier values for +         well-known programming and scripting languages. Every +         language registration MUST describe the format used +         when transferring scripts written in this language. + +         Any additions or changes to the contents of this MIB +         module require Designated Expert Review as defined in +         the Guidelines for Writing IANA Considerations Section +         document. The Designated Expert will be selected by +         the IESG Area Director of the OPS Area. + +         Note, this module does not have to register all possible +         languages since languages are identified by object +         identifier values. It is therefore possible to registered  +         languages in private OID trees. The references given below are not +         normative with regard to the language version. Other +         references might be better suited to describe some newer  +         versions of this language. The references are only +         provided as `a pointer into the right direction'." + + -- Revision log, in reverse chronological order + +    REVISION    "201405220000Z" -- May 22, 2014 +    DESCRIPTION "Updated contact info." + +    REVISION    "200005100000Z" -- May 10, 2000 +    DESCRIPTION "Import mib-2 instead of experimental, so that +                 this module compiles" + +    REVISION    "199909090900Z" -- September 9, 1999 +    DESCRIPTION "Initial version as published at time of +                 publication of RFC 2591." +    ::= { mib-2 73 } + +ianaLangJavaByteCode OBJECT-IDENTITY +    STATUS  current +    DESCRIPTION +        "Java byte code to be processed by a Java virtual machine. +         A script written in Java byte code is transferred by using +         the Java archive file format (JAR)." +    REFERENCE +        "The Java Virtual Machine Specification. +         ISBN 0-201-63452-X" +    ::= { ianaLanguages 1 } + +ianaLangTcl OBJECT-IDENTITY +    STATUS  current +    DESCRIPTION +        "The Tool Command Language (Tcl). A script written in the +         Tcl language is transferred in Tcl source code format." +    REFERENCE +        "Tcl and the Tk Toolkit. +         ISBN 0-201-63337-X" +    ::= { ianaLanguages 2 } + +ianaLangPerl OBJECT-IDENTITY +    STATUS  current +    DESCRIPTION +        "The Perl language. A script written in the Perl language +         is transferred in Perl source code format." +    REFERENCE +        "Programming Perl. +         ISBN 1-56592-149-6" +    ::= { ianaLanguages 3 } + +ianaLangScheme OBJECT-IDENTITY +    STATUS  current +    DESCRIPTION +        "The Scheme language. A script written in the Scheme +         language is transferred in Scheme source code format." +    REFERENCE +        "The Revised^4 Report on the Algorithmic Language Scheme. +         MIT Press" +    ::= { ianaLanguages 4 } + +ianaLangSRSL OBJECT-IDENTITY +    STATUS  current +    DESCRIPTION +        "The SNMP Script Language defined by SNMP Research. A +         script written in the SNMP Script Language is transferred +         in the SNMP Script Language source code format." +    ::= { ianaLanguages 5 } + +ianaLangPSL OBJECT-IDENTITY +    STATUS  current +    DESCRIPTION +        "The Patrol Script Language defined by BMC Software. A script +         written in the Patrol Script Language is transferred in the +         Patrol Script Language source code format." +    REFERENCE +        "PATROL Script Language Reference Manual, Version 3.0, +         November 30, 1995. BMC Software, Inc. 2101 City West Blvd., +         Houston, Texas 77042." +    ::= { ianaLanguages 6 } + +ianaLangSMSL OBJECT-IDENTITY +    STATUS  current +    DESCRIPTION +        "The Systems Management Scripting Language. A script written +         in the SMSL language is transferred in the SMSL source code +         format." +    REFERENCE +        "ISO/ITU Command Sequencer. +         ISO 10164-21 or ITU X.753" +    ::= { ianaLanguages 7 } + +END diff --git a/mibs/IANA-RTPROTO-MIB.txt b/mibs/IANA-RTPROTO-MIB.txt new file mode 100644 index 000000000..f7bc1ebc7 --- /dev/null +++ b/mibs/IANA-RTPROTO-MIB.txt @@ -0,0 +1,95 @@ +IANA-RTPROTO-MIB DEFINITIONS ::= BEGIN + +IMPORTS +    MODULE-IDENTITY, mib-2           FROM SNMPv2-SMI +    TEXTUAL-CONVENTION               FROM SNMPv2-TC; + +ianaRtProtoMIB  MODULE-IDENTITY +    LAST-UPDATED "201208300000Z" -- August 30, 2012 +    ORGANIZATION "IANA" +    CONTACT-INFO +            " Internet Assigned Numbers Authority +              Internet Corporation for Assigned Names and Numbers +              12025 Waterfront Drive, Suite 300 +              Los Angeles, CA 90094-2536 + +              Phone: +1 310 301 5800 +              EMail: iana&iana.org" +    DESCRIPTION +            "This MIB module defines the IANAipRouteProtocol and +            IANAipMRouteProtocol textual conventions for use in MIBs +            which need to identify unicast or multicast routing +            mechanisms. + +            Any additions or changes to the contents of this MIB module +            require either publication of an RFC, or Designated Expert +            Review as defined in RFC 2434, Guidelines for Writing an +            IANA Considerations Section in RFCs.  The Designated Expert  +            will be selected by the IESG Area Director(s) of the Routing +            Area." + +    REVISION     "201208300000Z"  -- August 30, 2012  +    DESCRIPTION  "Added dhcp(19)." + +    REVISION     "201107220000Z"  -- July 22, 2011  +    DESCRIPTION  "Added rpl(18) ." + +    REVISION     "200009260000Z"  -- September 26, 2000  +    DESCRIPTION  "Original version, published in coordination +                 with RFC 2932." +    ::= { mib-2 84 } + +IANAipRouteProtocol ::= TEXTUAL-CONVENTION +   STATUS      current +   DESCRIPTION +            "A mechanism for learning routes.  Inclusion of values for +            routing protocols is not intended to imply that those +            protocols need be supported." +   SYNTAX      INTEGER { +                other     (1),  -- not specified +                local     (2),  -- local interface +                netmgmt   (3),  -- static route +                icmp      (4),  -- result of ICMP Redirect + +                        -- the following are all dynamic +                        -- routing protocols + +                egp        (5),  -- Exterior Gateway Protocol +                ggp        (6),  -- Gateway-Gateway Protocol +                hello      (7),  -- FuzzBall HelloSpeak +                rip        (8),  -- Berkeley RIP or RIP-II +                isIs       (9),  -- Dual IS-IS +                esIs       (10), -- ISO 9542 +                ciscoIgrp  (11), -- Cisco IGRP +                bbnSpfIgp  (12), -- BBN SPF IGP +                ospf       (13), -- Open Shortest Path First +                bgp        (14), -- Border Gateway Protocol +                idpr       (15), -- InterDomain Policy Routing +                ciscoEigrp (16), -- Cisco EIGRP +                dvmrp      (17), -- DVMRP +                rpl        (18), -- RPL [RFC-ietf-roll-rpl-19] +                dhcp       (19)  -- DHCP [RFC2132] +               } + +IANAipMRouteProtocol ::= TEXTUAL-CONVENTION +   STATUS      current +   DESCRIPTION +            "The multicast routing protocol.  Inclusion of values for +            multicast routing protocols is not intended to imply that +            those protocols need be supported." +   SYNTAX      INTEGER { +                   other(1),          -- none of the following +                   local(2),          -- e.g., manually configured +                   netmgmt(3),        -- set via net.mgmt protocol +                   dvmrp(4), +                   mospf(5), +                   pimSparseDense(6), -- PIMv1, both DM and SM +                   cbt(7), +                   pimSparseMode(8),  -- PIM-SM +                   pimDenseMode(9),   -- PIM-DM +                   igmpOnly(10), +                   bgmp(11), +                   msdp(12) +               } + +END diff --git a/mibs/IANAifType-MIB.txt b/mibs/IANAifType-MIB.txt new file mode 100644 index 000000000..027a1532f --- /dev/null +++ b/mibs/IANAifType-MIB.txt @@ -0,0 +1,646 @@ +   IANAifType-MIB DEFINITIONS ::= BEGIN + +   IMPORTS +       MODULE-IDENTITY, mib-2      FROM SNMPv2-SMI +       TEXTUAL-CONVENTION          FROM SNMPv2-TC; + +   ianaifType MODULE-IDENTITY +       LAST-UPDATED "201407030000Z" -- July 3, 2014 +       ORGANIZATION "IANA" +       CONTACT-INFO "        Internet Assigned Numbers Authority + +                     Postal: ICANN +                             12025 Waterfront Drive, Suite 300 +                             Los Angeles, CA 90094-2536 + +                     Tel:    +1 310-301-5800 +                     E-Mail: iana&iana.org" +       DESCRIPTION  "This MIB module defines the IANAifType Textual +                     Convention, and thus the enumerated values of +                     the ifType object defined in MIB-II's ifTable." + +       REVISION     "201407030000Z"  -- July 3, 2014 +	   DESCRIPTION  "Registration of new IANAifTypes 277-278." + +       REVISION     "201405220000Z" -- May 22, 2014 +       DESCRIPTION  "Updated contact info." + +       REVISION     "201205170000Z"  -- May 17, 2012 +       DESCRIPTION  "Registration of new IANAifType 272." + +       REVISION     "201201110000Z"  -- January 11, 2012 +       DESCRIPTION  "Registration of new IANAifTypes 266-271." + +       REVISION     "201112180000Z"  -- December 18, 2011 +       DESCRIPTION  "Registration of new IANAifTypes 263-265." + +       REVISION     "201110260000Z"  -- October 26, 2011 +       DESCRIPTION  "Registration of new IANAifType 262." + +       REVISION     "201109070000Z"  -- September 7, 2011 +       DESCRIPTION  "Registration of new IANAifTypes 260 and 261." + +       REVISION     "201107220000Z"  -- July 22, 2011 +       DESCRIPTION  "Registration of new IANAifType 259." + +       REVISION     "201106030000Z"  -- June 03, 2011 +       DESCRIPTION  "Registration of new IANAifType 258." + +       REVISION     "201009210000Z"  -- September 21, 2010 +       DESCRIPTION  "Registration of new IANAifTypes 256 and 257." + +       REVISION     "201007210000Z"  -- July 21, 2010 +       DESCRIPTION  "Registration of new IANAifType 255." + +       REVISION     "201002110000Z"  -- February 11, 2010 +       DESCRIPTION  "Registration of new IANAifType 254." + +       REVISION     "201002080000Z"  -- February 08, 2010 +       DESCRIPTION  "Registration of new IANAifTypes 252 and 253." + +       REVISION     "200905060000Z"  -- May 06, 2009 +       DESCRIPTION  "Registration of new IANAifType 251." + +       REVISION     "200902060000Z"  -- February 06, 2009 +       DESCRIPTION  "Registration of new IANAtunnelType 15." + +       REVISION     "200810090000Z"  -- October 09, 2008 +       DESCRIPTION  "Registration of new IANAifType 250." + +       REVISION     "200808120000Z"  -- August 12, 2008 +       DESCRIPTION  "Registration of new IANAifType 249." + +       REVISION     "200807220000Z"  -- July 22, 2008 +       DESCRIPTION  "Registration of new IANAifTypes 247 and 248." + +       REVISION     "200806240000Z"  -- June 24, 2008 +       DESCRIPTION  "Registration of new IANAifType 246." + +       REVISION     "200805290000Z"  -- May 29, 2008 +       DESCRIPTION  "Registration of new IANAifType 245." + +       REVISION     "200709130000Z"  -- September 13, 2007 +       DESCRIPTION  "Registration of new IANAifTypes 243 and 244." + +       REVISION     "200705290000Z"  -- May 29, 2007 +       DESCRIPTION  "Changed the description for IANAifType 228." + +       REVISION     "200703080000Z"  -- March 08, 2007 +       DESCRIPTION  "Registration of new IANAifType 242." + +       REVISION     "200701230000Z"  -- January 23, 2007 +       DESCRIPTION  "Registration of new IANAifTypes 239, 240, and 241."  + +       REVISION     "200610170000Z"  -- October 17, 2006 +       DESCRIPTION  "Deprecated/Obsoleted IANAifType 230.  Registration of  +                     IANAifType 238."  + +       REVISION     "200609250000Z"  -- September 25, 2006 +       DESCRIPTION  "Changed the description for IANA ifType  +                     184 and added new IANA ifType 237."   + +       REVISION     "200608170000Z"  -- August 17, 2006 +       DESCRIPTION  "Changed the descriptions for IANAifTypes +                     20 and 21."    + +       REVISION     "200608110000Z"  -- August 11, 2006 +       DESCRIPTION  "Changed the descriptions for IANAifTypes +                     7, 11, 62, 69, and 117."    + +       REVISION     "200607250000Z"  -- July 25, 2006 +       DESCRIPTION  "Registration of new IANA ifType 236." + +       REVISION     "200606140000Z"  -- June 14, 2006 +       DESCRIPTION  "Registration of new IANA ifType 235." + +       REVISION     "200603310000Z"  -- March 31, 2006 +       DESCRIPTION  "Registration of new IANA ifType 234." + +       REVISION     "200603300000Z"  -- March 30, 2006 +       DESCRIPTION  "Registration of new IANA ifType 233." + +       REVISION     "200512220000Z"  -- December 22, 2005 +       DESCRIPTION  "Registration of new IANA ifTypes 231 and 232." + +       REVISION     "200510100000Z"  -- October 10, 2005 +       DESCRIPTION  "Registration of new IANA ifType 230." + +       REVISION     "200509090000Z"  -- September 09, 2005 +       DESCRIPTION  "Registration of new IANA ifType 229." + +       REVISION     "200505270000Z"  -- May 27, 2005 +       DESCRIPTION  "Registration of new IANA ifType 228." + +       REVISION     "200503030000Z"  -- March 3, 2005 +       DESCRIPTION  "Added the IANAtunnelType TC and deprecated +	                 IANAifType sixToFour (215) per RFC4087." + +       REVISION     "200411220000Z"  -- November 22, 2004 +       DESCRIPTION  "Registration of new IANA ifType 227 per RFC4631." + +       REVISION     "200406170000Z"  -- June 17, 2004 +       DESCRIPTION  "Registration of new IANA ifType 226." + +       REVISION     "200405120000Z"  -- May 12, 2004 +       DESCRIPTION  "Added description for IANAifType 6, and  +	                 changed the descriptions for IANAifTypes +                     180, 181, and 182." + +       REVISION     "200405070000Z"  -- May 7, 2004 +       DESCRIPTION  "Registration of new IANAifType 225." + +       REVISION     "200308250000Z"  -- Aug 25, 2003 +       DESCRIPTION  "Deprecated IANAifTypes 7 and 11. Obsoleted +                     IANAifTypes 62, 69, and 117.  ethernetCsmacd (6) +                     should be used instead of these values" + +       REVISION     "200308180000Z"  -- Aug 18, 2003 +       DESCRIPTION  "Registration of new IANAifType +                     224." + +       REVISION     "200308070000Z"  -- Aug 7, 2003 +       DESCRIPTION  "Registration of new IANAifTypes +                     222 and 223." + +       REVISION     "200303180000Z"  -- Mar 18, 2003 +       DESCRIPTION  "Registration of new IANAifType +                     221." + +       REVISION     "200301130000Z"  -- Jan 13, 2003 +       DESCRIPTION  "Registration of new IANAifType +                     220." + +       REVISION     "200210170000Z"  -- Oct 17, 2002 +       DESCRIPTION  "Registration of new IANAifType +                     219." + +       REVISION     "200207160000Z"  -- Jul 16, 2002 +       DESCRIPTION  "Registration of new IANAifTypes +                     217 and 218." + +       REVISION     "200207100000Z"  -- Jul 10, 2002 +       DESCRIPTION  "Registration of new IANAifTypes +                     215 and 216." + +       REVISION     "200206190000Z"  -- Jun 19, 2002 +       DESCRIPTION  "Registration of new IANAifType +                     214." + +       REVISION     "200201040000Z"  -- Jan 4, 2002 +       DESCRIPTION  "Registration of new IANAifTypes +                     211, 212 and 213." + +       REVISION     "200112200000Z"  -- Dec 20, 2001 +       DESCRIPTION  "Registration of new IANAifTypes +                     209 and 210." + +       REVISION     "200111150000Z"  -- Nov 15, 2001 +       DESCRIPTION  "Registration of new IANAifTypes +                     207 and 208." + +       REVISION     "200111060000Z"  -- Nov 6, 2001 +       DESCRIPTION  "Registration of new IANAifType +                     206." + +       REVISION     "200111020000Z"  -- Nov 2, 2001 +       DESCRIPTION  "Registration of new IANAifType +                     205." + +       REVISION     "200110160000Z"  -- Oct 16, 2001 +       DESCRIPTION  "Registration of new IANAifTypes +                     199, 200, 201, 202, 203, and 204." + +       REVISION     "200109190000Z"  -- Sept 19, 2001 +       DESCRIPTION  "Registration of new IANAifType +                     198." + +       REVISION     "200105110000Z"  -- May 11, 2001 +       DESCRIPTION  "Registration of new IANAifType +                     197." + +       REVISION     "200101120000Z"  -- Jan 12, 2001 +       DESCRIPTION  "Registration of new IANAifTypes +                     195 and 196." + +       REVISION     "200012190000Z"  -- Dec 19, 2000 +       DESCRIPTION  "Registration of new IANAifTypes +                     193 and 194." + +       REVISION     "200012070000Z"  -- Dec 07, 2000 +       DESCRIPTION  "Registration of new IANAifTypes +                     191 and 192." + +       REVISION     "200012040000Z"  -- Dec 04, 2000 +       DESCRIPTION  "Registration of new IANAifType +                     190." + +       REVISION     "200010170000Z"  -- Oct 17, 2000 +       DESCRIPTION  "Registration of new IANAifTypes +                     188 and 189."   + +       REVISION     "200010020000Z"  -- Oct 02, 2000 +       DESCRIPTION  "Registration of new IANAifType 187."  + +       REVISION     "200009010000Z"  -- Sept 01, 2000 +       DESCRIPTION  "Registration of new IANAifTypes +                     184, 185, and 186."			 + +       REVISION     "200008240000Z"  -- Aug 24, 2000 +       DESCRIPTION  "Registration of new IANAifType 183."  + +       REVISION     "200008230000Z"  -- Aug 23, 2000 +       DESCRIPTION  "Registration of new IANAifTypes +                     174-182." + +       REVISION     "200008220000Z"  -- Aug 22, 2000 +       DESCRIPTION  "Registration of new IANAifTypes 170, +                     171, 172 and 173." + +       REVISION     "200004250000Z"  -- Apr 25, 2000 +       DESCRIPTION  "Registration of new IANAifTypes 168 and 169."        + +       REVISION     "200003060000Z"  -- Mar 6, 2000 +       DESCRIPTION  "Fixed a missing semi-colon in the IMPORT. +                     Also cleaned up the REVISION log a bit. +                     It is not complete, but from now on it will +                     be maintained and kept up to date with each +                     change to this MIB module." + +       REVISION     "199910081430Z"  -- Oct 08, 1999 +       DESCRIPTION  "Include new name assignments up to cnr(85). +                     This is the first version available via the WWW +                     at: ftp://ftp.isi.edu/mib/ianaiftype.mib" + +       REVISION     "199401310000Z"  -- Jan 31, 1994 +       DESCRIPTION  "Initial version of this MIB as published in +                     RFC 1573." +       ::= { mib-2 30 } + +   IANAifType ::= TEXTUAL-CONVENTION +       STATUS       current +       DESCRIPTION +               "This data type is used as the syntax of the ifType +               object in the (updated) definition of MIB-II's +               ifTable. + +               The definition of this textual convention with the +               addition of newly assigned values is published +               periodically by the IANA, in either the Assigned +               Numbers RFC, or some derivative of it specific to +               Internet Network Management number assignments.  (The +               latest arrangements can be obtained by contacting the +               IANA.) + +               Requests for new values should be made to IANA via +               email (iana&iana.org). + +               The relationship between the assignment of ifType +               values and of OIDs to particular media-specific MIBs +               is solely the purview of IANA and is subject to change +               without notice.  Quite often, a media-specific MIB's +               OID-subtree assignment within MIB-II's 'transmission' +               subtree will be the same as its ifType value. +               However, in some circumstances this will not be the +               case, and implementors must not pre-assume any +               specific relationship between ifType values and +               transmission subtree OIDs." +       SYNTAX  INTEGER { +                   other(1),          -- none of the following +                   regular1822(2), +                   hdh1822(3), +                   ddnX25(4), +                   rfc877x25(5), +                   ethernetCsmacd(6), -- for all ethernet-like interfaces, +                                      -- regardless of speed, as per RFC3635 +                   iso88023Csmacd(7), -- Deprecated via RFC3635 +                                      -- ethernetCsmacd (6) should be used instead +                   iso88024TokenBus(8), +                   iso88025TokenRing(9), +                   iso88026Man(10), +                   starLan(11), -- Deprecated via RFC3635 +                                -- ethernetCsmacd (6) should be used instead +                   proteon10Mbit(12), +                   proteon80Mbit(13), +                   hyperchannel(14), +                   fddi(15), +                   lapb(16), +                   sdlc(17), +                   ds1(18),            -- DS1-MIB +                   e1(19),             -- Obsolete see DS1-MIB +                   basicISDN(20),              -- no longer used +                                               -- see also RFC2127 +                   primaryISDN(21),            -- no longer used +                                               -- see also RFC2127 +                   propPointToPointSerial(22), -- proprietary serial +                   ppp(23), +                   softwareLoopback(24), +                   eon(25),            -- CLNP over IP  +                   ethernet3Mbit(26), +                   nsip(27),           -- XNS over IP +                   slip(28),           -- generic SLIP +                   ultra(29),          -- ULTRA technologies +                   ds3(30),            -- DS3-MIB +                   sip(31),            -- SMDS, coffee +                   frameRelay(32),     -- DTE only.  +                   rs232(33), +                   para(34),           -- parallel-port +                   arcnet(35),         -- arcnet +                   arcnetPlus(36),     -- arcnet plus +                   atm(37),            -- ATM cells +                   miox25(38), +                   sonet(39),          -- SONET or SDH  +                   x25ple(40), +                   iso88022llc(41), +                   localTalk(42), +                   smdsDxi(43), +                   frameRelayService(44),  -- FRNETSERV-MIB +                   v35(45), +                   hssi(46), +                   hippi(47), +                   modem(48),          -- Generic modem +                   aal5(49),           -- AAL5 over ATM +                   sonetPath(50), +                   sonetVT(51), +                   smdsIcip(52),       -- SMDS InterCarrier Interface +                   propVirtual(53),    -- proprietary virtual/internal +                   propMultiplexor(54),-- proprietary multiplexing +                   ieee80212(55),      -- 100BaseVG +                   fibreChannel(56),   -- Fibre Channel +                   hippiInterface(57), -- HIPPI interfaces      +                   frameRelayInterconnect(58), -- Obsolete, use either +                                       -- frameRelay(32) or  +                                       -- frameRelayService(44). +                   aflane8023(59),     -- ATM Emulated LAN for 802.3 +                   aflane8025(60),     -- ATM Emulated LAN for 802.5 +                   cctEmul(61),        -- ATM Emulated circuit           +                   fastEther(62),      -- Obsoleted via RFC3635 +                                       -- ethernetCsmacd (6) should be used instead +                   isdn(63),           -- ISDN and X.25            +                   v11(64),            -- CCITT V.11/X.21              +                   v36(65),            -- CCITT V.36                   +                   g703at64k(66),      -- CCITT G703 at 64Kbps +                   g703at2mb(67),      -- Obsolete see DS1-MIB +                   qllc(68),           -- SNA QLLC                     +                   fastEtherFX(69),    -- Obsoleted via RFC3635 +                                       -- ethernetCsmacd (6) should be used instead +                   channel(70),        -- channel                      +                   ieee80211(71),      -- radio spread spectrum        +                   ibm370parChan(72),  -- IBM System 360/370 OEMI Channel +                   escon(73),          -- IBM Enterprise Systems Connection +                   dlsw(74),           -- Data Link Switching +                   isdns(75),          -- ISDN S/T interface +                   isdnu(76),          -- ISDN U interface +                   lapd(77),           -- Link Access Protocol D +                   ipSwitch(78),       -- IP Switching Objects +                   rsrb(79),           -- Remote Source Route Bridging +                   atmLogical(80),     -- ATM Logical Port +                   ds0(81),            -- Digital Signal Level 0 +                   ds0Bundle(82),      -- group of ds0s on the same ds1 +                   bsc(83),            -- Bisynchronous Protocol +                   async(84),          -- Asynchronous Protocol +                   cnr(85),            -- Combat Net Radio +                   iso88025Dtr(86),    -- ISO 802.5r DTR +                   eplrs(87),          -- Ext Pos Loc Report Sys +                   arap(88),           -- Appletalk Remote Access Protocol +                   propCnls(89),       -- Proprietary Connectionless Protocol +                   hostPad(90),        -- CCITT-ITU X.29 PAD Protocol +                   termPad(91),        -- CCITT-ITU X.3 PAD Facility +                   frameRelayMPI(92),  -- Multiproto Interconnect over FR +                   x213(93),           -- CCITT-ITU X213 +                   adsl(94),           -- Asymmetric Digital Subscriber Loop +                   radsl(95),          -- Rate-Adapt. Digital Subscriber Loop +                   sdsl(96),           -- Symmetric Digital Subscriber Loop +                   vdsl(97),           -- Very H-Speed Digital Subscrib. Loop +                   iso88025CRFPInt(98), -- ISO 802.5 CRFP +                   myrinet(99),        -- Myricom Myrinet +                   voiceEM(100),       -- voice recEive and transMit +                   voiceFXO(101),      -- voice Foreign Exchange Office +                   voiceFXS(102),      -- voice Foreign Exchange Station +                   voiceEncap(103),    -- voice encapsulation +                   voiceOverIp(104),   -- voice over IP encapsulation +                   atmDxi(105),        -- ATM DXI +                   atmFuni(106),       -- ATM FUNI +                   atmIma (107),       -- ATM IMA		    +                   pppMultilinkBundle(108), -- PPP Multilink Bundle +                   ipOverCdlc (109),   -- IBM ipOverCdlc +                   ipOverClaw (110),   -- IBM Common Link Access to Workstn +                   stackToStack (111), -- IBM stackToStack +                   virtualIpAddress (112), -- IBM VIPA +                   mpc (113),          -- IBM multi-protocol channel support +                   ipOverAtm (114),    -- IBM ipOverAtm +                   iso88025Fiber (115), -- ISO 802.5j Fiber Token Ring +                   tdlc (116),	       -- IBM twinaxial data link control +                   gigabitEthernet (117), -- Obsoleted via RFC3635 +                                          -- ethernetCsmacd (6) should be used instead +                   hdlc (118),         -- HDLC +                   lapf (119),	       -- LAP F +                   v37 (120),	       -- V.37 +                   x25mlp (121),       -- Multi-Link Protocol +                   x25huntGroup (122), -- X25 Hunt Group +                   transpHdlc (123),   -- Transp HDLC +                   interleave (124),   -- Interleave channel +                   fast (125),         -- Fast channel +                   ip (126),	       -- IP (for APPN HPR in IP networks) +                   docsCableMaclayer (127),  -- CATV Mac Layer +                   docsCableDownstream (128), -- CATV Downstream interface +                   docsCableUpstream (129),  -- CATV Upstream interface +                   a12MppSwitch (130), -- Avalon Parallel Processor +                   tunnel (131),       -- Encapsulation interface +                   coffee (132),       -- coffee pot +                   ces (133),          -- Circuit Emulation Service +                   atmSubInterface (134), -- ATM Sub Interface +                   l2vlan (135),       -- Layer 2 Virtual LAN using 802.1Q +                   l3ipvlan (136),     -- Layer 3 Virtual LAN using IP +                   l3ipxvlan (137),    -- Layer 3 Virtual LAN using IPX +                   digitalPowerline (138), -- IP over Power Lines	 +                   mediaMailOverIp (139), -- Multimedia Mail over IP +                   dtm (140),        -- Dynamic syncronous Transfer Mode +                   dcn (141),    -- Data Communications Network +                   ipForward (142),    -- IP Forwarding Interface +                   msdsl (143),       -- Multi-rate Symmetric DSL +                   ieee1394 (144), -- IEEE1394 High Performance Serial Bus +                   if-gsn (145),       --   HIPPI-6400  +                   dvbRccMacLayer (146), -- DVB-RCC MAC Layer +                   dvbRccDownstream (147),  -- DVB-RCC Downstream Channel +                   dvbRccUpstream (148),  -- DVB-RCC Upstream Channel +                   atmVirtual (149),   -- ATM Virtual Interface +                   mplsTunnel (150),   -- MPLS Tunnel Virtual Interface +                   srp (151),	-- Spatial Reuse Protocol	 +                   voiceOverAtm (152),  -- Voice Over ATM +                   voiceOverFrameRelay (153),   -- Voice Over Frame Relay  +                   idsl (154),		-- Digital Subscriber Loop over ISDN +                   compositeLink (155),  -- Avici Composite Link Interface +                   ss7SigLink (156),     -- SS7 Signaling Link  +                   propWirelessP2P (157),  --  Prop. P2P wireless interface +                   frForward (158),    -- Frame Forward Interface +                   rfc1483 (159),	-- Multiprotocol over ATM AAL5 +                   usb (160),		-- USB Interface +                   ieee8023adLag (161),  -- IEEE 802.3ad Link Aggregate +                   bgppolicyaccounting (162), -- BGP Policy Accounting +                   frf16MfrBundle (163), -- FRF .16 Multilink Frame Relay  +                   h323Gatekeeper (164), -- H323 Gatekeeper +                   h323Proxy (165), -- H323 Voice and Video Proxy +                   mpls (166), -- MPLS                    +                   mfSigLink (167), -- Multi-frequency signaling link +                   hdsl2 (168), -- High Bit-Rate DSL - 2nd generation +                   shdsl (169), -- Multirate HDSL2 +                   ds1FDL (170), -- Facility Data Link 4Kbps on a DS1 +                   pos (171), -- Packet over SONET/SDH Interface +                   dvbAsiIn (172), -- DVB-ASI Input +                   dvbAsiOut (173), -- DVB-ASI Output  +                   plc (174), -- Power Line Communtications +                   nfas (175), -- Non Facility Associated Signaling +                   tr008 (176), -- TR008 +                   gr303RDT (177), -- Remote Digital Terminal +                   gr303IDT (178), -- Integrated Digital Terminal +                   isup (179), -- ISUP +                   propDocsWirelessMaclayer (180), -- Cisco proprietary Maclayer +                   propDocsWirelessDownstream (181), -- Cisco proprietary Downstream +                   propDocsWirelessUpstream (182), -- Cisco proprietary Upstream +                   hiperlan2 (183), -- HIPERLAN Type 2 Radio Interface +                   propBWAp2Mp (184), -- PropBroadbandWirelessAccesspt2multipt +                             -- use of this iftype for IEEE 802.16 WMAN +                             -- interfaces as per IEEE Std 802.16f is +                             -- deprecated and ifType 237 should be used instead. +                   sonetOverheadChannel (185), -- SONET Overhead Channel +                   digitalWrapperOverheadChannel (186), -- Digital Wrapper +                   aal2 (187), -- ATM adaptation layer 2 +                   radioMAC (188), -- MAC layer over radio links +                   atmRadio (189), -- ATM over radio links    +                   imt (190), -- Inter Machine Trunks +                   mvl (191), -- Multiple Virtual Lines DSL +                   reachDSL (192), -- Long Reach DSL +                   frDlciEndPt (193), -- Frame Relay DLCI End Point +                   atmVciEndPt (194), -- ATM VCI End Point +                   opticalChannel (195), -- Optical Channel +                   opticalTransport (196), -- Optical Transport +                   propAtm (197), --  Proprietary ATM        +                   voiceOverCable (198), -- Voice Over Cable Interface +                   infiniband (199), -- Infiniband +                   teLink (200), -- TE Link +                   q2931 (201), -- Q.2931 +                   virtualTg (202), -- Virtual Trunk Group +                   sipTg (203), -- SIP Trunk Group +                   sipSig (204), -- SIP Signaling    +                   docsCableUpstreamChannel (205), -- CATV Upstream Channel +                   econet (206), -- Acorn Econet +                   pon155 (207), -- FSAN 155Mb Symetrical PON interface +                   pon622 (208), -- FSAN622Mb Symetrical PON interface +                   bridge (209), -- Transparent bridge interface +                   linegroup (210), -- Interface common to multiple lines    +                   voiceEMFGD (211), -- voice E&M Feature Group D +                   voiceFGDEANA (212), -- voice FGD Exchange Access North American +                   voiceDID (213), -- voice Direct Inward Dialing +                   mpegTransport (214), -- MPEG transport interface +                   sixToFour (215), -- 6to4 interface (DEPRECATED) +                   gtp (216), -- GTP (GPRS Tunneling Protocol) +                   pdnEtherLoop1 (217), -- Paradyne EtherLoop 1 +                   pdnEtherLoop2 (218), -- Paradyne EtherLoop 2 +                   opticalChannelGroup (219), -- Optical Channel Group +                   homepna (220), -- HomePNA ITU-T G.989 +                   gfp (221), -- Generic Framing Procedure (GFP) +                   ciscoISLvlan (222), -- Layer 2 Virtual LAN using Cisco ISL +                   actelisMetaLOOP (223), -- Acteleis proprietary MetaLOOP High Speed Link  +                   fcipLink (224), -- FCIP Link  +                   rpr (225), -- Resilient Packet Ring Interface Type +                   qam (226), -- RF Qam Interface +                   lmp (227), -- Link Management Protocol +                   cblVectaStar (228), -- Cambridge Broadband Networks Limited VectaStar +                   docsCableMCmtsDownstream (229), -- CATV Modular CMTS Downstream Interface +                   adsl2 (230), -- Asymmetric Digital Subscriber Loop Version 2  +                                -- (DEPRECATED/OBSOLETED - please use adsl2plus 238 instead) +                   macSecControlledIF (231), -- MACSecControlled  +                   macSecUncontrolledIF (232), -- MACSecUncontrolled +                   aviciOpticalEther (233), -- Avici Optical Ethernet Aggregate +                   atmbond (234), -- atmbond +                   voiceFGDOS (235), -- voice FGD Operator Services +                   mocaVersion1 (236), -- MultiMedia over Coax Alliance (MoCA) Interface +                             -- as documented in information provided privately to IANA +                   ieee80216WMAN (237), -- IEEE 802.16 WMAN interface +                   adsl2plus (238), -- Asymmetric Digital Subscriber Loop Version 2,  +                                   -- Version 2 Plus and all variants +                   dvbRcsMacLayer (239), -- DVB-RCS MAC Layer +                   dvbTdm (240), -- DVB Satellite TDM +                   dvbRcsTdma (241), -- DVB-RCS TDMA +                   x86Laps (242), -- LAPS based on ITU-T X.86/Y.1323 +                   wwanPP (243), -- 3GPP WWAN +                   wwanPP2 (244), -- 3GPP2 WWAN +                   voiceEBS (245), -- voice P-phone EBS physical interface +                   ifPwType (246), -- Pseudowire interface type +                   ilan (247), -- Internal LAN on a bridge per IEEE 802.1ap +                   pip (248), -- Provider Instance Port on a bridge per IEEE 802.1ah PBB +                   aluELP (249), -- Alcatel-Lucent Ethernet Link Protection +                   gpon (250), -- Gigabit-capable passive optical networks (G-PON) as per ITU-T G.948 +                   vdsl2 (251), -- Very high speed digital subscriber line Version 2 (as per ITU-T Recommendation G.993.2) +                   capwapDot11Profile (252), -- WLAN Profile Interface +                   capwapDot11Bss (253), -- WLAN BSS Interface +                   capwapWtpVirtualRadio (254), -- WTP Virtual Radio Interface +                   bits (255), -- bitsport +                   docsCableUpstreamRfPort (256), -- DOCSIS CATV Upstream RF Port +                   cableDownstreamRfPort (257), -- CATV downstream RF port +                   vmwareVirtualNic (258), -- VMware Virtual Network Interface +                   ieee802154 (259), -- IEEE 802.15.4 WPAN interface +                   otnOdu (260), -- OTN Optical Data Unit +                   otnOtu (261), -- OTN Optical channel Transport Unit +                   ifVfiType (262), -- VPLS Forwarding Instance Interface Type +                   g9981 (263), -- G.998.1 bonded interface +                   g9982 (264), -- G.998.2 bonded interface +                   g9983 (265), -- G.998.3 bonded interface +                   aluEpon (266), -- Ethernet Passive Optical Networks (E-PON) +                   aluEponOnu (267), -- EPON Optical Network Unit +                   aluEponPhysicalUni (268), -- EPON physical User to Network interface +                   aluEponLogicalLink (269), -- The emulation of a point-to-point link over the EPON layer +                   aluGponOnu (270), -- GPON Optical Network Unit +                   aluGponPhysicalUni (271), -- GPON physical User to Network interface +                   vmwareNicTeam (272), -- VMware NIC Team +                   docsOfdmDownstream (277), -- CATV Downstream OFDM interface +                   docsOfdmaUpstream (278) -- CATV Upstream OFDMA interface +                   } + +IANAtunnelType ::= TEXTUAL-CONVENTION +    STATUS     current +    DESCRIPTION +            "The encapsulation method used by a tunnel. The value +            direct indicates that a packet is encapsulated +            directly within a normal IP header, with no +            intermediate header, and unicast to the remote tunnel +            endpoint (e.g., an RFC 2003 IP-in-IP tunnel, or an RFC +            1933 IPv6-in-IPv4 tunnel). The value minimal indicates +            that a Minimal Forwarding Header (RFC 2004) is +            inserted between the outer header and the payload +            packet. The value UDP indicates that the payload +            packet is encapsulated within a normal UDP packet +            (e.g., RFC 1234). + +            The values sixToFour, sixOverFour, and isatap +            indicates that an IPv6 packet is encapsulated directly +            within an IPv4 header, with no intermediate header, +            and unicast to the destination determined by the 6to4, +            6over4, or ISATAP protocol. + +            The remaining protocol-specific values indicate that a +            header of the protocol of that name is inserted +            between the outer header and the payload header. + +            The assignment policy for IANAtunnelType values is +            identical to the policy for assigning IANAifType +            values." +    SYNTAX     INTEGER { +                   other(1),        -- none of the following +                   direct(2),       -- no intermediate header +                   gre(3),          -- GRE encapsulation +                   minimal(4),      -- Minimal encapsulation +                   l2tp(5),         -- L2TP encapsulation +                   pptp(6),         -- PPTP encapsulation +                   l2f(7),          -- L2F encapsulation +                   udp(8),          -- UDP encapsulation +                   atmp(9),         -- ATMP encapsulation +                   msdp(10),        -- MSDP encapsulation +                   sixToFour(11),   -- 6to4 encapsulation +                   sixOverFour(12), -- 6over4 encapsulation +                   isatap(13),      -- ISATAP encapsulation +                   teredo(14),      -- Teredo encapsulation +                   ipHttps(15)      -- IPHTTPS +               } + +   END diff --git a/op-mode-definitions/generate-interfaces-debug-archive.xml.in b/op-mode-definitions/generate-interfaces-debug-archive.xml.in new file mode 100644 index 000000000..5e4f4daad --- /dev/null +++ b/op-mode-definitions/generate-interfaces-debug-archive.xml.in @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<interfaceDefinition> +  <node name="generate"> +    <children> +      <node name="interfaces"> +        <properties> +          <help>Interface specific commands</help> +        </properties> +        <children> +          <node name="debug-archive"> +            <properties> +              <help>Generate interfaces debug-archive</help> +            </properties> +            <command>${vyos_op_scripts_dir}/generate_interfaces_debug_archive.py</command> +          </node> +        </children> +      </node> +    </children> +  </node> +</interfaceDefinition> diff --git a/op-mode-definitions/generate-openvpn-config-client.xml.in b/op-mode-definitions/generate-openvpn-config-client.xml.in index 4f9f31bfe..baec0842b 100644 --- a/op-mode-definitions/generate-openvpn-config-client.xml.in +++ b/op-mode-definitions/generate-openvpn-config-client.xml.in @@ -16,7 +16,7 @@                  <properties>                    <help>Local interface used for connection</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py --type openvpn</script> +                    <path>interfaces openvpn</path>                    </completionHelp>                  </properties>                  <children> diff --git a/op-mode-definitions/generate-wireguard.xml.in b/op-mode-definitions/generate-wireguard.xml.in index 0ef983cd2..6c01619be 100644 --- a/op-mode-definitions/generate-wireguard.xml.in +++ b/op-mode-definitions/generate-wireguard.xml.in @@ -19,7 +19,7 @@                  <properties>                    <help>Local interface used for connection</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py --type wireguard</script> +                    <path>interfaces wireguard</path>                    </completionHelp>                  </properties>                  <children> diff --git a/op-mode-definitions/ipv6-route.xml.in b/op-mode-definitions/ipv6-route.xml.in index d75caf308..46e416a8a 100644 --- a/op-mode-definitions/ipv6-route.xml.in +++ b/op-mode-definitions/ipv6-route.xml.in @@ -26,7 +26,7 @@                  <properties>                    <help>Show IPv6 neighbor table for specified interface</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py -b</script> +                    <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script>                    </completionHelp>                  </properties>                  <command>${vyos_op_scripts_dir}/neighbor.py show --family inet6 --interface "$5"</command> diff --git a/op-mode-definitions/monitor-log.xml.in b/op-mode-definitions/monitor-log.xml.in index d616bfc08..ec428a676 100644 --- a/op-mode-definitions/monitor-log.xml.in +++ b/op-mode-definitions/monitor-log.xml.in @@ -93,6 +93,12 @@              </properties>              <command>journalctl --no-hostname --boot --follow --unit uacctd.service</command>            </leafNode> +          <leafNode name="ipoe-server"> +            <properties> +              <help>Monitor last lines of IPoE server log</help> +            </properties> +            <command>journalctl --no-hostname --boot --follow --unit accel-ppp@ipoe.service</command> +          </leafNode>            <leafNode name="kernel">              <properties>                <help>Monitor last lines of Linux Kernel log</help> @@ -113,7 +119,7 @@            </leafNode>            <node name="pppoe">              <properties> -              <help>Monitor last lines of PPPoE log</help> +              <help>Monitor last lines of PPPoE interface log</help>              </properties>              <command>journalctl --no-hostname --boot --follow --unit "ppp@pppoe*.service"</command>              <children> @@ -121,13 +127,19 @@                  <properties>                    <help>Monitor last lines of PPPoE log for specific interface</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py -t pppoe</script> +                    <path>interfaces pppoe</path>                    </completionHelp>                  </properties>                  <command>journalctl --no-hostname --boot --follow --unit "ppp@$5.service"</command>                </tagNode>              </children>            </node> +          <leafNode name="pppoe-server"> +            <properties> +              <help>Monitor last lines of PPPoE server log</help> +            </properties> +            <command>journalctl --no-hostname --boot --follow --unit accel-ppp@pppoe.service</command> +          </leafNode>            <node name="protocol">              <properties>                <help>Monitor log for Routing Protocol</help> @@ -211,7 +223,7 @@                  <properties>                    <help>Monitor last lines of specific MACsec interface</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py -t macsec</script> +                    <path>interfaces macsec</path>                    </completionHelp>                  </properties>                  <command>SRC=$(cli-shell-api returnValue interfaces macsec "$5" source-interface); journalctl --no-hostname --boot --follow --unit "wpa_supplicant-macsec@$SRC.service"</command> @@ -246,7 +258,7 @@                  <properties>                    <help>Monitor last lines of SSTP client log for specific interface</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py -t sstpc</script> +                    <path>interfaces sstpc</path>                    </completionHelp>                  </properties>                  <command>journalctl --no-hostname --boot --follow --unit "ppp@$5.service"</command> @@ -255,14 +267,14 @@            </node>            <node name="vpn">              <properties> -              <help>Show log for Virtual Private Network (VPN)</help> +              <help>Monitor Virtual Private Network (VPN) services</help>              </properties>              <children>                <leafNode name="all">                  <properties>                    <help>Monitor last lines of ALL VPNs</help>                  </properties> -                <command>journalctl --no-hostname --boot --follow --unit strongswan-starter.service --unit accel-ppp@*.service</command> +                <command>journalctl --no-hostname --boot --follow --unit strongswan-starter.service --unit accel-ppp@*.service --unit ocserv.service</command>                </leafNode>                <leafNode name="ipsec">                  <properties> @@ -276,6 +288,12 @@                  </properties>                  <command>journalctl --no-hostname --boot --follow --unit accel-ppp@l2tp.service</command>                </leafNode> +              <leafNode name="openconnect"> +                <properties> +                  <help>Monitor last lines of OpenConnect</help> +                </properties> +                <command>journalctl --no-hostname --boot --follow --unit ocserv.service</command> +              </leafNode>                <leafNode name="pptp">                  <properties>                    <help>Monitor last lines of PPTP</help> diff --git a/op-mode-definitions/openvpn.xml.in b/op-mode-definitions/openvpn.xml.in index b2763da81..0a2657398 100644 --- a/op-mode-definitions/openvpn.xml.in +++ b/op-mode-definitions/openvpn.xml.in @@ -20,7 +20,7 @@              <properties>                <help>Reset OpenVPN process on interface</help>                <completionHelp> -                <script>sudo ${vyos_completion_dir}/list_interfaces.py --type openvpn</script> +                <path>interfaces openvpn</path>                </completionHelp>              </properties>              <command>sudo ${vyos_op_scripts_dir}/openvpn.py reset --interface $4</command> @@ -51,7 +51,7 @@              <properties>                <help>Show OpenVPN interface information</help>                <completionHelp> -                <script>sudo ${vyos_completion_dir}/list_interfaces.py --type openvpn</script> +                <path>interfaces openvpn</path>                </completionHelp>              </properties>              <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name=$4</command> diff --git a/op-mode-definitions/show-arp.xml.in b/op-mode-definitions/show-arp.xml.in index 8662549fc..3680c20c6 100644 --- a/op-mode-definitions/show-arp.xml.in +++ b/op-mode-definitions/show-arp.xml.in @@ -12,7 +12,7 @@              <properties>                <help>Show Address Resolution Protocol (ARP) cache for specified interface</help>                <completionHelp> -                <script>${vyos_completion_dir}/list_interfaces.py -b</script> +                <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script>                </completionHelp>              </properties>              <command>${vyos_op_scripts_dir}/neighbor.py show --family inet --interface "$4"</command> diff --git a/op-mode-definitions/show-bridge.xml.in b/op-mode-definitions/show-bridge.xml.in index dd2a28931..e7a646fdc 100644 --- a/op-mode-definitions/show-bridge.xml.in +++ b/op-mode-definitions/show-bridge.xml.in @@ -25,7 +25,7 @@          <properties>            <help>Show bridge information for a given bridge interface</help>            <completionHelp> -            <script>${vyos_completion_dir}/list_interfaces.py --type bridge</script> +            <path>interfaces bridge</path>            </completionHelp>          </properties>          <command>bridge -c link show | grep "master $3"</command> diff --git a/op-mode-definitions/show-interfaces-wireguard.xml.in b/op-mode-definitions/show-interfaces-wireguard.xml.in index eba8de568..75b0cc88e 100644 --- a/op-mode-definitions/show-interfaces-wireguard.xml.in +++ b/op-mode-definitions/show-interfaces-wireguard.xml.in @@ -8,7 +8,7 @@              <properties>                <help>Show specified WireGuard interface information</help>                <completionHelp> -                <script>${vyos_completion_dir}/list_interfaces.py --type wireguard</script> +                <path>interfaces wireguard</path>                </completionHelp>              </properties>  	        <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wireguard</command> diff --git a/op-mode-definitions/show-interfaces-wireless.xml.in b/op-mode-definitions/show-interfaces-wireless.xml.in index b0a272225..cdd591f82 100644 --- a/op-mode-definitions/show-interfaces-wireless.xml.in +++ b/op-mode-definitions/show-interfaces-wireless.xml.in @@ -28,7 +28,7 @@              <properties>                <help>Show specified wireless interface information</help>                <completionHelp> -                <script>${vyos_completion_dir}/list_interfaces.py --type wireless</script> +                <path>interfaces wireless</path>                </completionHelp>              </properties>              <command>${vyos_op_scripts_dir}/interfaces.py show --intf_name="$4" --intf_type=wireless</command> diff --git a/op-mode-definitions/show-ip-multicast.xml.in b/op-mode-definitions/show-ip-multicast.xml.in index 80d83b424..605d61e8d 100644 --- a/op-mode-definitions/show-ip-multicast.xml.in +++ b/op-mode-definitions/show-ip-multicast.xml.in @@ -13,13 +13,7 @@                  <properties>                    <help>Show multicast interfaces</help>                  </properties> -                <command>if ps -C igmpproxy &>/dev/null; then ${vyos_op_scripts_dir}/show_igmpproxy.py --interface; else echo IGMP proxy not configured; fi</command> -              </leafNode> -              <leafNode name="mfc"> -                <properties> -                  <help>Show multicast fowarding cache</help> -                </properties> -                <command>if ps -C igmpproxy &>/dev/null; then ${vyos_op_scripts_dir}/show_igmpproxy.py --mfc; else echo IGMP proxy not configured; fi</command> +                <command>${vyos_op_scripts_dir}/igmp-proxy.py show_interface</command>                </leafNode>                <leafNode name="summary">                  <properties> diff --git a/op-mode-definitions/show-ip.xml.in b/op-mode-definitions/show-ip.xml.in index 0751c50cb..a710e33d2 100644 --- a/op-mode-definitions/show-ip.xml.in +++ b/op-mode-definitions/show-ip.xml.in @@ -17,7 +17,7 @@                  <properties>                    <help>Show IPv4 neighbor table for specified interface</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py -b</script> +                    <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script>                    </completionHelp>                  </properties>                  <command>${vyos_op_scripts_dir}/neighbor.py show --family inet --interface "$5"</command> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 6608ea0d8..f5e5b1493 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -196,6 +196,12 @@                </tagNode>              </children>            </tagNode> +          <leafNode name="ipoe-server"> +            <properties> +              <help>Show log for IPoE server</help> +            </properties> +            <command>journalctl --no-hostname --boot --unit accel-ppp@ipoe.service</command> +          </leafNode>            <leafNode name="kernel">              <properties>                <help>Show log for Linux Kernel</help> @@ -236,7 +242,7 @@                  <properties>                    <help>Show MACsec log on specific interface</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py -t macsec</script> +                    <path>interfaces macsec</path>                    </completionHelp>                  </properties>                  <command>SRC=$(cli-shell-api returnValue interfaces macsec "$5" source-interface); journalctl --no-hostname --boot --unit "wpa_supplicant-macsec@$SRC.service"</command> @@ -262,7 +268,7 @@            </node>            <node name="pppoe">              <properties> -              <help>Show log for PPPoE</help> +              <help>Show log for PPPoE interface</help>              </properties>              <command>journalctl --no-hostname --boot --unit "ppp@pppoe*.service"</command>              <children> @@ -270,13 +276,19 @@                  <properties>                    <help>Show PPPoE log on specific interface</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py -t pppoe</script> +                    <path>interfaces pppoe</path>                    </completionHelp>                  </properties>                  <command>journalctl --no-hostname --boot --unit "ppp@$5.service"</command>                </tagNode>              </children>            </node> +          <leafNode name="pppoe-server"> +            <properties> +              <help>Show log for PPPoE server</help> +            </properties> +            <command>journalctl --no-hostname --boot --unit accel-ppp@pppoe.service</command> +          </leafNode>            <node name="protocol">              <properties>                <help>Show log for Routing Protocol</help> @@ -378,7 +390,7 @@                  <properties>                    <help>Show SSTP client log on specific interface</help>                    <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces.py -t sstpc</script> +                    <path>interfaces sstpc</path>                    </completionHelp>                  </properties>                  <command>journalctl --no-hostname --boot --unit "ppp@$5.service"</command> @@ -409,7 +421,7 @@                  <properties>                    <help>Show log for ALL</help>                  </properties> -                <command>journalctl --no-hostname --boot --unit strongswan-starter.service --unit accel-ppp@*.service</command> +                <command>journalctl --no-hostname --boot --unit strongswan-starter.service --unit accel-ppp@*.service --unit ocserv.service</command>                </leafNode>                <leafNode name="ipsec">                  <properties> @@ -423,6 +435,12 @@                  </properties>                  <command>journalctl --no-hostname --boot --unit accel-ppp@l2tp.service</command>                </leafNode> +              <leafNode name="openconnect"> +                <properties> +                  <help>Show log for OpenConnect</help> +                </properties> +                <command>journalctl --no-hostname --boot --unit ocserv.service</command> +              </leafNode>                <leafNode name="pptp">                  <properties>                    <help>Show log for PPTP</help> diff --git a/op-mode-definitions/show-protocols.xml.in b/op-mode-definitions/show-protocols.xml.in index 698001b76..27146f90d 100644 --- a/op-mode-definitions/show-protocols.xml.in +++ b/op-mode-definitions/show-protocols.xml.in @@ -22,7 +22,7 @@                      <properties>                        <help>Show Address Resolution Protocol (ARP) cache for specified interface</help>                        <completionHelp> -                        <script>${vyos_completion_dir}/list_interfaces.py -b</script> +                        <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script>                        </completionHelp>                      </properties>                      <command>/usr/sbin/arp -e -n -i "$6"</command> diff --git a/op-mode-definitions/show-system.xml.in b/op-mode-definitions/show-system.xml.in index 4a0e6c3b2..85bfdcdba 100644 --- a/op-mode-definitions/show-system.xml.in +++ b/op-mode-definitions/show-system.xml.in @@ -7,6 +7,42 @@            <help>Show system information</help>          </properties>          <children> +          <node name="commit"> +            <properties> +              <help>Show commit revision log</help> +            </properties> +            <command>${vyos_op_scripts_dir}/config_mgmt.py show_commit_log</command> +            <children> +              <tagNode name="diff"> +                <properties> +                  <help>Show commit revision diff</help> +                </properties> +                <command>${vyos_op_scripts_dir}/config_mgmt.py show_commit_diff --rev "$5"</command> +              </tagNode> +              <tagNode name="file"> +                <properties> +                  <help>Show commit revision file</help> +                </properties> +                <command>${vyos_op_scripts_dir}/config_mgmt.py show_commit_file --rev "$5"</command> +                <children> +                  <tagNode name="compare"> +                    <properties> +                      <help>Compare config file revisions</help> +                    </properties> +                    <command>${vyos_op_scripts_dir}/config_mgmt.py show_commit_diff --rev "$5" --rev2 "$7"</command> +                    <children> +                      <leafNode name="commands"> +                        <properties> +                          <help>Compare config file revision commands</help> +                        </properties> +                        <command>${vyos_op_scripts_dir}/config_mgmt.py show_commit_diff --rev "$5" --rev2 "$7" --commands</command> +                      </leafNode> +                    </children> +                  </tagNode> +                </children> +              </tagNode> +            </children> +          </node>            <node name="connections">              <properties>                <help>Show active network connections on the system</help> diff --git a/op-mode-definitions/wireless.xml.in b/op-mode-definitions/wireless.xml.in index 5d9db1544..f8e53ad21 100644 --- a/op-mode-definitions/wireless.xml.in +++ b/op-mode-definitions/wireless.xml.in @@ -21,7 +21,7 @@              <properties>                <help>Clear interface information for a given wireless interface</help>                <completionHelp> -                <script>${vyos_completion_dir}/list_interfaces.py --type wireless</script> +                <path>interfaces wireless</path>                </completionHelp>              </properties>              <children> diff --git a/op-mode-definitions/zone-policy.xml.in b/op-mode-definitions/zone-policy.xml.in index c4b02bcee..9d65ddd3d 100644 --- a/op-mode-definitions/zone-policy.xml.in +++ b/op-mode-definitions/zone-policy.xml.in @@ -11,13 +11,13 @@              <properties>                <help>Show summary of zone policy for a specific zone</help>                <completionHelp> -                <path>zone-policy zone</path> +                <path>firewall zone</path>                </completionHelp>              </properties> -            <command>sudo ${vyos_op_scripts_dir}/zone_policy.py --action show --name $4</command> +            <command>sudo ${vyos_op_scripts_dir}/zone.py show --zone $4</command>            </tagNode>          </children> -        <command>sudo ${vyos_op_scripts_dir}/zone_policy.py --action show</command> +        <command>sudo ${vyos_op_scripts_dir}/zone.py show</command>        </node>      </children>    </node> diff --git a/python/setup.py b/python/setup.py index e2d28bd6b..2d614e724 100644 --- a/python/setup.py +++ b/python/setup.py @@ -24,4 +24,9 @@ setup(          "Topic :: Utilities",          "License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)",      ], +    entry_points={ +        "console_scripts": [ +            "config-mgmt = vyos.config_mgmt:run", +        ], +    },  ) diff --git a/python/vyos/config_mgmt.py b/python/vyos/config_mgmt.py new file mode 100644 index 000000000..22a49ff50 --- /dev/null +++ b/python/vyos/config_mgmt.py @@ -0,0 +1,686 @@ +# Copyright 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/>. + +import os +import re +import sys +import gzip +import logging +from typing import Optional, Tuple, Union +from filecmp import cmp +from datetime import datetime +from tabulate import tabulate + +from vyos.config import Config +from vyos.configtree import ConfigTree +from vyos.defaults import directories +from vyos.util import is_systemd_service_active, ask_yes_no, rc_cmd + +SAVE_CONFIG = '/opt/vyatta/sbin/vyatta-save-config.pl' + +# created by vyatta-cfg-postinst +commit_post_hook_dir = '/etc/commit/post-hooks.d' + +commit_hooks = {'commit_revision': '01vyos-commit-revision', +                'commit_archive': '02vyos-commit-archive'} + +DEFAULT_TIME_MINUTES = 10 +timer_name = 'commit-confirm' + +config_file = os.path.join(directories['config'], 'config.boot') +archive_dir = os.path.join(directories['config'], 'archive') +archive_config_file = os.path.join(archive_dir, 'config.boot') +commit_log_file = os.path.join(archive_dir, 'commits') +logrotate_conf = os.path.join(archive_dir, 'lr.conf') +logrotate_state = os.path.join(archive_dir, 'lr.state') +rollback_config = os.path.join(archive_dir, 'config.boot-rollback') +prerollback_config = os.path.join(archive_dir, 'config.boot-prerollback') +tmp_log_entry = '/tmp/commit-rev-entry' + +logger = logging.getLogger('config_mgmt') +logger.setLevel(logging.INFO) +ch = logging.StreamHandler() +formatter = logging.Formatter('%(funcName)s: %(levelname)s:%(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + +class ConfigMgmtError(Exception): +    pass + +class ConfigMgmt: +    def __init__(self, session_env=None, config=None): +        if session_env: +            self._session_env = session_env +        else: +            self._session_env = None + +        if config is None: +            config = Config() + +        d = config.get_config_dict(['system', 'config-management'], +                                   key_mangling=('-', '_'), +                                   get_first_key=True) + +        self.max_revisions = int(d.get('commit_revisions', 0)) +        self.locations = d.get('commit_archive', {}).get('location', []) +        self.source_address = d.get('commit_archive', +                                    {}).get('source_address', '') +        if config.exists(['system', 'host-name']): +            self.hostname = config.return_value(['system', 'host-name']) +        else: +            self.hostname = 'vyos' + +        # upload only on existence of effective values, notably, on boot. +        # one still needs session self.locations (above) for setting +        # post-commit hook in conf_mode script +        path = ['system', 'config-management', 'commit-archive', 'location'] +        if config.exists_effective(path): +            self.effective_locations = config.return_effective_values(path) +        else: +            self.effective_locations = [] + +        # a call to compare without args is edit_level aware +        edit_level = os.getenv('VYATTA_EDIT_LEVEL', '') +        edit_path = [l for l in edit_level.split('/') if l] +        if edit_path: +            eff_conf = config.show_config(edit_path, effective=True) +            self.edit_level_active_config = ConfigTree(eff_conf) +            conf = config.show_config(edit_path) +            self.edit_level_working_config = ConfigTree(conf) +        else: +            self.edit_level_active_config = None +            self.edit_level_working_config = None + +        self.active_config = config._running_config +        self.working_config = config._session_config + +    @staticmethod +    def save_config(target): +        cmd = f'{SAVE_CONFIG} {target}' +        rc, out = rc_cmd(cmd) +        if rc != 0: +            logger.critical(f'save config failed: {out}') + +    def _unsaved_commits(self) -> bool: +        tmp_save = '/tmp/config.boot.check-save' +        self.save_config(tmp_save) +        ret = not cmp(tmp_save, config_file, shallow=False) +        os.unlink(tmp_save) +        return ret + +    # Console script functions +    # +    def commit_confirm(self, minutes: int=DEFAULT_TIME_MINUTES, +                       no_prompt: bool=False) -> Tuple[str,int]: +        """Commit with reboot to saved config in 'minutes' minutes if +        'confirm' call is not issued. +        """ +        if is_systemd_service_active(f'{timer_name}.timer'): +            msg = 'Another confirm is pending' +            return msg, 1 + +        if self._unsaved_commits(): +            W = '\nYou should save previous commits before commit-confirm !\n' +        else: +            W = '' + +        prompt_str = f''' +commit-confirm will automatically reboot in {minutes} minutes unless changes +are confirmed.\n +Proceed ?''' +        prompt_str = W + prompt_str +        if not no_prompt and not ask_yes_no(prompt_str, default=True): +            msg = 'commit-confirm canceled' +            return msg, 1 + +        action = 'sg vyattacfg "/usr/bin/config-mgmt revert"' +        cmd = f'sudo systemd-run --quiet --on-active={minutes}m --unit={timer_name} {action}' +        rc, out = rc_cmd(cmd) +        if rc != 0: +            raise ConfigMgmtError(out) + +        # start notify +        cmd = f'sudo -b /usr/libexec/vyos/commit-confirm-notify.py {minutes}' +        os.system(cmd) + +        msg = f'Initialized commit-confirm; {minutes} minutes to confirm before reboot' +        return msg, 0 + +    def confirm(self) -> Tuple[str,int]: +        """Do not reboot to saved config following 'commit-confirm'. +        Update commit log and archive. +        """ +        if not is_systemd_service_active(f'{timer_name}.timer'): +            msg = 'No confirm pending' +            return msg, 0 + +        cmd = f'sudo systemctl stop --quiet {timer_name}.timer' +        rc, out = rc_cmd(cmd) +        if rc != 0: +            raise ConfigMgmtError(out) + +        # kill notify +        cmd = 'sudo pkill -f commit-confirm-notify.py' +        rc, out = rc_cmd(cmd) +        if rc != 0: +            raise ConfigMgmtError(out) + +        entry = self._read_tmp_log_entry() +        self._add_log_entry(**entry) + +        if self._archive_active_config(): +            self._update_archive() + +        msg = 'Reboot timer stopped' +        return msg, 0 + +    def revert(self) -> Tuple[str,int]: +        """Reboot to saved config, dropping commits from 'commit-confirm'. +        """ +        _ = self._read_tmp_log_entry() + +        # archived config will be reverted on boot +        rc, out = rc_cmd('sudo systemctl reboot') +        if rc != 0: +            raise ConfigMgmtError(out) + +        return '', 0 + +    def rollback(self, rev: int, no_prompt: bool=False) -> Tuple[str,int]: +        """Reboot to config revision 'rev'. +        """ +        from shutil import copy + +        msg = '' + +        if not self._check_revision_number(rev): +            msg = f'Invalid revision number {rev}: must be 0 < rev < {maxrev}' +            return msg, 1 + +        prompt_str = 'Proceed with reboot ?' +        if not no_prompt and not ask_yes_no(prompt_str, default=True): +            msg = 'Canceling rollback' +            return msg, 0 + +        rc, out = rc_cmd(f'sudo cp {archive_config_file} {prerollback_config}') +        if rc != 0: +            raise ConfigMgmtError(out) + +        path = os.path.join(archive_dir, f'config.boot.{rev}.gz') +        with gzip.open(path) as f: +            config = f.read() +        try: +            with open(rollback_config, 'wb') as f: +                f.write(config) +            copy(rollback_config, config_file) +        except OSError as e: +            raise ConfigMgmtError from e + +        rc, out = rc_cmd('sudo systemctl reboot') +        if rc != 0: +            raise ConfigMgmtError(out) + +        return msg, 0 + +    def compare(self, saved: bool=False, commands: bool=False, +                rev1: Optional[int]=None, +                rev2: Optional[int]=None) -> Tuple[str,int]: +        """General compare function for config file revisions: +        revision n vs. revision m; working version vs. active version; +        or working version vs. saved version. +        """ +        from difflib import unified_diff + +        ct1 = self.edit_level_active_config +        if ct1 is None: +            ct1 = self.active_config +        ct2 = self.edit_level_working_config +        if ct2 is None: +            ct2 = self.working_config +        msg = 'No changes between working and active configurations.\n' +        if saved: +            ct1 = self._get_saved_config_tree() +            ct2 = self.working_config +            msg = 'No changes between working and saved configurations.\n' +        if rev1 is not None: +            if not self._check_revision_number(rev1): +                return f'Invalid revision number {rev1}', 1 +            ct1 = self._get_config_tree_revision(rev1) +            ct2 = self.working_config +            msg = f'No changes between working and revision {rev1} configurations.\n' +        if rev2 is not None: +            if not self._check_revision_number(rev2): +                return f'Invalid revision number {rev2}', 1 +            # compare older to newer +            ct2 = ct1 +            ct1 = self._get_config_tree_revision(rev2) +            msg = f'No changes between revisions {rev2} and {rev1} configurations.\n' + +        if commands: +            lines1 = ct1.to_commands().splitlines(keepends=True) +            lines2 = ct2.to_commands().splitlines(keepends=True) +        else: +            lines1 = ct1.to_string().splitlines(keepends=True) +            lines2 = ct2.to_string().splitlines(keepends=True) + +        out = '' +        comp = unified_diff(lines1, lines2) +        for line in comp: +            if re.match(r'(\-\-)|(\+\+)|(@@)', line): +                continue +            out += line +        if out: +            msg = out + +        return msg, 0 + +    def wrap_compare(self, options) -> Tuple[str,int]: +        """Interface to vyatta-cfg-run: args collected as 'options' to parse +        for compare. +        """ +        cmnds = False +        r1 = None +        r2 = None +        if 'commands' in options: +            cmnds=True +            options.remove('commands') +        for i in options: +            if not i.isnumeric(): +                options.remove(i) +        if len(options) > 0: +            r1 = int(options[0]) +        if len(options) > 1: +            r2 = int(options[1]) + +        return self.compare(commands=cmnds, rev1=r1, rev2=r2) + +    # Initialization and post-commit hooks for conf-mode +    # +    def initialize_revision(self): +        """Initialize config archive, logrotate conf, and commit log. +        """ +        mask = os.umask(0o002) +        os.makedirs(archive_dir, exist_ok=True) + +        self._add_logrotate_conf() + +        if (not os.path.exists(commit_log_file) or +            self._get_number_of_revisions() == 0): +            user = self._get_user() +            via = 'init' +            comment = '' +            self._add_log_entry(user, via, comment) +            # add empty init config before boot-config load for revision +            # and diff consistency +            if self._archive_active_config(): +                self._update_archive() + +        os.umask(mask) + +    def commit_revision(self): +        """Update commit log and rotate archived config.boot. + +        commit_revision is called in post-commit-hooks, if +        ['commit-archive', 'commit-revisions'] is configured. +        """ +        if os.getenv('IN_COMMIT_CONFIRM', ''): +            self._new_log_entry(tmp_file=tmp_log_entry) +            return + +        self._add_log_entry() + +        if self._archive_active_config(): +            self._update_archive() + +    def commit_archive(self): +        """Upload config to remote archive. +        """ +        from vyos.remote import upload + +        hostname = self.hostname +        t = datetime.now() +        timestamp = t.strftime('%Y%m%d_%H%M%S') +        remote_file = f'config.boot-{hostname}.{timestamp}' +        source_address = self.source_address + +        for location in self.effective_locations: +            upload(archive_config_file, f'{location}/{remote_file}', +                   source_host=source_address) + +    # op-mode functions +    # +    def get_raw_log_data(self) -> list: +        """Return list of dicts of log data: +           keys: [timestamp, user, commit_via, commit_comment] +        """ +        log = self._get_log_entries() +        res_l = [] +        for line in log: +            d = self._get_log_entry(line) +            res_l.append(d) + +        return res_l + +    @staticmethod +    def format_log_data(data: list) -> str: +        """Return formatted log data as str. +        """ +        res_l = [] +        for l_no, l in enumerate(data): +            time_d = datetime.fromtimestamp(int(l['timestamp'])) +            time_str = time_d.strftime("%Y-%m-%d %H:%M:%S") + +            res_l.append([l_no, time_str, +                          f"by {l['user']}", f"via {l['commit_via']}"]) + +            if l['commit_comment'] != 'commit': # default comment +                res_l.append([None, l['commit_comment']]) + +        ret = tabulate(res_l, tablefmt="plain") +        return ret + +    @staticmethod +    def format_log_data_brief(data: list) -> str: +        """Return 'brief' form of log data as str. + +        Slightly compacted format used in completion help for +        'rollback'. +        """ +        res_l = [] +        for l_no, l in enumerate(data): +            time_d = datetime.fromtimestamp(int(l['timestamp'])) +            time_str = time_d.strftime("%Y-%m-%d %H:%M:%S") + +            res_l.append(['\t', l_no, time_str, +                          f"{l['user']}", f"by {l['commit_via']}"]) + +        ret = tabulate(res_l, tablefmt="plain") +        return ret + +    def show_commit_diff(self, rev: int, rev2: Optional[int]=None, +                         commands: bool=False) -> str: +        """Show commit diff at revision number, compared to previous +        revision, or to another revision. +        """ +        if rev2 is None: +            out, _ = self.compare(commands=commands, rev1=rev, rev2=(rev+1)) +            return out + +        out, _ = self.compare(commands=commands, rev1=rev, rev2=rev2) +        return out + +    def show_commit_file(self, rev: int) -> str: +        return self._get_file_revision(rev) + +    # utility functions +    # +    @staticmethod +    def _strip_version(s): +        return re.split(r'(^//)', s, maxsplit=1, flags=re.MULTILINE)[0] + +    def _get_saved_config_tree(self): +        with open(config_file) as f: +            c = self._strip_version(f.read()) +        return ConfigTree(c) + +    def _get_file_revision(self, rev: int): +        if rev not in range(0, self._get_number_of_revisions()): +            raise ConfigMgmtError('revision not available') +        revision = os.path.join(archive_dir, f'config.boot.{rev}.gz') +        with gzip.open(revision) as f: +            r = f.read().decode() +        return r + +    def _get_config_tree_revision(self, rev: int): +        c = self._strip_version(self._get_file_revision(rev)) +        return ConfigTree(c) + +    def _add_logrotate_conf(self): +        conf = f"""{archive_config_file} {{ +    su root vyattacfg +    rotate {self.max_revisions} +    start 0 +    compress +    copy +}}""" +        mask = os.umask(0o133) + +        with open(logrotate_conf, 'w') as f: +            f.write(conf) + +        os.umask(mask) + +    def _archive_active_config(self) -> bool: +        mask = os.umask(0o113) + +        ext = os.getpid() +        tmp_save = f'/tmp/config.boot.{ext}' +        self.save_config(tmp_save) + +        try: +            if cmp(tmp_save, archive_config_file, shallow=False): +                # this will be the case on boot, as well as certain +                # re-initialiation instances after delete/set +                os.unlink(tmp_save) +                return False +        except FileNotFoundError: +            pass + +        rc, out = rc_cmd(f'sudo mv {tmp_save} {archive_config_file}') +        os.umask(mask) + +        if rc != 0: +            logger.critical(f'mv file to archive failed: {out}') +            return False + +        return True + +    @staticmethod +    def _update_archive(): +        cmd = f"sudo logrotate -f -s {logrotate_state} {logrotate_conf}" +        rc, out = rc_cmd(cmd) +        if rc != 0: +            logger.critical(f'logrotate failure: {out}') + +    @staticmethod +    def _get_log_entries() -> list: +        """Return lines of commit log as list of strings +        """ +        entries = [] +        if os.path.exists(commit_log_file): +            with open(commit_log_file) as f: +                entries = f.readlines() + +        return entries + +    def _get_number_of_revisions(self) -> int: +        l = self._get_log_entries() +        return len(l) + +    def _check_revision_number(self, rev: int) -> bool: +        # exclude init revision: +        maxrev = self._get_number_of_revisions() +        if not 0 <= rev < maxrev - 1: +            return False +        return True + +    @staticmethod +    def _get_user() -> str: +        import pwd + +        try: +            user = os.getlogin() +        except OSError: +            try: +                user = pwd.getpwuid(os.geteuid())[0] +            except KeyError: +                user = 'unknown' +        return user + +    def _new_log_entry(self, user: str='', commit_via: str='', +                       commit_comment: str='', timestamp: Optional[int]=None, +                       tmp_file: str=None) -> Optional[str]: +        # Format log entry and return str or write to file. +        # +        # Usage is within a post-commit hook, using env values. In case of +        # commit-confirm, it can be written to a temporary file for +        # inclusion on 'confirm'. +        from time import time + +        if timestamp is None: +            timestamp = int(time()) + +        if not user: +            user = self._get_user() +        if not commit_via: +            commit_via = os.getenv('COMMIT_VIA', 'other') +        if not commit_comment: +            commit_comment = os.getenv('COMMIT_COMMENT', 'commit') + +        # the commit log reserves '|' as field demarcation, so replace in +        # comment if present; undo this in _get_log_entry, below +        if re.search(r'\|', commit_comment): +            commit_comment = commit_comment.replace('|', '%%') + +        entry = f'|{timestamp}|{user}|{commit_via}|{commit_comment}|\n' + +        mask = os.umask(0o113) +        if tmp_file is not None: +            try: +                with open(tmp_file, 'w') as f: +                    f.write(entry) +            except OSError as e: +                logger.critical(f'write to {tmp_file} failed: {e}') +            os.umask(mask) +            return None + +        os.umask(mask) +        return entry + +    @staticmethod +    def _get_log_entry(line: str) -> dict: +        log_fmt = re.compile(r'\|.*\|\n?$') +        keys = ['user', 'commit_via', 'commit_comment', 'timestamp'] +        if not log_fmt.match(line): +            logger.critical(f'Invalid log format {line}') +            return {} + +        timestamp, user, commit_via, commit_comment = ( +        tuple(line.strip().strip('|').split('|'))) + +        commit_comment = commit_comment.replace('%%', '|') +        d = dict(zip(keys, [user, commit_via, +                            commit_comment, timestamp])) + +        return d + +    def _read_tmp_log_entry(self) -> dict: +        try: +            with open(tmp_log_entry) as f: +                entry = f.read() +            os.unlink(tmp_log_entry) +        except OSError as e: +            logger.critical(f'error on file {tmp_log_entry}: {e}') + +        return self._get_log_entry(entry) + +    def _add_log_entry(self, user: str='', commit_via: str='', +                       commit_comment: str='', timestamp: Optional[int]=None): +        mask = os.umask(0o113) + +        entry = self._new_log_entry(user=user, commit_via=commit_via, +                                    commit_comment=commit_comment, +                                    timestamp=timestamp) + +        log_entries = self._get_log_entries() +        log_entries.insert(0, entry) +        if len(log_entries) > self.max_revisions: +            log_entries = log_entries[:-1] + +        try: +            with open(commit_log_file, 'w') as f: +                f.writelines(log_entries) +        except OSError as e: +            logger.critical(e) + +        os.umask(mask) + +# entry_point for console script +# +def run(): +    from argparse import ArgumentParser, REMAINDER + +    config_mgmt = ConfigMgmt() + +    for s in list(commit_hooks): +        if sys.argv[0].replace('-', '_').endswith(s): +            func = getattr(config_mgmt, s) +            try: +                func() +            except Exception as e: +                print(f'{s}: {e}') +            sys.exit(0) + +    parser = ArgumentParser() +    subparsers = parser.add_subparsers(dest='subcommand') + +    commit_confirm = subparsers.add_parser('commit_confirm', +                     help="Commit with opt-out reboot to saved config") +    commit_confirm.add_argument('-t', dest='minutes', type=int, +                                default=DEFAULT_TIME_MINUTES, +                                help="Minutes until reboot, unless 'confirm'") +    commit_confirm.add_argument('-y', dest='no_prompt', action='store_true', +                                help="Execute without prompt") + +    subparsers.add_parser('confirm', help="Confirm commit") +    subparsers.add_parser('revert', help="Revert commit-confirm") + +    rollback = subparsers.add_parser('rollback', +                                     help="Rollback to earlier config") +    rollback.add_argument('--rev', type=int, +                          help="Revision number for rollback") +    rollback.add_argument('-y', dest='no_prompt', action='store_true', +                          help="Excute without prompt") + +    compare = subparsers.add_parser('compare', +                                    help="Compare config files") + +    compare.add_argument('--saved', action='store_true', +                         help="Compare session config with saved config") +    compare.add_argument('--commands', action='store_true', +                         help="Show difference between commands") +    compare.add_argument('--rev1', type=int, default=None, +                         help="Compare revision with session config or other revision") +    compare.add_argument('--rev2', type=int, default=None, +                         help="Compare revisions") + +    wrap_compare = subparsers.add_parser('wrap_compare', +                                         help="Wrapper interface for vyatta-cfg-run") +    wrap_compare.add_argument('--options', nargs=REMAINDER) + +    args = vars(parser.parse_args()) + +    func = getattr(config_mgmt, args['subcommand']) +    del args['subcommand'] + +    res = '' +    try: +        res, rc = func(**args) +    except ConfigMgmtError as e: +        print(e) +        sys.exit(1) +    if res: +        print(res) +    sys.exit(rc) diff --git a/python/vyos/configtree.py b/python/vyos/configtree.py index b88615513..f2358ee4f 100644 --- a/python/vyos/configtree.py +++ b/python/vyos/configtree.py @@ -242,7 +242,8 @@ class ConfigTree(object):              raise ConfigTreeError()          res = self.__copy(self.__config, oldpath_str, newpath_str)          if (res != 0): -            raise ConfigTreeError("Path [{}] doesn't exist".format(old_path)) +            msg = self.__get_error().decode() +            raise ConfigTreeError(msg)          if self.__migration:              print(f"- op: copy old_path: {old_path} new_path: {new_path}") diff --git a/python/vyos/cpu.py b/python/vyos/cpu.py index 488ae79fb..d2e5f6504 100644 --- a/python/vyos/cpu.py +++ b/python/vyos/cpu.py @@ -73,7 +73,7 @@ def _find_physical_cpus():              # On other architectures, e.g. on ARM, there's no such field.              # We just assume they are different CPUs,              # whether single core ones or cores of physical CPUs. -            phys_cpus[num] = cpu[num] +            phys_cpus[num] = cpus[num]      return phys_cpus diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py index 2b6012a73..abf8de688 100644 --- a/python/vyos/ethtool.py +++ b/python/vyos/ethtool.py @@ -56,10 +56,10 @@ class Ethtool:      def __init__(self, ifname):          # Get driver used for interface -        sysfs_file = f'/sys/class/net/{ifname}/device/driver/module' -        if os.path.exists(sysfs_file): -            link = os.readlink(sysfs_file) -            self._driver_name = os.path.basename(link) +        out, err = popen(f'ethtool --driver {ifname}') +        driver = re.search(r'driver:\s(\w+)', out) +        if driver: +            self._driver_name = driver.group(1)          # Build a dictinary of supported link-speed and dupley settings.          out, err = popen(f'ethtool {ifname}') diff --git a/python/vyos/ifconfig/input.py b/python/vyos/ifconfig/input.py index db7d2b6b4..3e5f5790d 100644 --- a/python/vyos/ifconfig/input.py +++ b/python/vyos/ifconfig/input.py @@ -1,4 +1,4 @@ -# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 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 @@ -17,6 +17,16 @@ from vyos.ifconfig.interface import Interface  @Interface.register  class InputIf(Interface): +    """ +    The Intermediate Functional Block (ifb) pseudo network interface acts as a +    QoS concentrator for multiple different sources of traffic. Packets from +    or to other interfaces have to be redirected to it using the mirred action +    in order to be handled, regularly routed traffic will be dropped. This way, +    a single stack of qdiscs, classes and filters can be shared between +    multiple interfaces. +    """ + +    iftype = 'ifb'      definition = {          **Interface.definition,          **{ diff --git a/python/vyos/opmode.py b/python/vyos/opmode.py index 30e893d74..d02ad4de6 100644 --- a/python/vyos/opmode.py +++ b/python/vyos/opmode.py @@ -1,4 +1,4 @@ -# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2022-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 @@ -22,6 +22,10 @@ from humps import decamelize  class Error(Exception):      """ Any error that makes requested operation impossible to complete          for reasons unrelated to the user input or script logic. + +        This is the base class, scripts should not use it directly +        and should raise more specific errors instead, +        whenever possible.      """      pass @@ -45,6 +49,13 @@ class PermissionDenied(Error):      """      pass +class InsufficientResources(Error): +    """ Requested operation and its arguments are valid but the system +        does not have enough resources (such as drive space or memory) +        to complete it. +    """ +    pass +  class UnsupportedOperation(Error):      """ Requested operation is technically valid but is not implemented yet. """      pass @@ -70,7 +81,7 @@ class InternalError(Error):  def _is_op_mode_function_name(name): -    if re.match(r"^(show|clear|reset|restart|add|delete|generate)", name): +    if re.match(r"^(show|clear|reset|restart|add|delete|generate|set)", name):          return True      else:          return False @@ -217,6 +228,9 @@ def run(module):          if not args["raw"]:              return res          else: +            if not isinstance(res, dict) and not isinstance(res, list): +                raise InternalError(f"Bare literal is not an acceptable raw output, must be a list or an object.\ +                  The output was:{res}")              res = decamelize(res)              res = _normalize_field_names(res)              from json import dumps diff --git a/python/vyos/template.py b/python/vyos/template.py index e079a820b..15240f815 100644 --- a/python/vyos/template.py +++ b/python/vyos/template.py @@ -486,6 +486,8 @@ def get_esp_ike_cipher(group_config, ike_group=None):                  continue              tmp = '{encryption}-{hash}'.format(**proposal) +            if 'prf' in proposal: +                tmp += '-' + proposal['prf']              if 'dh_group' in proposal:                  tmp += '-' + pfs_lut[ 'dh-group' +  proposal['dh_group'] ]              elif 'pfs' in group_config and group_config['pfs'] != 'disable': diff --git a/python/vyos/util.py b/python/vyos/util.py index 110da3be5..66ded464d 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -488,7 +488,7 @@ def is_listen_port_bind_service(port: int, service: str) -> bool:      Example:          % is_listen_port_bind_service(443, 'nginx')          True -        % is_listen_port_bind_service(443, 'ocservr-main') +        % is_listen_port_bind_service(443, 'ocserv-main')          False      """      from psutil import net_connections as connections diff --git a/smoketest/scripts/cli/test_ha_vrrp.py b/smoketest/scripts/cli/test_ha_vrrp.py index 68905e447..3a4de2d8d 100755 --- a/smoketest/scripts/cli/test_ha_vrrp.py +++ b/smoketest/scripts/cli/test_ha_vrrp.py @@ -87,11 +87,21 @@ class TestVRRP(VyOSUnitTestSHIM.TestCase):          advertise_interval = '77'          priority = '123'          preempt_delay = '400' +        startup_delay = '120' +        garp_master_delay = '2' +        garp_master_repeat = '3' +        garp_master_refresh = '4' +        garp_master_refresh_repeat = '5' +        garp_interval = '1.5' +        group_garp_master_delay = '12' +        group_garp_master_repeat = '13' +        group_garp_master_refresh = '14'          for group in groups:              vlan_id = group.lstrip('VLAN')              vip = f'100.64.{vlan_id}.1/24'              group_base = base_path + ['vrrp', 'group', group] +            global_param_base = base_path + ['vrrp', 'global-parameters']              self.cli_set(['interfaces', 'ethernet', vrrp_interface, 'vif', vlan_id, 'address', inc_ip(vip, 1) + '/' + vip.split('/')[-1]]) @@ -110,9 +120,32 @@ class TestVRRP(VyOSUnitTestSHIM.TestCase):              self.cli_set(group_base + ['authentication', 'type', 'plaintext-password'])              self.cli_set(group_base + ['authentication', 'password', f'{group}']) +            # GARP +            self.cli_set(group_base + ['garp', 'master-delay', group_garp_master_delay]) +            self.cli_set(group_base + ['garp', 'master-repeat', group_garp_master_repeat]) +            self.cli_set(group_base + ['garp', 'master-refresh', group_garp_master_refresh]) + +        # Global parameters +        #config = getConfig(f'global_defs') +        self.cli_set(global_param_base + ['startup-delay', f'{startup_delay}']) +        self.cli_set(global_param_base + ['garp', 'interval', f'{garp_interval}']) +        self.cli_set(global_param_base + ['garp', 'master-delay', f'{garp_master_delay}']) +        self.cli_set(global_param_base + ['garp', 'master-repeat', f'{garp_master_repeat}']) +        self.cli_set(global_param_base + ['garp', 'master-refresh', f'{garp_master_refresh}']) +        self.cli_set(global_param_base + ['garp', 'master-refresh-repeat', f'{garp_master_refresh_repeat}']) +          # commit changes          self.cli_commit() +        # Check Global parameters +        config = getConfig(f'global_defs') +        self.assertIn(f'vrrp_startup_delay {startup_delay}', config) +        self.assertIn(f'vrrp_garp_interval {garp_interval}', config) +        self.assertIn(f'vrrp_garp_master_delay {garp_master_delay}', config) +        self.assertIn(f'vrrp_garp_master_repeat {garp_master_repeat}', config) +        self.assertIn(f'vrrp_garp_master_refresh {garp_master_refresh}', config) +        self.assertIn(f'vrrp_garp_master_refresh_repeat {garp_master_refresh_repeat}', config) +          for group in groups:              vlan_id = group.lstrip('VLAN')              vip = f'100.64.{vlan_id}.1/24' @@ -132,6 +165,11 @@ class TestVRRP(VyOSUnitTestSHIM.TestCase):              self.assertIn(f'auth_pass "{group}"', config)              self.assertIn(f'auth_type PASS', config) +            #GARP +            self.assertIn(f'garp_master_delay {group_garp_master_delay}', config) +            self.assertIn(f'garp_master_refresh {group_garp_master_refresh}', config) +            self.assertIn(f'garp_master_repeat {group_garp_master_repeat}', config) +      def test_03_sync_group(self):          sync_group = 'VyOS' diff --git a/smoketest/scripts/cli/test_interfaces_input.py b/smoketest/scripts/cli/test_interfaces_input.py new file mode 100755 index 000000000..c6d7febec --- /dev/null +++ b/smoketest/scripts/cli/test_interfaces_input.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# +# 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/>. + +import unittest + +from vyos.util import read_file +from vyos.ifconfig import Interface +from base_vyostest_shim import VyOSUnitTestSHIM + +base_path = ['interfaces', 'input'] + +# add a classmethod to setup a temporaray PPPoE server for "proper" validation +class InputInterfaceTest(VyOSUnitTestSHIM.TestCase): +    @classmethod +    def setUpClass(cls): +        super(InputInterfaceTest, cls).setUpClass() + +        cls._interfaces = ['ifb10', 'ifb20', 'ifb30'] + +    def tearDown(self): +        self.cli_delete(base_path) +        self.cli_commit() + +    def test_01_description(self): +        # Check if PPPoE dialer can be configured and runs +        for interface in self._interfaces: +            self.cli_set(base_path + [interface, 'description', f'foo-{interface}']) + +        # commit changes +        self.cli_commit() + +        # Validate remove interface description "empty" +        for interface in self._interfaces: +            tmp = read_file(f'/sys/class/net/{interface}/ifalias') +            self.assertEqual(tmp, f'foo-{interface}') +            self.assertEqual(Interface(interface).get_alias(), f'foo-{interface}') + +if __name__ == '__main__': +    unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_pppoe.py b/smoketest/scripts/cli/test_interfaces_pppoe.py index 8927121a8..08b7f2f46 100755 --- a/smoketest/scripts/cli/test_interfaces_pppoe.py +++ b/smoketest/scripts/cli/test_interfaces_pppoe.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2019-2022 VyOS maintainers and contributors +# 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 @@ -57,8 +57,8 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):      def test_01_pppoe_client(self):          # Check if PPPoE dialer can be configured and runs          for interface in self._interfaces: -            user = 'VyOS-user-' + interface -            passwd = 'VyOS-passwd-' + interface +            user = f'VyOS-user-{interface}' +            passwd = f'VyOS-passwd-{interface}'              mtu = '1400'              self.cli_set(base_path + [interface, 'authentication', 'user', user]) @@ -76,23 +76,26 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):          # verify configuration file(s)          for interface in self._interfaces: -            user = 'VyOS-user-' + interface -            password = 'VyOS-passwd-' + interface +            user = f'VyOS-user-{interface}' +            passwd = f'VyOS-passwd-{interface}'              tmp = get_config_value(interface, 'mtu')[1]              self.assertEqual(tmp, mtu)              tmp = get_config_value(interface, 'user')[1].replace('"', '')              self.assertEqual(tmp, user)              tmp = get_config_value(interface, 'password')[1].replace('"', '') -            self.assertEqual(tmp, password) +            self.assertEqual(tmp, passwd)              tmp = get_config_value(interface, 'ifname')[1]              self.assertEqual(tmp, interface)      def test_02_pppoe_client_disabled_interface(self):          # Check if PPPoE Client can be disabled          for interface in self._interfaces: -            self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos']) -            self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos']) +            user = f'VyOS-user-{interface}' +            passwd = f'VyOS-passwd-{interface}' + +            self.cli_set(base_path + [interface, 'authentication', 'user', user]) +            self.cli_set(base_path + [interface, 'authentication', 'password', passwd])              self.cli_set(base_path + [interface, 'source-interface', self._source_interface])              self.cli_set(base_path + [interface, 'disable']) @@ -117,7 +120,10 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):      def test_03_pppoe_authentication(self):          # When username or password is set - so must be the other          for interface in self._interfaces: -            self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos']) +            user = f'VyOS-user-{interface}' +            passwd = f'VyOS-passwd-{interface}' + +            self.cli_set(base_path + [interface, 'authentication', 'user', user])              self.cli_set(base_path + [interface, 'source-interface', self._source_interface])              self.cli_set(base_path + [interface, 'ipv6', 'address', 'autoconf']) @@ -125,7 +131,7 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):              with self.assertRaises(ConfigSessionError):                  self.cli_commit() -            self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos']) +            self.cli_set(base_path + [interface, 'authentication', 'password', passwd])          self.cli_commit() @@ -136,8 +142,11 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):          sla_len = '8'          for interface in self._interfaces: -            self.cli_set(base_path + [interface, 'authentication', 'user', 'vyos']) -            self.cli_set(base_path + [interface, 'authentication', 'password', 'vyos']) +            user = f'VyOS-user-{interface}' +            passwd = f'VyOS-passwd-{interface}' + +            self.cli_set(base_path + [interface, 'authentication', 'user', user]) +            self.cli_set(base_path + [interface, 'authentication', 'password', passwd])              self.cli_set(base_path + [interface, 'no-default-route'])              self.cli_set(base_path + [interface, 'no-peer-dns'])              self.cli_set(base_path + [interface, 'source-interface', self._source_interface]) @@ -149,18 +158,54 @@ class PPPoEInterfaceTest(VyOSUnitTestSHIM.TestCase):              self.cli_set(dhcpv6_pd_base + ['interface', self._source_interface, 'address', address])              self.cli_set(dhcpv6_pd_base + ['interface', self._source_interface, 'sla-id',  sla_id]) -            # commit changes -            self.cli_commit() +        # commit changes +        self.cli_commit() + +        for interface in self._interfaces: +            user = f'VyOS-user-{interface}' +            passwd = f'VyOS-passwd-{interface}'              # verify "normal" PPPoE value - 1492 is default MTU              tmp = get_config_value(interface, 'mtu')[1]              self.assertEqual(tmp, '1492')              tmp = get_config_value(interface, 'user')[1].replace('"', '') -            self.assertEqual(tmp, 'vyos') +            self.assertEqual(tmp, user)              tmp = get_config_value(interface, 'password')[1].replace('"', '') -            self.assertEqual(tmp, 'vyos') +            self.assertEqual(tmp, passwd)              tmp = get_config_value(interface, '+ipv6 ipv6cp-use-ipaddr')              self.assertListEqual(tmp, ['+ipv6', 'ipv6cp-use-ipaddr']) +    def test_05_pppoe_options(self): +        # Check if PPPoE dialer can be configured with DHCPv6-PD +        for interface in self._interfaces: +            user = f'VyOS-user-{interface}' +            passwd = f'VyOS-passwd-{interface}' +            ac_name = f'AC{interface}' +            service_name = f'SRV{interface}' +            host_uniq = 'cafebeefBABE123456' + +            self.cli_set(base_path + [interface, 'authentication', 'user', user]) +            self.cli_set(base_path + [interface, 'authentication', 'password', passwd]) +            self.cli_set(base_path + [interface, 'source-interface', self._source_interface]) + +            self.cli_set(base_path + [interface, 'access-concentrator', ac_name]) +            self.cli_set(base_path + [interface, 'service-name', service_name]) +            self.cli_set(base_path + [interface, 'host-uniq', host_uniq]) + +        # commit changes +        self.cli_commit() + +        for interface in self._interfaces: +            ac_name = f'AC{interface}' +            service_name = f'SRV{interface}' +            host_uniq = 'cafebeefBABE123456' + +            tmp = get_config_value(interface, 'pppoe-ac')[1] +            self.assertEqual(tmp, f'"{ac_name}"') +            tmp = get_config_value(interface, 'pppoe-service')[1] +            self.assertEqual(tmp, f'"{service_name}"') +            tmp = get_config_value(interface, 'pppoe-host-uniq')[1] +            self.assertEqual(tmp, f'"{host_uniq}"') +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_service_ntp.py b/smoketest/scripts/cli/test_service_ntp.py index d4793adb6..3ccd19a31 100755 --- a/smoketest/scripts/cli/test_service_ntp.py +++ b/smoketest/scripts/cli/test_service_ntp.py @@ -135,6 +135,10 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):          self.cli_commit() +        # Check for process in VRF +        tmp = cmd(f'ip vrf pids {vrf_name}') +        self.assertIn(PROCESS_NAME, tmp) +          self.cli_delete(['vrf', 'name', vrf_name])  if __name__ == '__main__': diff --git a/smoketest/scripts/cli/test_service_snmp.py b/smoketest/scripts/cli/test_service_snmp.py index e80c689cc..b18b9e7a1 100755 --- a/smoketest/scripts/cli/test_service_snmp.py +++ b/smoketest/scripts/cli/test_service_snmp.py @@ -123,6 +123,28 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase):          self.assertTrue(process_named_running(PROCESS_NAME))          self.cli_delete(['interfaces', 'dummy', dummy_if]) +        ## Check communities and default view RESTRICTED +        for auth in ['ro', 'rw']: +            community = 'VyOS' + auth +            for addr in clients: +                if is_ipv4(addr): +                    entry = auth + 'community ' + community + ' ' + addr + ' -V' +                else: +                    entry = auth + 'community6 ' + community + ' ' + addr + ' -V' +                config = get_config_value(entry) +                expected = 'RESTRICTED' +                self.assertIn(expected, config) +            for addr in networks: +                if is_ipv4(addr): +                    entry = auth + 'community ' + community + ' ' + addr + ' -V' +                else: +                    entry = auth + 'community6 ' + community + ' ' + addr + ' -V' +                config = get_config_value(entry) +                expected = 'RESTRICTED' +                self.assertIn(expected, config) +        # And finally check global entry for RESTRICTED view +        config = get_config_value('view RESTRICTED    included .1') +        self.assertIn('80', config)      def test_snmpv3_sha(self):          # Check if SNMPv3 can be configured with SHA authentication diff --git a/smoketest/scripts/cli/test_service_tftp-server.py b/smoketest/scripts/cli/test_service_tftp-server.py index b57c33f26..99d81e203 100755 --- a/smoketest/scripts/cli/test_service_tftp-server.py +++ b/smoketest/scripts/cli/test_service_tftp-server.py @@ -33,15 +33,32 @@ address_ipv6 = '2001:db8::1'  vrf = 'mgmt'  class TestServiceTFTPD(VyOSUnitTestSHIM.TestCase): -    def setUp(self): -        self.cli_set(dummy_if_path + ['address', address_ipv4 + '/32']) -        self.cli_set(dummy_if_path + ['address', address_ipv6 + '/128']) +    @classmethod +    def setUpClass(cls): +        super(TestServiceTFTPD, cls).setUpClass() + +        # ensure we can also run this test on a live system - so lets clean +        # out the current configuration :) +        cls.cli_delete(cls, base_path) + +        cls.cli_set(cls, dummy_if_path + ['address', address_ipv4 + '/32']) +        cls.cli_set(cls, dummy_if_path + ['address', address_ipv6 + '/128']) + +    @classmethod +    def tearDownClass(cls): +        cls.cli_delete(cls, dummy_if_path) +        super(TestServiceTFTPD, cls).tearDownClass()      def tearDown(self): +        # Check for running process +        self.assertTrue(process_named_running(PROCESS_NAME)) +          self.cli_delete(base_path) -        self.cli_delete(dummy_if_path)          self.cli_commit() +        # Check for no longer running process +        self.assertFalse(process_named_running(PROCESS_NAME)) +      def test_01_tftpd_single(self):          directory = '/tmp'          port = '69' # default port @@ -61,9 +78,6 @@ class TestServiceTFTPD(VyOSUnitTestSHIM.TestCase):          # verify upload          self.assertIn('--create --umask 000', config) -        # Check for running process -        self.assertTrue(process_named_running(PROCESS_NAME)) -      def test_02_tftpd_multi(self):          directory = '/tmp'          address = [address_ipv4, address_ipv6] @@ -125,9 +139,6 @@ class TestServiceTFTPD(VyOSUnitTestSHIM.TestCase):          # verify upload          self.assertIn('--create --umask 000', config) -        # Check for running process -        self.assertTrue(process_named_running(PROCESS_NAME)) -          # Check for process in VRF          tmp = cmd(f'ip vrf pids {vrf}')          self.assertIn(PROCESS_NAME, tmp) diff --git a/smoketest/scripts/cli/test_vpn_ipsec.py b/smoketest/scripts/cli/test_vpn_ipsec.py index 92b377e59..c8634dd57 100755 --- a/smoketest/scripts/cli/test_vpn_ipsec.py +++ b/smoketest/scripts/cli/test_vpn_ipsec.py @@ -359,6 +359,7 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):          self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'dh-group', '2'])          self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'encryption', 'aes256'])          self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'hash', 'sha1']) +        self.cli_set(base_path + ['ike-group', ike_group, 'proposal', '2', 'prf', 'prfsha1'])          # Profile          self.cli_set(base_path + ['profile', 'NHRPVPN', 'authentication', 'mode', 'pre-shared-secret']) @@ -371,7 +372,7 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):          swanctl_conf = read_file(swanctl_file)          swanctl_lines = [ -            f'proposals = aes128-sha1-modp1024,aes256-sha1-modp1024', +            f'proposals = aes128-sha1-modp1024,aes256-sha1-prfsha1-modp1024',              f'version = 1',              f'rekey_time = {ike_lifetime}s',              f'rekey_time = {esp_lifetime}s', diff --git a/smoketest/scripts/cli/test_vpn_openconnect.py b/smoketest/scripts/cli/test_vpn_openconnect.py index 8572d6d66..ec8ecacb9 100755 --- a/smoketest/scripts/cli/test_vpn_openconnect.py +++ b/smoketest/scripts/cli/test_vpn_openconnect.py @@ -18,6 +18,7 @@ import unittest  from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.template import ip_from_cidr  from vyos.util import process_named_running  from vyos.util import read_file @@ -52,6 +53,9 @@ config_file = '/run/ocserv/ocserv.conf'  auth_file = '/run/ocserv/ocpasswd'  otp_file = '/run/ocserv/users.oath' +listen_if = 'dum116' +listen_address = '100.64.0.1/32' +  class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):      @classmethod      def setUpClass(cls): @@ -61,6 +65,8 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):          # out the current configuration :)          cls.cli_delete(cls, base_path) +        cls.cli_set(cls, ['interfaces', 'dummy', listen_if, 'address', listen_address]) +          cls.cli_set(cls, pki_path + ['ca', 'openconnect', 'certificate', cert_data.replace('\n','')])          cls.cli_set(cls, pki_path + ['certificate', 'openconnect', 'certificate', cert_data.replace('\n','')])          cls.cli_set(cls, pki_path + ['certificate', 'openconnect', 'private', 'key', key_data.replace('\n','')]) @@ -68,6 +74,7 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):      @classmethod      def tearDownClass(cls):          cls.cli_delete(cls, pki_path) +        cls.cli_delete(cls, ['interfaces', 'dummy', listen_if])          super(TestVPNOpenConnect, cls).tearDownClass()      def tearDown(self): @@ -104,6 +111,9 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):          self.cli_set(base_path + ['ssl', 'ca-certificate', 'openconnect'])          self.cli_set(base_path + ['ssl', 'certificate', 'openconnect']) +        listen_ip_no_cidr = ip_from_cidr(listen_address) +        self.cli_set(base_path + ['listen-address', listen_ip_no_cidr]) +          self.cli_commit()          # Verify configuration @@ -111,10 +121,15 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase):          # authentication mode local password-otp          self.assertIn(f'auth = "plain[passwd=/run/ocserv/ocpasswd,otp=/run/ocserv/users.oath]"', daemon_config) +        self.assertIn(f'listen-host = {listen_ip_no_cidr}', daemon_config)          self.assertIn(f'ipv4-network = {v4_subnet}', daemon_config)          self.assertIn(f'ipv6-network = {v6_prefix}', daemon_config)          self.assertIn(f'ipv6-subnet-prefix = {v6_len}', daemon_config) +        # defaults +        self.assertIn(f'tcp-port = 443', daemon_config) +        self.assertIn(f'udp-port = 443', daemon_config) +          for ns in name_server:              self.assertIn(f'dns = {ns}', daemon_config)          for domain in split_dns: diff --git a/smoketest/scripts/system/test_module_load.py b/smoketest/scripts/system/test_module_load.py index 76a41ac4d..bd30c57ec 100755 --- a/smoketest/scripts/system/test_module_load.py +++ b/smoketest/scripts/system/test_module_load.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# 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 @@ -23,8 +23,7 @@ modules = {      "intel_qat": ["qat_200xx", "qat_200xxvf", "qat_c3xxx", "qat_c3xxxvf",                    "qat_c62x", "qat_c62xvf", "qat_d15xx", "qat_d15xxvf",                    "qat_dh895xcc", "qat_dh895xccvf"], -    "accel_ppp": ["ipoe", "vlan_mon"], -    "misc": ["wireguard"] +    "accel_ppp": ["ipoe", "vlan_mon"]  }  class TestKernelModules(unittest.TestCase): diff --git a/src/conf_mode/config_mgmt.py b/src/conf_mode/config_mgmt.py new file mode 100755 index 000000000..c681a8405 --- /dev/null +++ b/src/conf_mode/config_mgmt.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# +# 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/>. + +import os +import sys + +from vyos import ConfigError +from vyos.config import Config +from vyos.config_mgmt import ConfigMgmt +from vyos.config_mgmt import commit_post_hook_dir, commit_hooks + +def get_config(config=None): +    if config: +        conf = config +    else: +        conf = Config() + +    base = ['system', 'config-management'] +    if not conf.exists(base): +        return None + +    mgmt = ConfigMgmt(config=conf) + +    return mgmt + +def verify(_mgmt): +    return + +def generate(mgmt): +    if mgmt is None: +        return + +    mgmt.initialize_revision() + +def apply(mgmt): +    if mgmt is None: +        return + +    locations = mgmt.locations +    archive_target = os.path.join(commit_post_hook_dir, +                               commit_hooks['commit_archive']) +    if locations: +        try: +            os.symlink('/usr/bin/config-mgmt', archive_target) +        except FileExistsError: +            pass +        except OSError as exc: +            raise ConfigError from exc +    else: +        try: +            os.unlink(archive_target) +        except FileNotFoundError: +            pass +        except OSError as exc: +            raise ConfigError from exc + +    revisions = mgmt.max_revisions +    revision_target = os.path.join(commit_post_hook_dir, +                               commit_hooks['commit_revision']) +    if revisions > 0: +        try: +            os.symlink('/usr/bin/config-mgmt', revision_target) +        except FileExistsError: +            pass +        except OSError as exc: +            raise ConfigError from exc +    else: +        try: +            os.unlink(revision_target) +        except FileNotFoundError: +            pass +        except OSError as exc: +            raise ConfigError from exc + +if __name__ == '__main__': +    try: +        c = get_config() +        verify(c) +        generate(c) +        apply(c) +    except ConfigError as e: +        print(e) +        sys.exit(1) diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py index 7567444db..08861053d 100755 --- a/src/conf_mode/container.py +++ b/src/conf_mode/container.py @@ -75,6 +75,8 @@ def get_config(config=None):          default_values = defaults(base + ['name'])          if 'port' in default_values:              del default_values['port'] +        if 'volume' in default_values: +            del default_values['volume']          for name in container['name']:              container['name'][name] = dict_merge(default_values, container['name'][name]) @@ -85,6 +87,13 @@ def get_config(config=None):                      default_values = defaults(base + ['name', 'port'])                      container['name'][name]['port'][port] = dict_merge(                          default_values, container['name'][name]['port'][port]) +            # XXX: T2665: we can not safely rely on the defaults() when there are +            # tagNodes in place, it is better to blend in the defaults manually. +            if 'volume' in container['name'][name]: +                for volume in container['name'][name]['volume']: +                    default_values = defaults(base + ['name', 'volume']) +                    container['name'][name]['volume'][volume] = dict_merge( +                        default_values, container['name'][name]['volume'][volume])      # Delete container network, delete containers      tmp = node_changed(conf, base + ['network']) @@ -245,7 +254,7 @@ def generate_run_arguments(name, container_config):      env_opt = ''      if 'environment' in container_config:          for k, v in container_config['environment'].items(): -            env_opt += f" -e \"{k}={v['value']}\"" +            env_opt += f" --env \"{k}={v['value']}\""      # Publish ports      port = '' @@ -255,7 +264,7 @@ def generate_run_arguments(name, container_config):              protocol = container_config['port'][portmap]['protocol']              sport = container_config['port'][portmap]['source']              dport = container_config['port'][portmap]['destination'] -            port += f' -p {sport}:{dport}/{protocol}' +            port += f' --publish {sport}:{dport}/{protocol}'      # Bind volume      volume = '' @@ -263,7 +272,8 @@ def generate_run_arguments(name, container_config):          for vol, vol_config in container_config['volume'].items():              svol = vol_config['source']              dvol = vol_config['destination'] -            volume += f' -v {svol}:{dvol}' +            mode = vol_config['mode'] +            volume += f' --volume {svol}:{dvol}:{mode}'      container_base_cmd = f'--detach --interactive --tty --replace {cap_add} ' \                           f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} ' \ diff --git a/src/conf_mode/high-availability.py b/src/conf_mode/high-availability.py index 4ed16d0d7..79e407efd 100755 --- a/src/conf_mode/high-availability.py +++ b/src/conf_mode/high-availability.py @@ -28,6 +28,7 @@ from vyos.template import render  from vyos.template import is_ipv4  from vyos.template import is_ipv6  from vyos.util import call +from vyos.util import dict_search  from vyos.xml import defaults  from vyos import ConfigError  from vyos import airbag @@ -49,10 +50,27 @@ def get_config(config=None):      # We have gathered the dict representation of the CLI, but there are default      # options which we need to update into the dictionary retrived.      if 'vrrp' in ha: +        if dict_search('vrrp.global_parameters.garp', ha) != None: +            default_values = defaults(base_vrrp + ['global-parameters', 'garp']) +            ha['vrrp']['global_parameters']['garp'] = dict_merge( +                default_values, ha['vrrp']['global_parameters']['garp']) +          if 'group' in ha['vrrp']: -            default_values_vrrp = defaults(base_vrrp + ['group']) +            default_values = defaults(base_vrrp + ['group']) +            default_values_garp = defaults(base_vrrp + ['group', 'garp']) + +            # XXX: T2665: we can not safely rely on the defaults() when there are +            # tagNodes in place, it is better to blend in the defaults manually. +            if 'garp' in default_values: +                del default_values['garp']              for group in ha['vrrp']['group']: -                ha['vrrp']['group'][group] = dict_merge(default_values_vrrp, ha['vrrp']['group'][group]) +                ha['vrrp']['group'][group] = dict_merge(default_values, ha['vrrp']['group'][group]) + +                # XXX: T2665: we can not safely rely on the defaults() when there are +                # tagNodes in place, it is better to blend in the defaults manually. +                if 'garp' in ha['vrrp']['group'][group]: +                    ha['vrrp']['group'][group]['garp'] = dict_merge( +                        default_values_garp, ha['vrrp']['group'][group]['garp'])      # Merge per virtual-server default values      if 'virtual_server' in ha: diff --git a/src/conf_mode/interfaces-input.py b/src/conf_mode/interfaces-input.py new file mode 100755 index 000000000..ad248843d --- /dev/null +++ b/src/conf_mode/interfaces-input.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# +# 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/>. + +from sys import exit + +from vyos.config import Config +from vyos.configdict import get_interface_dict +from vyos.configverify import verify_mirror_redirect +from vyos.ifconfig import InputIf +from vyos import ConfigError +from vyos import airbag +airbag.enable() + +def get_config(config=None): +    """ +    Retrive CLI config as dictionary. Dictionary can never be empty, as at +    least the interface name will be added or a deleted flag +    """ +    if config: +        conf = config +    else: +        conf = Config() +    base = ['interfaces', 'input'] +    _, ifb = get_interface_dict(conf, base) + +    return ifb + +def verify(ifb): +    if 'deleted' in ifb: +        return None + +    verify_mirror_redirect(ifb) +    return None + +def generate(ifb): +    return None + +def apply(ifb): +    d = InputIf(ifb['ifname']) + +    # Remove input interface +    if 'deleted' in ifb: +        d.remove() +    else: +        d.update(ifb) + +    return None + +if __name__ == '__main__': +    try: +        c = get_config() +        verify(c) +        generate(c) +        apply(c) +    except ConfigError as e: +        print(e) +        exit(1) diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py index ee4defa0d..5f0b76f90 100755 --- a/src/conf_mode/interfaces-pppoe.py +++ b/src/conf_mode/interfaces-pppoe.py @@ -54,7 +54,8 @@ def get_config(config=None):      # All parameters that can be changed on-the-fly (like interface description)      # should not lead to a reconnect!      for options in ['access-concentrator', 'connect-on-demand', 'service-name', -                    'source-interface', 'vrf', 'no-default-route', 'authentication']: +                    'source-interface', 'vrf', 'no-default-route', +                    'authentication', 'host_uniq']:          if is_node_changed(conf, base + [ifname, options]):              pppoe.update({'shutdown_required': {}})              # bail out early - no need to further process other nodes diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py index 914ec245c..ab2ccf99e 100755 --- a/src/conf_mode/snmp.py +++ b/src/conf_mode/snmp.py @@ -166,6 +166,10 @@ def verify(snmp):              if 'community' not in trap_config:                  raise ConfigError(f'Trap target "{trap}" requires a community to be set!') +    if 'oid_enable' in snmp: +        Warning(f'Custom OIDs are enabled and may lead to system instability and high resource consumption') + +      verify_vrf(snmp)      # bail out early if SNMP v3 is not configured diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py index af3c51efc..63ffe2a41 100755 --- a/src/conf_mode/vpn_openconnect.py +++ b/src/conf_mode/vpn_openconnect.py @@ -46,6 +46,65 @@ radius_servers = cfg_dir + '/radius_servers'  def get_hash(password):      return crypt(password, mksalt(METHOD_SHA512)) + +def T2665_default_dict_cleanup(origin: dict, default_values: dict) -> dict: +    """ +    https://phabricator.vyos.net/T2665 +    Clear unnecessary key values in merged config by dict_merge function +    :param origin: config +    :type origin: dict +    :param default_values: default values +    :type default_values: dict +    :return: merged dict +    :rtype: dict +    """ +    if 'mode' in origin["authentication"] and "local" in \ +            origin["authentication"]["mode"]: +        del origin['authentication']['local_users']['username']['otp'] +        if not origin["authentication"]["local_users"]["username"]: +            raise ConfigError( +                'Openconnect mode local required at least one user') +        default_ocserv_usr_values = \ +        default_values['authentication']['local_users']['username']['otp'] +        for user, params in origin['authentication']['local_users'][ +            'username'].items(): +            # Not every configuration requires OTP settings +            if origin['authentication']['local_users']['username'][user].get( +                    'otp'): +                origin['authentication']['local_users']['username'][user][ +                    'otp'] = dict_merge(default_ocserv_usr_values, +                                        origin['authentication'][ +                                            'local_users']['username'][user][ +                                            'otp']) + +    if 'mode' in origin["authentication"] and "radius" in \ +            origin["authentication"]["mode"]: +        del origin['authentication']['radius']['server']['port'] +        if not origin["authentication"]['radius']['server']: +            raise ConfigError( +                'Openconnect authentication mode radius required at least one radius server') +        default_values_radius_port = \ +        default_values['authentication']['radius']['server']['port'] +        for server, params in origin['authentication']['radius'][ +            'server'].items(): +            if 'port' not in params: +                params['port'] = default_values_radius_port + +    if 'mode' in origin["accounting"] and "radius" in \ +            origin["accounting"]["mode"]: +        del origin['accounting']['radius']['server']['port'] +        if not origin["accounting"]['radius']['server']: +            raise ConfigError( +                'Openconnect accounting mode radius required at least one radius server') +        default_values_radius_port = \ +            default_values['accounting']['radius']['server']['port'] +        for server, params in origin['accounting']['radius'][ +            'server'].items(): +            if 'port' not in params: +                params['port'] = default_values_radius_port +    return origin + +  def get_config():      conf = Config()      base = ['vpn', 'openconnect'] @@ -57,18 +116,8 @@ def get_config():      # options which we need to update into the dictionary retrived.      default_values = defaults(base)      ocserv = dict_merge(default_values, ocserv) - -    if 'mode' in ocserv["authentication"] and "local" in ocserv["authentication"]["mode"]: -        # workaround a "know limitation" - https://phabricator.vyos.net/T2665 -        del ocserv['authentication']['local_users']['username']['otp'] -        if not ocserv["authentication"]["local_users"]["username"]: -            raise ConfigError('openconnect mode local required at least one user') -        default_ocserv_usr_values = default_values['authentication']['local_users']['username']['otp'] -        for user, params in ocserv['authentication']['local_users']['username'].items(): -            # Not every configuration requires OTP settings -            if ocserv['authentication']['local_users']['username'][user].get('otp'): -                ocserv['authentication']['local_users']['username'][user]['otp'] = dict_merge(default_ocserv_usr_values, ocserv['authentication']['local_users']['username'][user]['otp']) - +    # workaround a "know limitation" - https://phabricator.vyos.net/T2665 +    ocserv = T2665_default_dict_cleanup(ocserv, default_values)      if ocserv:          ocserv['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),                                  get_first_key=True, no_tag_node_value_mangle=True) @@ -85,6 +134,14 @@ def verify(ocserv):                  not is_listen_port_bind_service(int(port), 'ocserv-main'):              raise ConfigError(f'"{proto}" port "{port}" is used by another service') +    # Check accounting +    if "accounting" in ocserv: +        if "mode" in ocserv["accounting"] and "radius" in ocserv["accounting"]["mode"]: +            if "authentication" not in ocserv or "mode" not in ocserv["authentication"]: +                raise ConfigError('Accounting depends on OpenConnect authentication configuration') +            elif "radius" not in ocserv["authentication"]["mode"]: +                raise ConfigError('RADIUS accounting must be used with RADIUS authentication') +      # Check authentication      if "authentication" in ocserv:          if "mode" in ocserv["authentication"]: @@ -166,10 +223,18 @@ def generate(ocserv):          return None      if "radius" in ocserv["authentication"]["mode"]: -        # Render radius client configuration -        render(radius_cfg, 'ocserv/radius_conf.j2', ocserv["authentication"]["radius"]) -        # Render radius servers -        render(radius_servers, 'ocserv/radius_servers.j2', ocserv["authentication"]["radius"]) +        if dict_search(ocserv, 'accounting.mode.radius'): +            # Render radius client configuration +            render(radius_cfg, 'ocserv/radius_conf.j2', ocserv) +            merged_servers = ocserv["accounting"]["radius"]["server"] | ocserv["authentication"]["radius"]["server"] +            # Render radius servers +            # Merge the accounting and authentication servers into a single dictionary +            render(radius_servers, 'ocserv/radius_servers.j2', {'server': merged_servers}) +        else: +            # Render radius client configuration +            render(radius_cfg, 'ocserv/radius_conf.j2', ocserv) +            # Render radius servers +            render(radius_servers, 'ocserv/radius_servers.j2', ocserv["authentication"]["radius"])      elif "local" in ocserv["authentication"]["mode"]:          # if mode "OTP", generate OTP users file parameters          if "otp" in ocserv["authentication"]["mode"]["local"]: diff --git a/src/etc/modprobe.d/ifb.conf b/src/etc/modprobe.d/ifb.conf new file mode 100644 index 000000000..2dcfb6af4 --- /dev/null +++ b/src/etc/modprobe.d/ifb.conf @@ -0,0 +1 @@ +options ifb numifbs=0 diff --git a/src/etc/sysctl.d/30-vyos-router.conf b/src/etc/sysctl.d/30-vyos-router.conf index 411429510..4880605d6 100644 --- a/src/etc/sysctl.d/30-vyos-router.conf +++ b/src/etc/sysctl.d/30-vyos-router.conf @@ -98,9 +98,6 @@ net.ipv6.route.skip_notify_on_dev_down=1  # Default value of 20 seems to interfere with larger OSPF and VRRP setups  net.ipv4.igmp_max_memberships = 512 -# Enable conntrack helper by default -net.netfilter.nf_conntrack_helper=1 -  # Increase default garbage collection thresholds  net.ipv4.neigh.default.gc_thresh1 = 1024  net.ipv4.neigh.default.gc_thresh2 = 4096 diff --git a/src/migration-scripts/ntp/1-to-2 b/src/migration-scripts/ntp/1-to-2 index 4a701e7e5..d1e510e4c 100755 --- a/src/migration-scripts/ntp/1-to-2 +++ b/src/migration-scripts/ntp/1-to-2 @@ -37,6 +37,11 @@ if not config.exists(base_path):      # Nothing to do      sys.exit(0) +# config.copy does not recursively create a path, so create ['service'] if +# it doesn't yet exist, such as for config.boot.default +if not config.exists(['service']): +    config.set(['service']) +  # copy "system ntp" to "service ntp"  config.copy(base_path, new_base_path)  config.delete(base_path) diff --git a/src/migration-scripts/snmp/2-to-3 b/src/migration-scripts/snmp/2-to-3 new file mode 100755 index 000000000..5f8d9c88d --- /dev/null +++ b/src/migration-scripts/snmp/2-to-3 @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# +# 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/>. + +# T4857: Implement FRR SNMP recomendations +#  cli changes from: +#  set service snmp oid-enable route-table +#  To +#  set service snmp oid-enable ip-forward + +import re + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree +from vyos.ifconfig import Section + +if (len(argv) < 1): +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +base = ['service snmp'] +config = ConfigTree(config_file) + +if not config.exists(base): +    # Nothing to do +    exit(0) + +if config.exists(base + ['oid-enable']): +    config.delete(base + ['oid-enable']) +    config.set(base + ['oid-enable'], 'ip-forward') + + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print("Failed to save the modified config: {}".format(e)) +    exit(1) diff --git a/src/op_mode/config_mgmt.py b/src/op_mode/config_mgmt.py new file mode 100755 index 000000000..66de26d1f --- /dev/null +++ b/src/op_mode/config_mgmt.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# +# 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/>. + +import sys +import typing + +import vyos.opmode +from vyos.config_mgmt import ConfigMgmt + +def show_commit_diff(raw: bool, rev: int, rev2: typing.Optional[int], +                     commands: bool): +    config_mgmt = ConfigMgmt() +    config_diff = config_mgmt.show_commit_diff(rev, rev2, commands) + +    if raw: +        rev2 = (rev+1) if rev2 is None else rev2 +        if commands: +            d = {f'config_command_diff_{rev2}_{rev}': config_diff} +        else: +            d = {f'config_file_diff_{rev2}_{rev}': config_diff} +        return d + +    return config_diff + +def show_commit_file(raw: bool, rev: int): +    config_mgmt = ConfigMgmt() +    config_file = config_mgmt.show_commit_file(rev) + +    if raw: +        d = {f'config_revision_{rev}': config_file} +        return d + +    return config_file + +def show_commit_log(raw: bool): +    config_mgmt = ConfigMgmt() + +    msg = '' +    if config_mgmt.max_revisions == 0: +        msg = ('commit-revisions is not configured;\n' +               'commit log is empty or stale:\n\n') + +    data = config_mgmt.get_raw_log_data() +    if raw: +        return data + +    out = config_mgmt.format_log_data(data) +    out = msg + out + +    return out + +def show_commit_log_brief(raw: bool): +    # used internally for completion help for 'rollback' +    # option 'raw' will return same as 'show_commit_log' +    config_mgmt = ConfigMgmt() + +    data = config_mgmt.get_raw_log_data() +    if raw: +        return data + +    out = config_mgmt.format_log_data_brief(data) + +    return out + +if __name__ == '__main__': +    try: +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res) +    except (ValueError, vyos.opmode.Error) as e: +        print(e) +        sys.exit(1) diff --git a/src/op_mode/generate_interfaces_debug_archive.py b/src/op_mode/generate_interfaces_debug_archive.py new file mode 100755 index 000000000..f5767080a --- /dev/null +++ b/src/op_mode/generate_interfaces_debug_archive.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# +# 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/>. + +from datetime import datetime +from pathlib import Path +from shutil import rmtree +from socket import gethostname +from sys import exit +from tarfile import open as tar_open +from vyos.util import rc_cmd +import os + +# define a list of commands that needs to be executed + +CMD_LIST: list[str] = [ +    "journalctl -b -n 500", +    "journalctl -b -k -n 500", +    "ip -s l", +    "cat /proc/interrupts", +    "cat /proc/softirqs", +    "top -b -d 1 -n 2 -1", +    "netstat -l",              +    "cat /proc/net/dev", +    "cat /proc/net/softnet_stat", +    "cat /proc/net/icmp", +    "cat /proc/net/udp", +    "cat /proc/net/tcp", +    "cat /proc/net/netstat", +    "sysctl net", +    "timeout 10 tcpdump -c 500 -eni any port not 22" +] + +CMD_INTERFACES_LIST: list[str] = [ +    "ethtool -i ", +    "ethtool -S ", +    "ethtool -g ", +    "ethtool -c ", +    "ethtool -a ", +    "ethtool -k ", +    "ethtool -i ", +    "ethtool --phy-statistics " +] + +# get intefaces info +interfaces_list = os.popen('ls /sys/class/net/').read().split() + +# modify CMD_INTERFACES_LIST for all interfaces +CMD_INTERFACES_LIST_MOD=[] +for command_interface in interfaces_list: +    for command_interfacev2 in CMD_INTERFACES_LIST: +        CMD_INTERFACES_LIST_MOD.append (f'{command_interfacev2}{command_interface}') + +# execute a command and save the output to a file + +def save_stdout(command: str, file: Path) -> None: +    rc, stdout = rc_cmd(command) +    body: str = f'''### {command} ### +Command: {command} +Exit code: {rc} +Stdout: +{stdout} + +''' +    with file.open(mode='a') as f: +        f.write(body) + +# get local host name +hostname: str = gethostname() +# get current time +time_now: str = datetime.now().isoformat(timespec='seconds') + +# define a temporary directory for logs and collected data +tmp_dir: Path = Path(f'/tmp/drops-debug_{time_now}') +# set file paths +drops_file: Path = Path(f'{tmp_dir}/drops.txt') +interfaces_file: Path = Path(f'{tmp_dir}/interfaces.txt') +archive_file: str = f'/tmp/packet-drops-debug_{time_now}.tar.bz2' + +# create files +tmp_dir.mkdir() +drops_file.touch() +interfaces_file.touch() + +try: +    # execute all commands +    for command in CMD_LIST: +        save_stdout(command, drops_file) +    for command_interface in CMD_INTERFACES_LIST_MOD: +        save_stdout(command_interface, interfaces_file) + +    # create an archive +    with tar_open(name=archive_file, mode='x:bz2') as tar_file: +        tar_file.add(tmp_dir) + +    # inform user about success +    print(f'Debug file is generated and located in {archive_file}') +except Exception as err: +    print(f'Error during generating a debug file: {err}') +finally: +    # cleanup +    rmtree(tmp_dir) +    exit() diff --git a/src/op_mode/igmp-proxy.py b/src/op_mode/igmp-proxy.py new file mode 100755 index 000000000..0086c9aa6 --- /dev/null +++ b/src/op_mode/igmp-proxy.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# +# 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/>. + +# File: show_igmpproxy.py +# Purpose: +#    Display istatistics from IPv4 IGMP proxy. +#    Used by the "run show ip multicast" command tree. + +import ipaddress +import json +import socket +import sys +import tabulate + +import vyos.config +import vyos.opmode + +from vyos.util import bytes_to_human, print_error + +def _is_configured(): +    """Check if IGMP proxy is configured""" +    return vyos.config.Config().exists_effective('protocols igmp-proxy') + +def _is_running(): +    """Check if IGMP proxy is currently running""" +    return not vyos.util.run('ps -C igmpproxy') + +def _kernel_to_ip(addr): +    """ +    Convert any given address from Linux kernel to a proper, IPv4 address +    using the correct host byte order. +    """ +    # Convert from hex 'FE000A0A' to decimal '4261415434' +    addr = int(addr, 16) +    # Kernel ABI _always_ uses network byte order. +    addr = socket.ntohl(addr) +    return str(ipaddress.IPv4Address(addr)) + +def _process_mr_vif(): +    """Read rows from /proc/net/ip_mr_vif into dicts.""" +    result = [] +    with open('/proc/net/ip_mr_vif', 'r') as f: +        next(f) +        for line in f: +            result.append({ +                'Interface': line.split()[1], +                'PktsIn'   : int(line.split()[3]), +                'PktsOut'  : int(line.split()[5]), +                'BytesIn'  : int(line.split()[2]), +                'BytesOut' : int(line.split()[4]), +                'Local'    : _kernel_to_ip(line.split()[7]), +            }) +    return result + +def show_interface(raw: bool): +    if data := _process_mr_vif(): +        if raw: +            # Make the interface name the key for each row. +            table = {} +            for v in data: +                table[v.pop('Interface')] = v +            return json.loads(json.dumps(table)) +        # Make byte values human-readable for the table. +        arr = [] +        for x in data: +            arr.append({k: bytes_to_human(v) if k.startswith('Bytes') \ +                        else v for k, v in x.items()}) +        return tabulate.tabulate(arr, headers='keys') + + +if not _is_configured(): +    print_error('IGMP proxy is not configured.') +    sys.exit(0) +if not _is_running(): +    print_error('IGMP proxy is not running.') +    sys.exit(0) + + +if __name__ == "__main__": +    try: +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res) +    except (ValueError, vyos.opmode.Error) as e: +        print_error(e) +        sys.exit(1) diff --git a/src/op_mode/lldp.py b/src/op_mode/lldp.py index dc2b1e0b5..1a1b94783 100755 --- a/src/op_mode/lldp.py +++ b/src/op_mode/lldp.py @@ -61,7 +61,14 @@ def _get_raw_data(interface=None, detail=False):  def _get_formatted_output(raw_data):      data_entries = [] -    for neighbor in dict_search('lldp.interface', raw_data): +    tmp = dict_search('lldp.interface', raw_data) +    if not tmp: +        return None +    # One can not always ensure that "interface" is of type list, add safeguard. +    # E.G. Juniper Networks, Inc. ex2300-c-12t only has a dict, not a list of dicts +    if isinstance(tmp, dict): +        tmp = [tmp] +    for neighbor in tmp:          for local_if, values in neighbor.items():              tmp = [] @@ -80,6 +87,10 @@ def _get_formatted_output(raw_data):              # Capabilities              cap = ''              capabilities = jmespath.search('chassis.[*][0][0].capability', values) +            # One can not always ensure that "capability" is of type list, add +            # safeguard. E.G. Unify US-24-250W only has a dict, not a list of dicts +            if isinstance(capabilities, dict): +                capabilities = [capabilities]              if capabilities:                  for capability in capabilities:                      if capability['enabled']: diff --git a/src/op_mode/show_igmpproxy.py b/src/op_mode/show_igmpproxy.py deleted file mode 100755 index 4714e494b..000000000 --- a/src/op_mode/show_igmpproxy.py +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2018 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/>. - -# File: show_igmpproxy.py -# Purpose: -#    Display istatistics from IPv4 IGMP proxy. -#    Used by the "run show ip multicast" command tree. - -import sys -import jinja2 -import argparse -import ipaddress -import socket - -import vyos.config - -# Output Template for "show ip multicast interface" command -# -# Example: -# Interface  BytesIn      PktsIn       BytesOut     PktsOut      Local -# eth0       0.0b         0            0.0b         0            xxx.xxx.xxx.65 -# eth1       0.0b         0            0.0b         0            xxx.xxx.xx.201 -# eth0.3     0.0b         0            0.0b         0            xxx.xxx.x.7 -# tun1       0.0b         0            0.0b         0            xxx.xxx.xxx.2 -vif_out_tmpl = """ -{% for r in data %} -{{ "%-10s"|format(r.interface) }} {{ "%-12s"|format(r.bytes_in) }} {{ "%-12s"|format(r.pkts_in) }} {{ "%-12s"|format(r.bytes_out) }} {{ "%-12s"|format(r.pkts_out) }} {{ "%-15s"|format(r.loc) }} -{% endfor %} -""" - -# Output Template for "show ip multicast mfc" command -# -# Example: -# Group             Origin            In    Out           Pkts        Bytes        Wrong -# xxx.xxx.xxx.250   xxx.xx.xxx.75     -- -# xxx.xxx.xx.124    xx.xxx.xxx.26     -- -mfc_out_tmpl = """ -{% for r in data %} -{{ "%-15s"|format(r.group) }} {{ "%-15s"|format(r.origin) }} {{ "%-12s"|format(r.pkts) }} {{ "%-12s"|format(r.bytes) }} {{ "%-12s"|format(r.wrong) }} {{ "%-10s"|format(r.iif) }} {{ "%-20s"|format(r.oifs|join(', ')) }} -{% endfor %} -""" - -parser = argparse.ArgumentParser() -parser.add_argument("--interface", action="store_true", help="Interface Statistics") -parser.add_argument("--mfc", action="store_true", help="Multicast Forwarding Cache") - -def byte_string(size): -    # convert size to integer -    size = int(size) - -    # One Terrabyte -    s_TB = 1024 * 1024 * 1024 * 1024 -    # One Gigabyte -    s_GB = 1024 * 1024 * 1024 -    # One Megabyte -    s_MB = 1024 * 1024 -    # One Kilobyte -    s_KB = 1024 -    # One Byte -    s_B  = 1 - -    if size > s_TB: -        return str(round((size/s_TB), 2)) + 'TB' -    elif size > s_GB: -        return str(round((size/s_GB), 2)) + 'GB' -    elif size > s_MB: -        return str(round((size/s_MB), 2)) + 'MB' -    elif size > s_KB: -        return str(round((size/s_KB), 2)) + 'KB' -    else: -        return str(round((size/s_B), 2)) + 'b' - -    return None - -def kernel2ip(addr): -    """ -    Convert any given addr from Linux Kernel to a proper, IPv4 address -    using the correct host byte order. -    """ - -    # Convert from hex 'FE000A0A' to decimal '4261415434' -    addr = int(addr, 16) -    # Kernel ABI _always_ uses network byteorder -    addr = socket.ntohl(addr) - -    return ipaddress.IPv4Address( addr ) - -def do_mr_vif(): -    """ -    Read contents of file /proc/net/ip_mr_vif and print a more human -    friendly version to the command line. IPv4 addresses present as -    32bit integers in hex format are converted to IPv4 notation, too. -    """ - -    with open('/proc/net/ip_mr_vif', 'r') as f: -        lines = len(f.readlines()) -        if lines < 2: -            return None - -    result = { -        'data': [] -    } - -    # Build up table format string -    table_format = { -        'interface': 'Interface', -        'pkts_in'  : 'PktsIn', -        'pkts_out' : 'PktsOut', -        'bytes_in' : 'BytesIn', -        'bytes_out': 'BytesOut', -        'loc'      : 'Local' -    } -    result['data'].append(table_format) - -    # read and parse information from /proc filesystema -    with open('/proc/net/ip_mr_vif', 'r') as f: -        header_line = next(f) -        for line in f: -            data = { -                'interface': line.split()[1], -                'pkts_in'  : line.split()[3], -                'pkts_out' : line.split()[5], - -                # convert raw byte number to something more human readable -                # Note: could be replaced by Python3 hurry.filesize module -                'bytes_in' : byte_string( line.split()[2] ), -                'bytes_out': byte_string( line.split()[4] ), - -                # convert IP address from hex 'FE000A0A' to decimal '4261415434' -                'loc'      : kernel2ip( line.split()[7] ), -            } -            result['data'].append(data) - -    return result - -def do_mr_mfc(): -    """ -    Read contents of file /proc/net/ip_mr_cache and print a more human -    friendly version to the command line. IPv4 addresses present as -    32bit integers in hex format are converted to IPv4 notation, too. -    """ - -    with open('/proc/net/ip_mr_cache', 'r') as f: -        lines = len(f.readlines()) -        if lines < 2: -            return None - -    # We need this to convert from interface index to a real interface name -    # Thus we also skip the format identifier on list index 0 -    vif = do_mr_vif()['data'][1:] - -    result = { -        'data': [] -    } - -    # Build up table format string -    table_format = { -        'group' : 'Group', -        'origin': 'Origin', -        'iif'   : 'In', -        'oifs'  : ['Out'], -        'pkts'  : 'Pkts', -        'bytes' : 'Bytes', -        'wrong' : 'Wrong' -    } -    result['data'].append(table_format) - -    # read and parse information from /proc filesystem -    with open('/proc/net/ip_mr_cache', 'r') as f: -        header_line = next(f) -        for line in f: -            data = { -                # convert IP address from hex 'FE000A0A' to decimal '4261415434' -                'group' : kernel2ip( line.split()[0] ), -                'origin': kernel2ip( line.split()[1] ), - -                'iif'   : '--', -                'pkts'  : '', -                'bytes' : '', -                'wrong' : '', -                'oifs'  : [] -            } - -            iif = int( line.split()[2] ) -            if not ((iif == -1) or (iif == 65535)): -                data['pkts']  = line.split()[3] -                data['bytes'] = byte_string( line.split()[4] ) -                data['wrong'] = line.split()[5] - -                # convert index to real interface name -                data['iif']  = vif[iif]['interface'] - -                # convert each output interface index to a real interface name -                for oif in line.split()[6:]: -                    idx = int( oif.split(':')[0] ) -                    data['oifs'].append( vif[idx]['interface'] ) - -            result['data'].append(data) - -    return result - -if __name__ == '__main__': -    args = parser.parse_args() - -    # Do nothing if service is not configured -    c = vyos.config.Config() -    if not c.exists_effective('protocols igmp-proxy'): -        print("IGMP proxy is not configured") -        sys.exit(0) - -    if args.interface: -        data = do_mr_vif() -        if data: -            tmpl = jinja2.Template(vif_out_tmpl) -            print(tmpl.render(data)) - -        sys.exit(0) -    elif args.mfc: -        data = do_mr_mfc() -        if data: -            tmpl = jinja2.Template(mfc_out_tmpl) -            print(tmpl.render(data)) - -        sys.exit(0) -    else: -        parser.print_help() -        sys.exit(1) - diff --git a/src/op_mode/zone.py b/src/op_mode/zone.py new file mode 100755 index 000000000..f326215b1 --- /dev/null +++ b/src/op_mode/zone.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python3 +# +# 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/>. +import typing +import sys +import vyos.opmode + +import tabulate +from vyos.configquery import ConfigTreeQuery +from vyos.util import dict_search_args +from vyos.util import dict_search + + +def get_config_zone(conf, name=None): +    config_path = ['firewall', 'zone'] +    if name: +        config_path += [name] + +    zone_policy = conf.get_config_dict(config_path, key_mangling=('-', '_'), +                                       get_first_key=True, +                                       no_tag_node_value_mangle=True) +    return zone_policy + + +def _convert_one_zone_data(zone: str, zone_config: dict) -> dict: +    """ +    Convert config dictionary of one zone to API dictionary +    :param zone: Zone name +    :type zone: str +    :param zone_config: config dictionary +    :type zone_config: dict +    :return: AP dictionary +    :rtype: dict +    """ +    list_of_rules = [] +    intrazone_dict = {} +    if dict_search('from', zone_config): +        for from_zone, from_zone_config in zone_config['from'].items(): +            from_zone_dict = {'name': from_zone} +            if dict_search('firewall.name', from_zone_config): +                from_zone_dict['firewall'] = dict_search('firewall.name', +                                                         from_zone_config) +            if dict_search('firewall.ipv6_name', from_zone_config): +                from_zone_dict['firewall_v6'] = dict_search( +                    'firewall.ipv6_name', from_zone_config) +            list_of_rules.append(from_zone_dict) + +    zone_dict = { +        'name': zone, +        'interface': dict_search('interface', zone_config), +        'type': 'LOCAL' if dict_search('local_zone', +                                       zone_config) is not None else None, +    } +    if list_of_rules: +        zone_dict['from'] = list_of_rules +    if dict_search('intra_zone_filtering.firewall.name', zone_config): +        intrazone_dict['firewall'] = dict_search( +            'intra_zone_filtering.firewall.name', zone_config) +    if dict_search('intra_zone_filtering.firewall.ipv6_name', zone_config): +        intrazone_dict['firewall_v6'] = dict_search( +            'intra_zone_filtering.firewall.ipv6_name', zone_config) +    if intrazone_dict: +        zone_dict['intrazone'] = intrazone_dict +    return zone_dict + + +def _convert_zones_data(zone_policies: dict) -> list: +    """ +    Convert all config dictionary to API list of zone dictionaries +    :param zone_policies: config dictionary +    :type zone_policies: dict +    :return: API list +    :rtype: list +    """ +    zone_list = [] +    for zone, zone_config in zone_policies.items(): +        zone_list.append(_convert_one_zone_data(zone, zone_config)) +    return zone_list + + +def _convert_config(zones_config: dict, zone: str = None) -> list: +    """ +    convert config to API list +    :param zones_config: zones config +    :type zones_config: +    :param zone: zone name +    :type zone: str +    :return: API list +    :rtype: list +    """ +    if zone: +        if zones_config: +            output = [_convert_one_zone_data(zone, zones_config)] +        else: +            raise vyos.opmode.DataUnavailable(f'Zone {zone} not found') +    else: +        if zones_config: +            output = _convert_zones_data(zones_config) +        else: +            raise vyos.opmode.UnconfiguredSubsystem( +                'Zone entries are not configured') +    return output + + +def output_zone_list(zone_conf: dict) -> list: +    """ +    Format one zone row +    :param zone_conf: zone config +    :type zone_conf: dict +    :return: formatted list of zones +    :rtype: list +    """ +    zone_info = [zone_conf['name']] +    if zone_conf['type'] == 'LOCAL': +        zone_info.append('LOCAL') +    else: +        zone_info.append("\n".join(zone_conf['interface'])) + +    from_zone = [] +    firewall = [] +    firewall_v6 = [] +    if 'intrazone' in zone_conf: +        from_zone.append(zone_conf['name']) + +        v4_name = dict_search_args(zone_conf['intrazone'], 'firewall') +        v6_name = dict_search_args(zone_conf['intrazone'], 'firewall_v6') +        if v4_name: +            firewall.append(v4_name) +        else: +            firewall.append('') +        if v6_name: +            firewall_v6.append(v6_name) +        else: +            firewall_v6.append('') + +    if 'from' in zone_conf: +        for from_conf in zone_conf['from']: +            from_zone.append(from_conf['name']) + +            v4_name = dict_search_args(from_conf, 'firewall') +            v6_name = dict_search_args(from_conf, 'firewall_v6') +            if v4_name: +                firewall.append(v4_name) +            else: +                firewall.append('') +            if v6_name: +                firewall_v6.append(v6_name) +            else: +                firewall_v6.append('') + +    zone_info.append("\n".join(from_zone)) +    zone_info.append("\n".join(firewall)) +    zone_info.append("\n".join(firewall_v6)) +    return zone_info + + +def get_formatted_output(zone_policy: list) -> str: +    """ +    Formatted output of all zones +    :param zone_policy: list of zones +    :type zone_policy: list +    :return: formatted table with zones +    :rtype: str +    """ +    headers = ["Zone", +               "Interfaces", +               "From Zone", +               "Firewall IPv4", +               "Firewall IPv6" +               ] +    formatted_list = [] +    for zone_conf in zone_policy: +        formatted_list.append(output_zone_list(zone_conf)) +    tabulate.PRESERVE_WHITESPACE = True +    output = tabulate.tabulate(formatted_list, headers, numalign="left") +    return output + + +def show(raw: bool, zone: typing.Optional[str]): +    """ +    Show zone-policy command +    :param raw: if API +    :type raw: bool +    :param zone: zone name +    :type zone: str +    """ +    conf: ConfigTreeQuery = ConfigTreeQuery() +    zones_config: dict = get_config_zone(conf, zone) +    zone_policy_api: list = _convert_config(zones_config, zone) +    if raw: +        return zone_policy_api +    else: +        return get_formatted_output(zone_policy_api) + + +if __name__ == '__main__': +    try: +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res) +    except (ValueError, vyos.opmode.Error) as e: +        print(e) +        sys.exit(1) diff --git a/src/op_mode/zone_policy.py b/src/op_mode/zone_policy.py deleted file mode 100755 index 7b43018c2..000000000 --- a/src/op_mode/zone_policy.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/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 argparse -import tabulate - -from vyos.config import Config -from vyos.util import dict_search_args - -def get_config_zone(conf, name=None): -    config_path = ['zone-policy'] -    if name: -        config_path += ['zone', name] - -    zone_policy = conf.get_config_dict(config_path, key_mangling=('-', '_'), -                                get_first_key=True, no_tag_node_value_mangle=True) -    return zone_policy - -def output_zone_name(zone, zone_conf): -    print(f'\n---------------------------------\nZone: "{zone}"\n') -     -    interfaces = ', '.join(zone_conf['interface']) if 'interface' in zone_conf else '' -    if 'local_zone' in zone_conf: -        interfaces = 'LOCAL' - -    print(f'Interfaces: {interfaces}\n') - -    header = ['From Zone', 'Firewall'] -    rows = [] - -    if 'from' in zone_conf: -        for from_name, from_conf in zone_conf['from'].items(): -            row = [from_name] -            v4_name = dict_search_args(from_conf, 'firewall', 'name') -            v6_name = dict_search_args(from_conf, 'firewall', 'ipv6_name') - -            if v4_name: -                rows.append(row + [v4_name]) - -            if v6_name: -                rows.append(row + [f'{v6_name} [IPv6]']) - -    if rows: -        print('From Zones:\n') -        print(tabulate.tabulate(rows, header)) - -def show_zone_policy(zone): -    conf = Config() -    zone_policy = get_config_zone(conf, zone) - -    if not zone_policy: -        return - -    if 'zone' in zone_policy: -        for zone, zone_conf in zone_policy['zone'].items(): -            output_zone_name(zone, zone_conf) -    elif zone: -        output_zone_name(zone, zone_policy) - -if __name__ == '__main__': -    parser = argparse.ArgumentParser() -    parser.add_argument('--action', help='Action', required=False) -    parser.add_argument('--name', help='Zone name', required=False, action='store', nargs='?', default='') - -    args = parser.parse_args() - -    if args.action == 'show': -        show_zone_policy(args.name) diff --git a/src/services/api/graphql/generate/schema_from_op_mode.py b/src/services/api/graphql/generate/schema_from_op_mode.py index fc63b0100..b320a529e 100755 --- a/src/services/api/graphql/generate/schema_from_op_mode.py +++ b/src/services/api/graphql/generate/schema_from_op_mode.py @@ -25,16 +25,17 @@ from inspect import signature, getmembers, isfunction, isclass, getmro  from jinja2 import Template  from vyos.defaults import directories +from vyos.opmode import _is_op_mode_function_name as is_op_mode_function_name  from vyos.util import load_as_module  if __package__ is None or __package__ == '':      sys.path.append("/usr/libexec/vyos/services/api") -    from graphql.libs.op_mode import is_op_mode_function_name, is_show_function_name +    from graphql.libs.op_mode import is_show_function_name      from graphql.libs.op_mode import snake_to_pascal_case, map_type_name      from vyos.config import Config      from vyos.configdict import dict_merge      from vyos.xml import defaults  else: -    from .. libs.op_mode import is_op_mode_function_name, is_show_function_name +    from .. libs.op_mode import is_show_function_name      from .. libs.op_mode import snake_to_pascal_case, map_type_name      from .. import state diff --git a/src/services/api/graphql/graphql/mutations.py b/src/services/api/graphql/graphql/mutations.py index 87ea59c43..8254e22b1 100644 --- a/src/services/api/graphql/graphql/mutations.py +++ b/src/services/api/graphql/graphql/mutations.py @@ -15,7 +15,7 @@  from importlib import import_module  from typing import Any, Dict, Optional -from ariadne import ObjectType, convert_kwargs_to_snake_case, convert_camel_case_to_snake +from ariadne import ObjectType, convert_camel_case_to_snake  from graphql import GraphQLResolveInfo  from makefun import with_signature @@ -45,7 +45,6 @@ def make_mutation_resolver(mutation_name, class_name, session_func):      func_sig = '(obj: Any, info: GraphQLResolveInfo, data: Optional[Dict]=None)'      @mutation.field(mutation_name) -    @convert_kwargs_to_snake_case      @with_signature(func_sig, func_name=resolver_name)      async def func_impl(*args, **kwargs):          try: diff --git a/src/services/api/graphql/graphql/queries.py b/src/services/api/graphql/graphql/queries.py index 1ad586428..daccc19b2 100644 --- a/src/services/api/graphql/graphql/queries.py +++ b/src/services/api/graphql/graphql/queries.py @@ -15,7 +15,7 @@  from importlib import import_module  from typing import Any, Dict, Optional -from ariadne import ObjectType, convert_kwargs_to_snake_case, convert_camel_case_to_snake +from ariadne import ObjectType, convert_camel_case_to_snake  from graphql import GraphQLResolveInfo  from makefun import with_signature @@ -45,7 +45,6 @@ def make_query_resolver(query_name, class_name, session_func):      func_sig = '(obj: Any, info: GraphQLResolveInfo, data: Optional[Dict]=None)'      @query.field(query_name) -    @convert_kwargs_to_snake_case      @with_signature(func_sig, func_name=resolver_name)      async def func_impl(*args, **kwargs):          try: diff --git a/src/services/api/graphql/libs/op_mode.py b/src/services/api/graphql/libs/op_mode.py index c1eb493db..c553bbd67 100644 --- a/src/services/api/graphql/libs/op_mode.py +++ b/src/services/api/graphql/libs/op_mode.py @@ -29,11 +29,6 @@ def load_op_mode_as_module(name: str):      name = os.path.splitext(name)[0].replace('-', '_')      return load_as_module(name, path) -def is_op_mode_function_name(name): -    if re.match(r"^(show|clear|reset|restart|add|delete)", name): -        return True -    return False -  def is_show_function_name(name):      if re.match(r"^show", name):          return True diff --git a/src/services/api/graphql/session/errors/op_mode_errors.py b/src/services/api/graphql/session/errors/op_mode_errors.py index 4029fd0a1..18d555f2d 100644 --- a/src/services/api/graphql/session/errors/op_mode_errors.py +++ b/src/services/api/graphql/session/errors/op_mode_errors.py @@ -1,9 +1,8 @@ - -  op_mode_err_msg = {      "UnconfiguredSubsystem": "subsystem is not configured or not running",      "DataUnavailable": "data currently unavailable",      "PermissionDenied": "client does not have permission", +    "InsufficientResources": "insufficient system resources",      "IncorrectValue": "argument value is incorrect",      "UnsupportedOperation": "operation is not supported (yet)",  } @@ -11,6 +10,7 @@ op_mode_err_msg = {  op_mode_err_code = {      "UnconfiguredSubsystem": 2000,      "DataUnavailable": 2001, +    "InsufficientResources": 2002,      "PermissionDenied": 1003,      "IncorrectValue": 1002,      "UnsupportedOperation": 1004, | 
