diff options
52 files changed, 489 insertions, 241 deletions
| diff --git a/data/templates/accel-ppp/pptp.config.j2 b/data/templates/accel-ppp/pptp.config.j2 index 442830b6b..78a629d2d 100644 --- a/data/templates/accel-ppp/pptp.config.j2 +++ b/data/templates/accel-ppp/pptp.config.j2 @@ -93,10 +93,15 @@ bind={{ radius_source_address }}  gw-ip-address={{ gw_ip }}  {% endif %} -{% if radius_shaper_attr %} +{% if radius_shaper_enable %}  [shaper]  verbose=1 +{%     if radius_shaper_attr %}  attr={{ radius_shaper_attr }} +{%     endif %} +{%     if radius_shaper_multiplier %} +rate-multiplier={{ radius_shaper_multiplier }} +{%     endif %}  {%     if radius_shaper_vendor %}  vendor={{ radius_shaper_vendor }}  {%     endif %} diff --git a/data/templates/ethernet/wpa_supplicant.conf.j2 b/data/templates/ethernet/wpa_supplicant.conf.j2 index 8f140f6cb..cd35d6d1e 100644 --- a/data/templates/ethernet/wpa_supplicant.conf.j2 +++ b/data/templates/ethernet/wpa_supplicant.conf.j2 @@ -67,6 +67,11 @@ network={      # discards such frames to protect against potential attacks by rogue      # devices, but this option can be used to disable that protection for cases      # where the server/authenticator does not need to be authenticated. -    phase1="allow_canned_success=1" +    # +    # "tls_disable_tlsv1_0=0" is used to allow TLSv1 for compatibility with +    # legacy networks. This follows the behavior of Debian's wpa_supplicant, +    # which includes a custom patch for allowing TLSv1, but the patch currently +    # does not work for VyOS' git builds of wpa_supplicant. +    phase1="allow_canned_success=1 tls_disable_tlsv1_0=0"  } diff --git a/data/templates/frr/isisd.frr.j2 b/data/templates/frr/isisd.frr.j2 index 8df1e9513..3c37e28b9 100644 --- a/data/templates/frr/isisd.frr.j2 +++ b/data/templates/frr/isisd.frr.j2 @@ -25,6 +25,12 @@ interface {{ iface }}  {%         if iface_config.hello_padding is vyos_defined %}   isis hello padding  {%         endif %} +{%         if iface_config.ldp_sync.disable is vyos_defined %} + no isis mpls ldp-sync +{%         elif iface_config.ldp_sync.holddown is vyos_defined %} + isis mpls ldp-sync + isis mpls ldp-sync holddown {{ iface_config.ldp_sync.holddown }} +{%         endif %}  {%         if iface_config.metric is vyos_defined %}   isis metric {{ iface_config.metric }}  {%         endif %} @@ -84,6 +90,11 @@ router isis VyOS {{ 'vrf ' + vrf if vrf is vyos_defined }}  {% if max_lsp_lifetime is vyos_defined %}   max-lsp-lifetime {{ max_lsp_lifetime }}  {% endif %} +{% if ldp_sync.holddown is vyos_defined %} + mpls ldp-sync holddown {{ ldp_sync.holddown }} +{% elif ldp_sync is vyos_defined %} + mpls ldp-sync +{% endif %}  {% if spf_interval is vyos_defined %}   spf-interval {{ spf_interval }}  {% endif %} diff --git a/data/templates/frr/ospfd.frr.j2 b/data/templates/frr/ospfd.frr.j2 index 8c4a81c57..3f97b7325 100644 --- a/data/templates/frr/ospfd.frr.j2 +++ b/data/templates/frr/ospfd.frr.j2 @@ -44,6 +44,12 @@ interface {{ iface }}  {%         if iface_config.bfd.profile is vyos_defined %}   ip ospf bfd profile {{ iface_config.bfd.profile }}  {%         endif %} +{%         if iface_config.ldp_sync.disable is vyos_defined %} + no ip ospf mpls ldp-sync +{%         elif iface_config.ldp_sync.holddown is vyos_defined %} + ip ospf mpls ldp-sync + ip ospf mpls ldp-sync holddown {{ iface_config.ldp_sync.holddown }} +{%         endif %}  {%         if iface_config.mtu_ignore is vyos_defined %}   ip ospf mtu-ignore  {%         endif %} @@ -133,6 +139,11 @@ router ospf {{ 'vrf ' ~ vrf if vrf is vyos_defined }}  {% if maximum_paths is vyos_defined %}   maximum-paths {{ maximum_paths }}  {% endif %} +{% if ldp_sync.holddown is vyos_defined %} + mpls ldp-sync holddown {{ ldp_sync.holddown }} +{% elif ldp_sync is vyos_defined %} + mpls ldp-sync +{% endif %}  {% if distance.global is vyos_defined %}   distance {{ distance.global }}  {% endif %} diff --git a/data/templates/login/limits.j2 b/data/templates/login/limits.j2 new file mode 100644 index 000000000..5e2c11f35 --- /dev/null +++ b/data/templates/login/limits.j2 @@ -0,0 +1,5 @@ +# Generated by /usr/libexec/vyos/conf_mode/system-login.py + +{% if max_login_session is vyos_defined %} +* - maxsyslogins {{ max_login_session }} +{% endif %} diff --git a/data/templates/telegraf/telegraf.j2 b/data/templates/telegraf/telegraf.j2 index c9f402281..5852d6232 100644 --- a/data/templates/telegraf/telegraf.j2 +++ b/data/templates/telegraf/telegraf.j2 @@ -12,7 +12,7 @@    debug = false    quiet = false    logfile = "" -  hostname = "" +  hostname = "{{ hostname }}"    omit_hostname = false  {% if azure_data_explorer is vyos_defined %}  ### Azure Data Explorer ### diff --git a/debian/control b/debian/control index 8cd49f62a..856f57030 100644 --- a/debian/control +++ b/debian/control @@ -35,6 +35,7 @@ Architecture: amd64 arm64  Depends:    ${python3:Depends},    accel-ppp, +  auditd,    avahi-daemon,    beep,    bmon, @@ -80,6 +81,7 @@ Depends:    lcdproc,    lcdproc-extra-drivers,    libatomic1, +  libauparse0,    libbpf1 [amd64],    libcharon-extra-plugins (>=5.9),    libcharon-extauth-plugins (>=5.9), diff --git a/interface-definitions/bcast-relay.xml.in b/interface-definitions/bcast-relay.xml.in index aeaa5ab37..e2993f3f3 100644 --- a/interface-definitions/bcast-relay.xml.in +++ b/interface-definitions/bcast-relay.xml.in @@ -34,11 +34,7 @@                    </constraint>                  </properties>                </leafNode> -              <leafNode name="description"> -                <properties> -                  <help>Description</help> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                #include <include/generic-interface-multi.xml.i>                #include <include/port-number.xml.i>              </children> diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in index b09536a16..9b6d2369d 100644 --- a/interface-definitions/container.xml.in +++ b/interface-definitions/container.xml.in @@ -348,11 +348,7 @@            <constraintErrorMessage>Network name cannot be longer than 11 characters</constraintErrorMessage>          </properties>          <children> -          <leafNode name="description"> -            <properties> -              <help>Network description</help> -            </properties> -          </leafNode> +          #include <include/generic-description.xml.i>            <leafNode name="prefix">              <properties>                <help>Prefix which allocated to that network</help> @@ -371,6 +367,7 @@                <multi/>              </properties>            </leafNode> +          #include <include/interface/vrf.xml.i>          </children>        </tagNode>        <tagNode name="registry"> diff --git a/interface-definitions/dns-forwarding.xml.in b/interface-definitions/dns-forwarding.xml.in index 14b38b24d..6b7344b1d 100644 --- a/interface-definitions/dns-forwarding.xml.in +++ b/interface-definitions/dns-forwarding.xml.in @@ -83,6 +83,13 @@                <tagNode name="domain">                  <properties>                    <help>Domain to forward to a custom DNS server</help> +                  <valueHelp> +                    <format>txt</format> +                    <description>An absolute DNS domain name</description> +                  </valueHelp> +                  <constraint> +                    <validator name="fqdn"/> +                  </constraint>                  </properties>                  <children>                    #include <include/name-server-ipv4-ipv6-port.xml.i> @@ -104,11 +111,11 @@                  <properties>                    <help>Domain to host authoritative records for</help>                    <valueHelp> -                    <format>text</format> -                    <description>An absolute DNS name</description> +                    <format>txt</format> +                    <description>An absolute DNS domain name</description>                    </valueHelp>                    <constraint> -                    <regex>[-_a-zA-Z0-9.]{1,63}</regex> +                    <validator name="fqdn"/>                    </constraint>                  </properties>                  <children> @@ -121,7 +128,7 @@                          <properties>                            <help>"A" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -158,7 +165,7 @@                          <properties>                            <help>"AAAA" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -195,7 +202,7 @@                          <properties>                            <help>"CNAME" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -227,7 +234,7 @@                          <properties>                            <help>"MX" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -274,7 +281,7 @@                          <properties>                            <help>"PTR" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -306,7 +313,7 @@                          <properties>                            <help>"TXT" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -322,7 +329,7 @@                              <properties>                                <help>Record contents</help>                                <valueHelp> -                                <format>text</format> +                                <format>txt</format>                                  <description>Record contents</description>                                </valueHelp>                                <multi/> @@ -336,7 +343,7 @@                          <properties>                            <help>"SPF" record (type=SPF)</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -352,7 +359,7 @@                              <properties>                                <help>Record contents</help>                                <valueHelp> -                                <format>text</format> +                                <format>txt</format>                                  <description>Record contents</description>                                </valueHelp>                              </properties> @@ -365,7 +372,7 @@                          <properties>                            <help>"SRV" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> @@ -449,7 +456,7 @@                          <properties>                            <help>"NAPTR" record</help>                            <valueHelp> -                            <format>text</format> +                            <format>txt</format>                              <description>A DNS name relative to the root record</description>                            </valueHelp>                            <valueHelp> diff --git a/interface-definitions/include/isis/ldp-sync-holddown.xml.i b/interface-definitions/include/isis/ldp-sync-holddown.xml.i new file mode 100644 index 000000000..15ac26f07 --- /dev/null +++ b/interface-definitions/include/isis/ldp-sync-holddown.xml.i @@ -0,0 +1,14 @@ +<!-- include start from isis/ldp-sync-holddown.xml.i --> +<leafNode name="holddown"> +  <properties> +    <help>Hold down timer for LDP-IGP cost restoration</help> +    <valueHelp> +      <format>u32:0-10000</format> +      <description>Time to wait in seconds for LDP-IGP synchronization to occur before restoring interface cost</description> +    </valueHelp> +    <constraint> +      <validator name="numeric" argument="--range 0-10000"/> +    </constraint> +  </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/isis/ldp-sync-interface.xml.i b/interface-definitions/include/isis/ldp-sync-interface.xml.i new file mode 100644 index 000000000..222a35256 --- /dev/null +++ b/interface-definitions/include/isis/ldp-sync-interface.xml.i @@ -0,0 +1,11 @@ +<!-- include start from isis/ldp-igp-sync.xml.i --> +<node name="ldp-sync"> +  <properties> +    <help>LDP-IGP synchronization configuration for interface</help> +  </properties> +  <children> +    #include <include/generic-disable-node.xml.i> +    #include <include/isis/ldp-sync-holddown.xml.i> +  </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/isis/ldp-sync-protocol.xml.i b/interface-definitions/include/isis/ldp-sync-protocol.xml.i new file mode 100644 index 000000000..b2e696a70 --- /dev/null +++ b/interface-definitions/include/isis/ldp-sync-protocol.xml.i @@ -0,0 +1,10 @@ +<!-- include start from isis/ldp-igp-sync.xml.i --> +<node name="ldp-sync"> +  <properties> +    <help>Protocol wide LDP-IGP synchronization configuration</help> +  </properties> +  <children> +    #include <include/isis/ldp-sync-holddown.xml.i> +  </children> +</node> +<!-- include end --> diff --git a/interface-definitions/include/isis/protocol-common-config.xml.i b/interface-definitions/include/isis/protocol-common-config.xml.i index 0e6f19480..8103b5c5d 100644 --- a/interface-definitions/include/isis/protocol-common-config.xml.i +++ b/interface-definitions/include/isis/protocol-common-config.xml.i @@ -152,6 +152,7 @@      </constraint>    </properties>  </leafNode> +#include <include/isis/ldp-sync-protocol.xml.i>  <leafNode name="net">    <properties>      <help>A Network Entity Title for this process (ISO only)</help> @@ -172,7 +173,7 @@  </leafNode>  <node name="traffic-engineering">    <properties> -    <help>Show IS-IS neighbor adjacencies</help> +    <help>IS-IS traffic engineering extensions</help>    </properties>    <children>      <leafNode name="enable"> @@ -631,6 +632,7 @@        </properties>      </leafNode>      #include <include/isis/metric.xml.i> +    #include <include/isis/ldp-sync-interface.xml.i>      <node name="network">        <properties>          <help>Set network type</help> diff --git a/interface-definitions/include/ospf/protocol-common-config.xml.i b/interface-definitions/include/ospf/protocol-common-config.xml.i index f39b9c5e3..e400119dd 100644 --- a/interface-definitions/include/ospf/protocol-common-config.xml.i +++ b/interface-definitions/include/ospf/protocol-common-config.xml.i @@ -331,6 +331,7 @@      </constraint>    </properties>  </leafNode> +#include <include/isis/ldp-sync-protocol.xml.i>  <node name="distance">    <properties>      <help>Administrative distance</help> @@ -385,6 +386,7 @@      #include <include/ospf/authentication.xml.i>      #include <include/ospf/intervals.xml.i>      #include <include/ospf/interface-common.xml.i> +    #include <include/isis/ldp-sync-interface.xml.i>      <leafNode name="bandwidth">        <properties>          <help>Interface bandwidth (Mbit/s)</help> @@ -875,4 +877,4 @@      </node>    </children>  </node> -<!-- include end --> +<!-- include end -->
\ No newline at end of file diff --git a/interface-definitions/load-balancing-wan.xml.in b/interface-definitions/load-balancing-wan.xml.in index 2b812eb4d..c1d7e2c67 100644 --- a/interface-definitions/load-balancing-wan.xml.in +++ b/interface-definitions/load-balancing-wan.xml.in @@ -191,15 +191,7 @@                </constraint>              </properties>              <children> -              <leafNode name="description"> -                <properties> -                  <help>Description for this rule</help> -                  <valueHelp> -                    <format>txt</format> -                    <description>Description for this rule</description> -                  </valueHelp> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                <node name="destination">                  <properties>                    <help>Destination</help> diff --git a/interface-definitions/nat66.xml.in b/interface-definitions/nat66.xml.in index 6ea611789..7a8970bdf 100644 --- a/interface-definitions/nat66.xml.in +++ b/interface-definitions/nat66.xml.in @@ -24,11 +24,7 @@                <constraintErrorMessage>NAT66 rule number must be between 1 and 999999</constraintErrorMessage>              </properties>              <children> -              <leafNode name="description"> -                <properties> -                  <help>Rule description</help> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                <leafNode name="disable">                  <properties>                    <help>Disable NAT66 rule</help> @@ -156,11 +152,7 @@                <constraintErrorMessage>NAT66 rule number must be between 1 and 999999</constraintErrorMessage>              </properties>              <children> -              <leafNode name="description"> -                <properties> -                  <help>Rule description</help> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                <leafNode name="disable">                  <properties>                    <help>Disable NAT66 rule</help> diff --git a/interface-definitions/pki.xml.in b/interface-definitions/pki.xml.in index c4fde2c78..a13a357fd 100644 --- a/interface-definitions/pki.xml.in +++ b/interface-definitions/pki.xml.in @@ -16,11 +16,7 @@                <help>CA certificate in PEM format</help>              </properties>            </leafNode> -          <leafNode name="description"> -            <properties> -              <help>Description</help> -            </properties> -          </leafNode> +          #include <include/generic-description.xml.i>            <node name="private">              <properties>                <help>CA private key in PEM format</help> @@ -63,11 +59,7 @@                <help>Certificate in PEM format</help>              </properties>            </leafNode> -          <leafNode name="description"> -            <properties> -              <help>Description</help> -            </properties> -          </leafNode> +          #include <include/generic-description.xml.i>            <node name="private">              <properties>                <help>Certificate private key</help> diff --git a/interface-definitions/protocols-failover.xml.in b/interface-definitions/protocols-failover.xml.in index 900c76eab..a8c5c717f 100644 --- a/interface-definitions/protocols-failover.xml.in +++ b/interface-definitions/protocols-failover.xml.in @@ -48,6 +48,7 @@                            <constraint>                              <validator name="ipv4-address"/>                            </constraint> +                          <multi/>                          </properties>                        </leafNode>                        <leafNode name="timeout"> diff --git a/interface-definitions/service-webproxy.xml.in b/interface-definitions/service-webproxy.xml.in index a315aa2ef..b24997816 100644 --- a/interface-definitions/service-webproxy.xml.in +++ b/interface-definitions/service-webproxy.xml.in @@ -538,11 +538,7 @@                            <multi/>                          </properties>                        </leafNode> -                      <leafNode name="description"> -                        <properties> -                          <help>Description for source-group</help> -                        </properties> -                      </leafNode> +                      #include <include/generic-description.xml.i>                        <leafNode name="domain">                          <properties>                            <help>Domain for source-group</help> @@ -644,11 +640,7 @@                            </leafNode>                          </children>                        </tagNode> -                      <leafNode name="description"> -                        <properties> -                          <help>Time-period description</help> -                        </properties> -                      </leafNode> +                      #include <include/generic-description.xml.i>                      </children>                    </tagNode>                  </children> diff --git a/interface-definitions/snmp.xml.in b/interface-definitions/snmp.xml.in index 592db7f4e..559e09388 100644 --- a/interface-definitions/snmp.xml.in +++ b/interface-definitions/snmp.xml.in @@ -78,15 +78,7 @@                <constraintErrorMessage>Contact information is limited to 255 characters or less</constraintErrorMessage>              </properties>            </leafNode> -          <leafNode name="description"> -            <properties> -              <help>Description information</help> -              <constraint> -                <regex>.{1,255}</regex> -              </constraint> -              <constraintErrorMessage>Description is limited to 255 characters or less</constraintErrorMessage> -            </properties> -          </leafNode> +          #include <include/generic-description.xml.i>            <tagNode name="listen-address">              <properties>                <help>IP address to listen for incoming SNMP requests</help> diff --git a/interface-definitions/system-login.xml.in b/interface-definitions/system-login.xml.in index b00741ffe..258913929 100644 --- a/interface-definitions/system-login.xml.in +++ b/interface-definitions/system-login.xml.in @@ -225,6 +225,19 @@                #include <include/interface/vrf.xml.i>              </children>            </node> +          <leafNode name="max-login-session"> +            <properties> +              <help>Maximum number of all login sessions</help> +              <valueHelp> +                <format>u32:1-65536</format> +                <description>Maximum number of all login sessions</description> +              </valueHelp> +              <constraint> +                <validator name="numeric" argument="--range 1-65536"/> +              </constraint> +              <constraintErrorMessage>Maximum logins must be between 1 and 65536</constraintErrorMessage> +            </properties> +          </leafNode>            <leafNode name="timeout">              <properties>                <help>Session timeout</help> diff --git a/interface-definitions/vpn-ipsec.xml.in b/interface-definitions/vpn-ipsec.xml.in index 1b3a5532e..64cfbda08 100644 --- a/interface-definitions/vpn-ipsec.xml.in +++ b/interface-definitions/vpn-ipsec.xml.in @@ -357,11 +357,11 @@                  <properties>                    <help>IKE lifetime</help>                    <valueHelp> -                    <format>u32:30-86400</format> +                    <format>u32:0-86400</format>                      <description>IKE lifetime in seconds</description>                    </valueHelp>                    <constraint> -                    <validator name="numeric" argument="--range 30-86400"/> +                    <validator name="numeric" argument="--range 0-86400"/>                    </constraint>                  </properties>                  <defaultValue>28800</defaultValue> diff --git a/interface-definitions/vpn-l2tp.xml.in b/interface-definitions/vpn-l2tp.xml.in index 0a92017bd..6b64c5f5d 100644 --- a/interface-definitions/vpn-l2tp.xml.in +++ b/interface-definitions/vpn-l2tp.xml.in @@ -124,11 +124,7 @@                  </children>                </node>                #include <include/accel-ppp/client-ipv6-pool.xml.i> -              <leafNode name="description"> -                <properties> -                  <help>Description for L2TP remote-access settings</help> -                </properties> -              </leafNode> +              #include <include/generic-description.xml.i>                #include <include/dhcp-interface.xml.i>                <leafNode name="idle">                  <properties> diff --git a/interface-definitions/vpn-pptp.xml.in b/interface-definitions/vpn-pptp.xml.in index 00ffd26f9..5a8b4a78a 100644 --- a/interface-definitions/vpn-pptp.xml.in +++ b/interface-definitions/vpn-pptp.xml.in @@ -108,9 +108,13 @@                        </tagNode>                      </children>                    </node> +                  <node name="radius"> +                    <children> +                      #include <include/accel-ppp/radius-additions-rate-limit.xml.i> +                    </children> +                  </node>                    #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>                </node>              </children> diff --git a/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i b/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i index 7dbc4fde5..820d507fd 100644 --- a/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i +++ b/op-mode-definitions/include/bgp/afi-ipv4-ipv6-common.xml.i @@ -195,6 +195,12 @@          </leafNode>        </children>      </node> +    <leafNode name="filtered-routes"> +      <properties> +        <help>Show filtered routes from BGP neighbor</help> +      </properties> +      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +    </leafNode>      <leafNode name="received-routes">        <properties>          <help>Show received routes from BGP neighbor</help> diff --git a/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i b/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i index 36cc9a3fa..db9021f3e 100644 --- a/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i +++ b/op-mode-definitions/include/bgp/show-ip-bgp-common.xml.i @@ -93,6 +93,12 @@                </properties>                <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>              </leafNode> +            <leafNode name="filtered-routes"> +              <properties> +                <help>Show the filtered routes from neighbor</help> +              </properties> +              <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +            </leafNode>              <leafNode name="received-routes">                <properties>                  <help>Show the received routes from neighbor</help> diff --git a/op-mode-definitions/include/isis-common.xml.i b/op-mode-definitions/include/isis-common.xml.i index 0e20861c7..e94d868e8 100644 --- a/op-mode-definitions/include/isis-common.xml.i +++ b/op-mode-definitions/include/isis-common.xml.i @@ -4,12 +4,7 @@      <help>Show IS-IS link state database</help>    </properties>    <children> -    <leafNode name="detail"> -      <properties> -        <help>Show detailed information</help> -      </properties> -      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -    </leafNode> +    #include <include/vtysh-generic-detail.xml.i>    </children>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node> @@ -36,27 +31,22 @@      </completionHelp>    </properties>    <children> -    <leafNode name="detail"> -      <properties> -        <help>Show detailed information</help> -      </properties> -      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -    </leafNode> +    #include <include/vtysh-generic-detail.xml.i>    </children>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node> -<tagNode name="interface"> +#include <include/vtysh-generic-interface-tagNode.xml.i> +<node name="mpls">    <properties> -    <help>Show specific IS-IS interface</help> -    <completionHelp> -      <script>${vyos_completion_dir}/list_interfaces</script> -    </completionHelp> +    <help>Show MPLS information</help>    </properties> -  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -</tagNode> +  <children> +  #include <include/ldp-sync.xml.i> +  </children> +</node>  <node name="mpls-te">    <properties> -    <help>Show IS-IS MPLS traffic engineering information</help> +    <help>Show MPLS traffic engineering information</help>    </properties>    <children>      <leafNode name="router"> @@ -71,15 +61,7 @@        </properties>        <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>      </leafNode> -    <tagNode name="interface"> -      <properties> -        <help>Show specific IS-IS interface</help> -        <completionHelp> -          <script>${vyos_completion_dir}/list_interfaces</script> -        </completionHelp> -      </properties> -      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -    </tagNode> +    #include <include/vtysh-generic-interface-tagNode.xml.i>    </children>  </node>  <node name="neighbor"> @@ -87,12 +69,7 @@      <help>Show IS-IS neighbor adjacencies</help>    </properties>    <children> -    <leafNode name="detail"> -      <properties> -        <help>Show detailed information</help> -      </properties> -      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -    </leafNode> +    #include <include/vtysh-generic-detail.xml.i>    </children>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node> @@ -176,4 +153,4 @@    </children>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node> -<!-- included end --> +<!-- included end -->
\ No newline at end of file diff --git a/op-mode-definitions/include/ldp-sync.xml.i b/op-mode-definitions/include/ldp-sync.xml.i new file mode 100644 index 000000000..b7b04e7e5 --- /dev/null +++ b/op-mode-definitions/include/ldp-sync.xml.i @@ -0,0 +1,11 @@ +<!-- included start from ldp-sync.xml.i --> +<node name="ldp-sync"> +  <properties> +    <help>Show LDP-IGP synchronization information</help> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +  <children> +    #include <include/vtysh-generic-interface-tagNode.xml.i> +  </children> +</node> +<!-- included end -->
\ No newline at end of file diff --git a/op-mode-definitions/include/ospf-common.xml.i b/op-mode-definitions/include/ospf-common.xml.i index 098254f4e..aebbae5ff 100644 --- a/op-mode-definitions/include/ospf-common.xml.i +++ b/op-mode-definitions/include/ospf-common.xml.i @@ -508,15 +508,15 @@    </properties>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </node> -<tagNode name="interface"> +#include <include/vtysh-generic-interface-tagNode.xml.i> +<node name="mpls">    <properties> -    <help>Show IPv4 OSPF information for specified interface</help> -    <completionHelp> -      <script>${vyos_completion_dir}/list_interfaces</script> -    </completionHelp> +    <help>Show MPLS information</help>    </properties> -  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -</tagNode> +  <children> +  #include <include/ldp-sync.xml.i> +  </children> +</node>  <node name="neighbor">    <properties>      <help>Show IPv4 OSPF neighbor information</help> @@ -547,4 +547,4 @@    </properties>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </leafNode> -<!-- included end --> +<!-- included end -->
\ No newline at end of file diff --git a/op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i b/op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i new file mode 100644 index 000000000..e95961177 --- /dev/null +++ b/op-mode-definitions/include/vtysh-generic-interface-tagNode.xml.i @@ -0,0 +1,11 @@ +<!-- included start from vtysh-generic-interface.xml.i --> +<tagNode name="interface"> +  <properties> +    <help>Show information about specific interface</help> +    <completionHelp> +      <script>${vyos_completion_dir}/list_interfaces</script> +    </completionHelp> +  </properties> +  <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</tagNode> +<!-- included end --> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 7f6469ca9..7663e4c00 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -8,6 +8,12 @@          </properties>          <command>journalctl --no-hostname --boot</command>          <children> +          <leafNode name="audit"> +            <properties> +              <help>Show audit logs</help> +            </properties> +            <command>cat /var/log/audit/audit.log</command> +          </leafNode>            <leafNode name="all">              <properties>                <help>Show contents of all master log files</help> diff --git a/smoketest/scripts/cli/test_interfaces_openvpn.py b/smoketest/scripts/cli/test_interfaces_openvpn.py index b2143d16e..c80c7cf80 100755 --- a/smoketest/scripts/cli/test_interfaces_openvpn.py +++ b/smoketest/scripts/cli/test_interfaces_openvpn.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2020-2022 VyOS maintainers and contributors +# Copyright (C) 2020-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 @@ -368,6 +368,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):              self.cli_set(path + ['hash', auth_hash])              self.cli_set(path + ['mode', 'server'])              self.cli_set(path + ['local-port', port]) +            self.cli_set(path + ['server', 'mfa', 'totp'])              self.cli_set(path + ['server', 'subnet', subnet])              self.cli_set(path + ['server', 'topology', 'subnet'])              self.cli_set(path + ['keep-alive', 'failure-count', '5']) @@ -388,6 +389,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):          for ii in num_range:              interface = f'vtun{ii}' +            plugin = f'plugin "/usr/lib/openvpn/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{interface}-otp-secrets otp_slop=180 totp_t0=0 totp_step=30 totp_digits=6 password_is_cr=1"'              subnet = f'192.0.{ii}.0/24'              start_addr = inc_ip(subnet, '2') @@ -411,6 +413,7 @@ class TestInterfacesOpenVPN(VyOSUnitTestSHIM.TestCase):              self.assertIn(f'topology subnet', config)              self.assertIn(f'lport {port}', config)              self.assertIn(f'push "redirect-gateway def1"', config) +            self.assertIn(f'{plugin}', config)              self.assertIn(f'keepalive 5 25', config)              # TLS options diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py index d11d80a1f..61e29c449 100755 --- a/smoketest/scripts/cli/test_protocols_isis.py +++ b/smoketest/scripts/cli/test_protocols_isis.py @@ -308,5 +308,48 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):          self.assertIn(f' segment-routing prefix {prefix_three} absolute {prefix_three_value} explicit-null', tmp)          self.assertIn(f' segment-routing prefix {prefix_four} absolute {prefix_four_value} no-php-flag', tmp) +    def test_isis_08_ldp_sync(self): +        holddown = "500" +        interface = 'lo' + +        self.cli_set(base_path + ['net', net]) +        self.cli_set(base_path + ['interface', interface]) +        self.cli_set(base_path + ['ldp-sync', 'holddown', holddown]) +         +        # Commit main ISIS changes +        self.cli_commit() +         +        # Verify main ISIS changes +        tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') +        self.assertIn(f' net {net}', tmp) +        self.assertIn(f' mpls ldp-sync', tmp) +        self.assertIn(f' mpls ldp-sync holddown {holddown}', tmp) +         +        for interface in self._interfaces: +            self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'holddown', holddown]) + +            # Commit interface changes for holddown +            self.cli_commit() + +            # Verify interface changes for holddown +            tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd') +            self.assertIn(f'interface {interface}', tmp) +            self.assertIn(f' ip router isis {domain}', tmp) +            self.assertIn(f' ipv6 router isis {domain}', tmp) +            self.assertIn(f' isis mpls ldp-sync holddown {holddown}', tmp) +             +        for interface in self._interfaces: +            self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'disable']) +             +            # Commit interface changes for disable +            self.cli_commit() +             +            # Verify interface changes for disable +            tmp = self.getFRRconfig(f'interface {interface}', daemon='isisd') +            self.assertIn(f'interface {interface}', tmp) +            self.assertIn(f' ip router isis {domain}', tmp) +            self.assertIn(f' ipv6 router isis {domain}', tmp) +            self.assertIn(f' no isis mpls ldp-sync', tmp) +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index 581959b15..d4c85f2b2 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -434,6 +434,47 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):          self.assertIn(f' segment-routing prefix {prefix_one} index {prefix_one_value} explicit-null', frrconfig)          self.assertIn(f' segment-routing prefix {prefix_two} index {prefix_two_value} no-php-flag', frrconfig) +    def test_ospf_15_ldp_sync(self): +        holddown = "500" +        interface = 'lo' +        interfaces = Section.interfaces('ethernet') + +        self.cli_set(base_path + ['interface', interface]) +        self.cli_set(base_path + ['ldp-sync', 'holddown', holddown]) +         +        # Commit main OSPF changes +        self.cli_commit() +         +        # Verify main OSPF changes +        frrconfig = self.getFRRconfig('router ospf') +        self.assertIn(f'router ospf', frrconfig) +        self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) +        self.assertIn(f' mpls ldp-sync holddown {holddown}', frrconfig) +         +        for interface in interfaces: +            self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'holddown', holddown]) + +            # Commit interface changes for holddown +            self.cli_commit() + +            # Verify interface changes for holddown +            config = self.getFRRconfig(f'interface {interface}') +            self.assertIn(f'interface {interface}', config) +            self.assertIn(f' ip ospf dead-interval 40', config) +            self.assertIn(f' ip ospf mpls ldp-sync', config) +            self.assertIn(f' ip ospf mpls ldp-sync holddown {holddown}', config) +             +        for interface in interfaces: +            self.cli_set(base_path + ['interface', interface, 'ldp-sync', 'disable']) +             +            # Commit interface changes for disable +            self.cli_commit() +             +            # Verify interface changes for disable +            config = self.getFRRconfig(f'interface {interface}') +            self.assertIn(f'interface {interface}', config) +            self.assertIn(f' ip ospf dead-interval 40', config) +            self.assertIn(f' no ip ospf mpls ldp-sync', config)  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_login.py b/smoketest/scripts/cli/test_system_login.py index 6006fe0f6..a1d2ba2ad 100755 --- a/smoketest/scripts/cli/test_system_login.py +++ b/smoketest/scripts/cli/test_system_login.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 @@ -264,5 +264,26 @@ class TestSystemLogin(VyOSUnitTestSHIM.TestCase):          tmp = re.findall(r'group:\s+mapname\s+files', nsswitch_conf)          self.assertTrue(tmp) +    def test_system_login_max_login_session(self): +        max_logins = '2' +        timeout = '600' + +        self.cli_set(base_path + ['max-login-session', max_logins]) + +        # 'max-login-session' must be only with 'timeout' option +        with self.assertRaises(ConfigSessionError): +            self.cli_commit() + +        self.cli_set(base_path + ['timeout', timeout]) + +        self.cli_commit() + +        security_limits = read_file('/etc/security/limits.d/10-vyos.conf') +        self.assertIn(f'* - maxsyslogins {max_logins}', security_limits) + +        self.cli_delete(base_path + ['timeout']) +        self.cli_delete(base_path + ['max-login-session']) + +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py index 3827f4c70..4b7ab3444 100755 --- a/src/conf_mode/container.py +++ b/src/conf_mode/container.py @@ -26,6 +26,8 @@ from vyos.config import Config  from vyos.configdict import dict_merge  from vyos.configdict import node_changed  from vyos.configdict import is_node_changed +from vyos.configverify import verify_vrf +from vyos.ifconfig import Interface  from vyos.util import call  from vyos.util import cmd  from vyos.util import run @@ -250,6 +252,8 @@ def verify(container):              if v6_prefix > 1:                  raise ConfigError(f'Only one IPv6 prefix can be defined for network "{network}"!') +            # Verify VRF exists +            verify_vrf(network_config)      # A network attached to a container can not be deleted      if {'network_remove', 'name'} <= set(container): @@ -469,6 +473,20 @@ def apply(container):      if disabled_new:          call('systemctl daemon-reload') +    # Start network and assign it to given VRF if requested. this can only be done +    # after the containers got started as the podman network interface will +    # only be enabled by the first container and yet I do not know how to enable +    # the network interface in advance +    if 'network' in container: +        for network, network_config in container['network'].items(): +            network_name = f'podman-{network}' +            # T5147: Networks are started only as soon as there is a consumer. +            # If only a network is created in the first place, no need to assign +            # it to a VRF as there's no consumer, yet. +            if os.path.exists(f'/sys/class/net/{network_name}'): +                tmp = Interface(network_name) +                tmp.set_vrf(network_config.get('vrf', '')) +      return None  if __name__ == '__main__': diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index c41a442df..190587980 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -282,6 +282,9 @@ def verify_rule(firewall, rule_conf, ipv6):                  if rule_conf['protocol'] not in ['tcp', 'udp', 'tcp_udp']:                      raise ConfigError('Protocol must be tcp, udp, or tcp_udp when specifying a port or port-group') +            if 'port' in side_conf and dict_search_args(side_conf, 'group', 'port_group'): +                raise ConfigError(f'{side} port-group and port cannot both be defined') +      if 'log_options' in rule_conf:          if 'log' not in rule_conf or 'enable' not in rule_conf['log']:              raise ConfigError('log-options defined, but log is not enable') diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 13d84a6fe..6f227b0d1 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.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 @@ -597,7 +597,7 @@ def generate_pki_files(openvpn):  def generate(openvpn):      interface = openvpn['ifname']      directory = os.path.dirname(cfg_file.format(**openvpn)) -    plugin_dir = '/usr/lib/openvpn' +    openvpn['plugin_dir'] = '/usr/lib/openvpn'      # create base config directory on demand      makedir(directory, user, group)      # enforce proper permissions on /run/openvpn diff --git a/src/conf_mode/protocols_eigrp.py b/src/conf_mode/protocols_eigrp.py index c1a1a45e1..6e75e34ff 100755 --- a/src/conf_mode/protocols_eigrp.py +++ b/src/conf_mode/protocols_eigrp.py @@ -69,8 +69,6 @@ def get_config(config=None):      # Merge policy dict into "regular" config dict      eigrp = dict_merge(tmp, eigrp) -    import pprint -    pprint.pprint(eigrp)      return eigrp  def verify(eigrp): diff --git a/src/conf_mode/service_monitoring_telegraf.py b/src/conf_mode/service_monitoring_telegraf.py index 363408679..47510ce80 100755 --- a/src/conf_mode/service_monitoring_telegraf.py +++ b/src/conf_mode/service_monitoring_telegraf.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -15,6 +15,7 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  import os +import socket  import json  from sys import exit @@ -57,6 +58,13 @@ def get_nft_filter_chains():      return chain_list +def get_hostname() -> str: +    try: +        hostname = socket.getfqdn() +    except socket.gaierror: +        hostname = socket.gethostname() +    return hostname +  def get_config(config=None):      if config:          conf = config @@ -79,6 +87,7 @@ def get_config(config=None):      monitoring = dict_merge(default_values, monitoring)      monitoring['custom_scripts_dir'] = custom_scripts_dir +    monitoring['hostname'] = get_hostname()      monitoring['interfaces_ethernet'] = Section.interfaces('ethernet', vlan=False)      monitoring['nft_chains'] = get_nft_filter_chains() diff --git a/src/conf_mode/system-login.py b/src/conf_mode/system-login.py index d15fe399d..fbb013cf3 100755 --- a/src/conf_mode/system-login.py +++ b/src/conf_mode/system-login.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2020-2022 VyOS maintainers and contributors +# Copyright (C) 2020-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 @@ -40,6 +40,7 @@ from vyos import airbag  airbag.enable()  autologout_file = "/etc/profile.d/autologout.sh" +limits_file = "/etc/security/limits.d/10-vyos.conf"  radius_config_file = "/etc/pam_radius_auth.conf"  # LOGIN_TIMEOUT from /etc/loign.defs minus 10 sec @@ -164,6 +165,9 @@ def verify(login):              if ipv6_count > 1:                  raise ConfigError('Only one IPv6 source-address can be set!') +    if 'max_login_session' in login and 'timeout' not in login: +        raise ConfigError('"login timeout" must be configured!') +      return None @@ -226,6 +230,14 @@ def generate(login):          if os.path.isfile(radius_config_file):              os.unlink(radius_config_file) +    # /etc/security/limits.d/10-vyos.conf +    if 'max_login_session' in login: +        render(limits_file, 'login/limits.j2', login, +                   permission=0o644, user='root', group='root') +    else: +        if os.path.isfile(limits_file): +            os.unlink(limits_file) +      if 'timeout' in login:          render(autologout_file, 'login/autologout.j2', login,                     permission=0o755, user='root', group='root') diff --git a/src/conf_mode/vpn_pptp.py b/src/conf_mode/vpn_pptp.py index 7550c411e..986a19972 100755 --- a/src/conf_mode/vpn_pptp.py +++ b/src/conf_mode/vpn_pptp.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2018-2020 VyOS maintainers and contributors +# Copyright (C) 2018-2023 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -44,6 +44,8 @@ default_pptp = {      'radius_nas_ip' : '',      'radius_source_address' : '',      'radius_shaper_attr' : '', +    'radius_shaper_enable': False, +    'radius_shaper_multiplier': '',      'radius_shaper_vendor': '',      'radius_dynamic_author' : '',      'chap_secrets_file': pptp_chap_secrets, # used in Jinja2 template @@ -183,15 +185,18 @@ def get_config(config=None):              pptp['radius_dynamic_author'] = dae +        # Rate limit +        if conf.exists(['rate-limit', 'attribute']): +            pptp['radius_shaper_attr'] = conf.return_value(['rate-limit', 'attribute']) +          if conf.exists(['rate-limit', 'enable']): -            pptp['radius_shaper_attr'] = 'Filter-Id' -            c_attr = ['rate-limit', 'enable', 'attribute'] -            if conf.exists(c_attr): -                pptp['radius_shaper_attr'] = conf.return_value(c_attr) - -            c_vendor = ['rate-limit', 'enable', 'vendor'] -            if conf.exists(c_vendor): -                pptp['radius_shaper_vendor'] = conf.return_value(c_vendor) +            pptp['radius_shaper_enable'] = True + +        if conf.exists(['rate-limit', 'multiplier']): +            pptp['radius_shaper_multiplier'] = conf.return_value(['rate-limit', 'multiplier']) + +        if conf.exists(['rate-limit', 'vendor']): +            pptp['radius_shaper_vendor'] = conf.return_value(['rate-limit', 'vendor'])      conf.set_level(base_path)      if conf.exists(['client-ip-pool']): diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/vyatta-dhclient-hook b/src/etc/dhcp/dhclient-exit-hooks.d/03-vyatta-dhclient-hook index 49bb18372..49bb18372 100644 --- a/src/etc/dhcp/dhclient-exit-hooks.d/vyatta-dhclient-hook +++ b/src/etc/dhcp/dhclient-exit-hooks.d/03-vyatta-dhclient-hook diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/99-run-user-hooks b/src/etc/dhcp/dhclient-exit-hooks.d/98-run-user-hooks index 442419d79..442419d79 100755 --- a/src/etc/dhcp/dhclient-exit-hooks.d/99-run-user-hooks +++ b/src/etc/dhcp/dhclient-exit-hooks.d/98-run-user-hooks diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/ipsec-dhclient-hook b/src/etc/dhcp/dhclient-exit-hooks.d/99-ipsec-dhclient-hook index 1f1926e17..1f1926e17 100755 --- a/src/etc/dhcp/dhclient-exit-hooks.d/ipsec-dhclient-hook +++ b/src/etc/dhcp/dhclient-exit-hooks.d/99-ipsec-dhclient-hook diff --git a/src/etc/opennhrp/opennhrp-script.py b/src/etc/opennhrp/opennhrp-script.py index bf25a7331..688c7af2a 100755 --- a/src/etc/opennhrp/opennhrp-script.py +++ b/src/etc/opennhrp/opennhrp-script.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors  #  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 or later as @@ -17,7 +17,7 @@  import os  import re  import sys -import vici +import vyos.ipsec  from json import loads  from pathlib import Path @@ -51,9 +51,8 @@ def vici_get_ipsec_uniqueid(conn: str, src_nbma: str,          logger.info(              f'Resolving IKE unique ids for: conn: {conn}, '              f'src_nbma: {src_nbma}, dst_nbma: {dst_nbma}') -        session: vici.Session = vici.Session()          list_ikeid: list[str] = [] -        list_sa = session.list_sas({'ike': conn}) +        list_sa: list = vyos.ipsec.get_vici_sas_by_name(conn, None)          for sa in list_sa:              if sa[conn]['local-host'].decode('ascii') == src_nbma \                      and sa[conn]['remote-host'].decode('ascii') == dst_nbma: @@ -78,16 +77,7 @@ def vici_ike_terminate(list_ikeid: list[str]) -> bool:          return False      try: -        session = vici.Session() -        for ikeid in list_ikeid: -            logger.info(f'Terminating IKE SA with id {ikeid}') -            session_generator = session.terminate( -                {'ike-id': ikeid, 'timeout': '-1'}) -            # a dummy `for` loop is required because of requirements -            # from vici. Without a full iteration on the output, the -            # command to vici may not be executed completely -            for _ in session_generator: -                pass +        vyos.ipsec.terminate_vici_ikeid_list(list_ikeid)          return True      except Exception as err:          logger.error(f'Failed to terminate SA for IKE ids {list_ikeid}: {err}') @@ -180,19 +170,7 @@ def vici_initiate(conn: str, child_sa: str, src_addr: str,          f'Trying to initiate connection. Name: {conn}, child sa: {child_sa}, '          f'src_addr: {src_addr}, dst_addr: {dest_addr}')      try: -        session = vici.Session() -        session_generator = session.initiate({ -            'ike': conn, -            'child': child_sa, -            'timeout': '-1', -            'my-host': src_addr, -            'other-host': dest_addr -        }) -        # a dummy `for` loop is required because of requirements -        # from vici. Without a full iteration on the output, the -        # command to vici may not be executed completely -        for _ in session_generator: -            pass +        vyos.ipsec.vici_initiate(conn, child_sa, src_addr, dest_addr)          return True      except Exception as err:          logger.error(f'Unable to initiate connection {err}') @@ -218,8 +196,11 @@ def vici_terminate(conn: str, src_addr: str, dest_addr: str) -> None:              f'No active sessions found for IKE profile {conn}, '              f'local NBMA {src_addr}, remote NBMA {dest_addr}')      else: -        vici_ike_terminate(ikeid_list) - +        try: +            vyos.ipsec.terminate_vici_ikeid_list(ikeid_list) +        except Exception as err: +            logger.error( +                f'Failed to terminate SA for IKE ids {ikeid_list}: {err}')  def iface_up(interface: str) -> None:      """Proceed tunnel interface UP event diff --git a/src/etc/systemd/system/hostapd@.service.d/override.conf b/src/etc/systemd/system/hostapd@.service.d/override.conf index bb8e81d7a..926c07f94 100644 --- a/src/etc/systemd/system/hostapd@.service.d/override.conf +++ b/src/etc/systemd/system/hostapd@.service.d/override.conf @@ -1,6 +1,8 @@  [Unit]  After=  After=vyos-router.service +ConditionFileNotEmpty= +ConditionFileNotEmpty=/run/hostapd/%i.conf  [Service]  WorkingDirectory=/run/hostapd diff --git a/src/helpers/vyos-failover.py b/src/helpers/vyos-failover.py index 0de945f20..03fb42f57 100755 --- a/src/helpers/vyos-failover.py +++ b/src/helpers/vyos-failover.py @@ -30,7 +30,7 @@ my_name = Path(__file__).stem  def is_route_exists(route, gateway, interface, metric):      """Check if route with expected gateway, dev and metric exists""" -    rc, data = rc_cmd(f'sudo ip --json route show protocol failover {route} ' +    rc, data = rc_cmd(f'ip --json route show protocol failover {route} '                        f'via {gateway} dev {interface} metric {metric}')      if rc == 0:          data = json.loads(data) @@ -72,6 +72,7 @@ def get_best_route_options(route, debug=False):                    f'best_metric: {best_metric}, best_iface: {best_interface}')          return best_gateway, best_interface, best_metric +  def is_port_open(ip, port):      """      Check connection to remote host and port @@ -91,32 +92,54 @@ def is_port_open(ip, port):      finally:          s.close() -def is_target_alive(target=None, iface='', proto='icmp', port=None, debug=False): -    """ -    Host availability check by ICMP, ARP, TCP -    Return True if target checks is successful -    % is_target_alive('192.0.2.1', 'eth1', proto='arp') -    True +def is_target_alive(target_list=None, iface='', proto='icmp', port=None, debug=False): +    """Check the availability of each target in the target_list using +    the specified protocol ICMP, ARP, TCP + +    Args: +        target_list (list): A list of IP addresses or hostnames to check. +        iface (str): The name of the network interface to use for the check. +        proto (str): The protocol to use for the check. Options are 'icmp', 'arp', or 'tcp'. +        port (int): The port number to use for the TCP check. Only applicable if proto is 'tcp'. +        debug (bool): If True, print debug information during the check. + +    Returns: +        bool: True if all targets are reachable, False otherwise. + +    Example: +        % is_target_alive(['192.0.2.1', '192.0.2.5'], 'eth1', proto='arp') +        True      """      if iface != '':          iface = f'-I {iface}' -    if proto == 'icmp': -        command = f'/usr/bin/ping -q {target} {iface} -n -c 2 -W 1' -        rc, response = rc_cmd(command) -        if debug: print(f'    [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]') -        if rc == 0: -            return True -    elif proto == 'arp': -        command = f'/usr/bin/arping -b -c 2 -f -w 1 -i 1 {iface} {target}' -        rc, response = rc_cmd(command) -        if debug: print(f'    [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]') -        if rc == 0: -            return True -    elif proto == 'tcp' and port is not None: -        return True if is_port_open(target, port) else False -    else: -        return False + +    for target in target_list: +        match proto: +            case 'icmp': +                command = f'/usr/bin/ping -q {target} {iface} -n -c 2 -W 1' +                rc, response = rc_cmd(command) +                if debug: +                    print(f'    [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]') +                if rc != 0: +                    return False + +            case 'arp': +                command = f'/usr/bin/arping -b -c 2 -f -w 1 -i 1 {iface} {target}' +                rc, response = rc_cmd(command) +                if debug: +                    print(f'    [ CHECK-TARGET ]: [{command}] -- return-code [RC: {rc}]') +                if rc != 0: +                    return False + +            case _ if proto == 'tcp' and port is not None: +                if not is_port_open(target, port): +                    return False + +            case _: +                return False + +    return True  if __name__ == '__main__': diff --git a/src/op_mode/dynamic_dns.py b/src/op_mode/dynamic_dns.py index 263a3b6a5..2cba33cc8 100755 --- a/src/op_mode/dynamic_dns.py +++ b/src/op_mode/dynamic_dns.py @@ -16,69 +16,63 @@  import os  import argparse -import jinja2  import sys  import time +from tabulate import tabulate  from vyos.config import Config  from vyos.util import call  cache_file = r'/run/ddclient/ddclient.cache' -OUT_TMPL_SRC = """ -{% for entry in hosts %} -ip address   : {{ entry.ip }} -host-name    : {{ entry.host }} -last update  : {{ entry.time }} -update-status: {{ entry.status }} +columns = { +    'host':        'Hostname', +    'ipv4':        'IPv4 address', +    'status-ipv4': 'IPv4 status', +    'ipv6':        'IPv6 address', +    'status-ipv6': 'IPv6 status', +    'mtime':       'Last update', +} + + +def _get_formatted_host_records(host_data): +    data_entries = [] +    for entry in host_data: +        data_entries.append([entry.get(key) for key in columns.keys()]) + +    header = columns.values() +    output = tabulate(data_entries, header, numalign='left') +    return output -{% endfor %} -"""  def show_status():      # A ddclient status file must not always exist      if not os.path.exists(cache_file):          sys.exit(0) -    data = { -        'hosts': [] -    } +    data = []      with open(cache_file, 'r') as f:          for line in f:              if line.startswith('#'):                  continue -            outp = { -                'host': '', -                'ip': '', -                'time': '' -            } - -            if 'host=' in line: -                host = line.split('host=')[1] -                if host: -                    outp['host'] = host.split(',')[0] - -            if 'ip=' in line: -                ip = line.split('ip=')[1] -                if ip: -                    outp['ip'] = ip.split(',')[0] - -            if 'mtime=' in line: -                mtime = line.split('mtime=')[1] -                if mtime: -                    outp['time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(mtime.split(',')[0], base=10))) +            props = {} +            # ddclient cache rows have properties in 'key=value' format separated by comma +            # we pick up the ones we are interested in +            for kvraw in line.split(' ')[0].split(','): +                k, v = kvraw.split('=') +                if k in columns.keys(): +                    props[k] = v -            if 'status=' in line: -                status = line.split('status=')[1] -                if status: -                    outp['status'] = status.split(',')[0] +            # Convert mtime to human readable format +            if 'mtime' in props: +                props['mtime'] = time.strftime( +                    "%Y-%m-%d %H:%M:%S", time.localtime(int(props['mtime'], base=10))) -            data['hosts'].append(outp) +            data.append(props) -    tmpl = jinja2.Template(OUT_TMPL_SRC) -    print(tmpl.render(data)) +    print(_get_formatted_host_records(data))  def update_ddns(): diff --git a/src/op_mode/openvpn.py b/src/op_mode/openvpn.py index 37fdbcbeb..d9ae965c5 100755 --- a/src/op_mode/openvpn.py +++ b/src/op_mode/openvpn.py @@ -16,6 +16,7 @@  #  # +import json  import os  import sys  import typing @@ -25,6 +26,7 @@ import vyos.opmode  from vyos.util import bytes_to_human  from vyos.util import commit_in_progress  from vyos.util import call +from vyos.util import rc_cmd  from vyos.config import Config  ArgMode = typing.Literal['client', 'server', 'site_to_site'] @@ -63,7 +65,7 @@ def _get_interface_status(mode: str, interface: str) -> dict:      }      if not os.path.exists(status_file): -        raise vyos.opmode.DataUnavailable('No information for interface {interface}') +        return data      with open(status_file, 'r') as f:          lines = f.readlines() @@ -142,6 +144,25 @@ def _get_interface_status(mode: str, interface: str) -> dict:      return data + +def _get_interface_state(iface): +    rc, out = rc_cmd(f'ip --json link show dev {iface}') +    try: +        data = json.loads(out) +    except: +        return 'DOWN' +    return data[0].get('operstate', 'DOWN') + + +def _get_interface_description(iface): +    rc, out = rc_cmd(f'ip --json link show dev {iface}') +    try: +        data = json.loads(out) +    except: +        return '' +    return data[0].get('ifalias', '') + +  def _get_raw_data(mode: str) -> list:      data: list = []      conf = Config() @@ -154,6 +175,8 @@ def _get_raw_data(mode: str) -> list:                    conf_dict[x]['mode'].replace('-', '_') == mode]      for intf in interfaces:          d = _get_interface_status(mode, intf) +        d['state'] = _get_interface_state(intf) +        d['description'] = _get_interface_description(intf)          d['local_host'] = conf_dict[intf].get('local-host', '')          d['local_port'] = conf_dict[intf].get('local-port', '')          if conf.exists(f'interfaces openvpn {intf} server client'): diff --git a/src/op_mode/sflow.py b/src/op_mode/sflow.py index ddb8bf44d..88f70d6bd 100755 --- a/src/op_mode/sflow.py +++ b/src/op_mode/sflow.py @@ -37,11 +37,12 @@ def _get_raw_sflow():          sflow, dbus_interface='net.sflow.hsflowd.telemetry')      agent_address = sflow_telemetry.GetAgent()      samples_dropped = int(sflow_telemetry.Get('dropped_samples')) -    samples_drop_events_sent = int(sflow_telemetry.Get('event_samples')) +    packet_drop_sent = int(sflow_telemetry.Get('event_samples'))      samples_packet_sent = int(sflow_telemetry.Get('flow_samples'))      samples_counter_sent = int(sflow_telemetry.Get('counter_samples'))      datagrams_sent = int(sflow_telemetry.Get('datagrams'))      rtmetric_samples = int(sflow_telemetry.Get('rtmetric_samples')) +    event_samples_suppressed = int(sflow_telemetry.Get('event_samples_suppressed'))      samples_suppressed = int(sflow_telemetry.Get('flow_samples_suppressed'))      counter_samples_suppressed = int(          sflow_telemetry.Get("counter_samples_suppressed")) @@ -53,10 +54,11 @@ def _get_raw_sflow():          'sflow_servers': servers,          'counter_samples_sent': samples_counter_sent,          'datagrams_sent': datagrams_sent, -        'samples_drop_events_sent': samples_drop_events_sent, +        'packet_drop_sent': packet_drop_sent,          'packet_samples_dropped': samples_dropped,          'packet_samples_sent': samples_packet_sent,          'rtmetric_samples': rtmetric_samples, +        'event_samples_suppressed': event_samples_suppressed,          'flow_samples_suppressed': samples_suppressed,          'counter_samples_suppressed': counter_samples_suppressed,          'hsflowd_version': version @@ -73,7 +75,8 @@ def _get_formatted_sflow(data):          ['Datagrams sent', f'{data.get("datagrams_sent")}'],          ['Packet samples sent', f'{data.get("packet_samples_sent")}'],          ['Packet samples dropped', f'{data.get("packet_samples_dropped")}'], -        ['Samples drop events sent', f'{data.get("samples_drop_events_sent")}'], +        ['Packet drops sent', f'{data.get("packet_drop_sent")}'], +        ['Packet drops suppressed', f'{data.get("event_samples_suppressed")}'],          ['Flow samples suppressed', f'{data.get("flow_samples_suppressed")}'],          ['Counter samples suppressed', f'{data.get("counter_samples_suppressed")}']      ] | 
