diff --git a/data/configd-include.json b/data/configd-include.json index 5a4912e30..648655a8b 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -1,88 +1,89 @@ [ "arp.py", "bcast_relay.py", "container.py", "conntrack.py", "conntrack_sync.py", "dhcp_relay.py", "dhcp_server.py", "dhcpv6_relay.py", "dhcpv6_server.py", "dns_forwarding.py", "dynamic_dns.py", "firewall.py", "flow_accounting_conf.py", "high-availability.py", "host_name.py", "https.py", "igmp_proxy.py", "intel_qat.py", "interfaces-bonding.py", "interfaces-bridge.py", "interfaces-dummy.py", "interfaces-ethernet.py", "interfaces-geneve.py", "interfaces-l2tpv3.py", "interfaces-loopback.py", "interfaces-macsec.py", "interfaces-openvpn.py", "interfaces-pppoe.py", "interfaces-pseudo-ethernet.py", +"interfaces-sstpc.py", "interfaces-tunnel.py", "interfaces-vti.py", "interfaces-vxlan.py", "interfaces-wireguard.py", "interfaces-wireless.py", "interfaces-wwan.py", "lldp.py", "nat.py", "nat66.py", "netns.py", "ntp.py", "pki.py", "policy.py", "policy-local-route.py", "protocols_bfd.py", "protocols_bgp.py", "protocols_igmp.py", "protocols_isis.py", "protocols_mpls.py", "protocols_nhrp.py", "protocols_ospf.py", "protocols_ospfv3.py", "protocols_pim.py", "protocols_rip.py", "protocols_ripng.py", "protocols_rpki.py", "protocols_static.py", "protocols_static_multicast.py", "qos.py", "salt-minion.py", "service_console-server.py", "service_ids_fastnetmon.py", "service_ipoe-server.py", "service_mdns-repeater.py", "service_monitoring_telegraf.py", "service_pppoe-server.py", "service_router-advert.py", "service_upnp.py", "ssh.py", "system-ip.py", "system-ipv6.py", "system-login-banner.py", "system-logs.py", "system-option.py", "system-proxy.py", "system_sysctl.py", "system-syslog.py", "system-timezone.py", "system_console.py", "system_lcd.py", "task_scheduler.py", "tftp_server.py", "vpn_l2tp.py", "vpn_pptp.py", "vpn_sstp.py", "vrf.py", "vrf_vni.py" ] diff --git a/data/templates/sstp-client/peer.j2 b/data/templates/sstp-client/peer.j2 new file mode 100644 index 000000000..1127d0564 --- /dev/null +++ b/data/templates/sstp-client/peer.j2 @@ -0,0 +1,46 @@ +### Autogenerated by interfaces-sstpc.py ### +{{ '# ' ~ description if description is vyos_defined else '' }} + +# Require peer to provide the local IP address if it is not +# specified explicitly in the config file. +noipdefault + +# Don't show the password in logfiles: +hide-password + +remotename {{ ifname }} +linkname {{ ifname }} +ipparam {{ ifname }} +ifname {{ ifname }} +pty "sstpc --ipparam {{ ifname }} --nolaunchpppd {{ server }}:{{ port }} --ca-cert {{ ca_file_path }}" + +# Override any connect script that may have been set in /etc/ppp/options. +connect /bin/true + +# Don't try to authenticate the remote node +noauth + +# We won't want EAP +refuse-eap + +# Don't try to proxy ARP for the remote endpoint. User can set proxy +# arp entries up manually if they wish. More importantly, having +# the "proxyarp" parameter set disables the "defaultroute" option. +noproxyarp + +# Unlimited connection attempts +maxfail 0 + +plugin sstp-pppd-plugin.so +sstp-sock /var/run/sstpc/sstpc-{{ ifname }} + +persist +debug + +{% if authentication is vyos_defined %} +{{ 'user "' + authentication.user + '"' if authentication.user is vyos_defined }} +{{ 'password "' + authentication.password + '"' if authentication.password is vyos_defined }} +{% endif %} + +{{ "usepeerdns" if no_peer_dns is not vyos_defined }} + diff --git a/interface-definitions/dns-dynamic.xml.in b/interface-definitions/dns-dynamic.xml.in index e41ba7f60..a39e412b2 100644 --- a/interface-definitions/dns-dynamic.xml.in +++ b/interface-definitions/dns-dynamic.xml.in @@ -1,291 +1,279 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="service"> <children> <node name="dns"> <properties> <help>Domain Name System related services</help> </properties> <children> <node name="dynamic" owner="${vyos_conf_scripts_dir}/dynamic_dns.py"> <properties> <help>Dynamic DNS</help> </properties> <children> <tagNode name="interface"> <properties> <help>Interface to send DDNS updates for</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> </properties> <children> <tagNode name="rfc2136"> <properties> <help>RFC2136 Update name</help> </properties> <children> <leafNode name="key"> <properties> <help>File containing the secret key shared with remote DNS server</help> <valueHelp> <format>filename</format> <description>File in /config/auth directory</description> </valueHelp> </properties> </leafNode> <leafNode name="record"> <properties> <help>Record to be updated</help> <multi/> </properties> </leafNode> <leafNode name="server"> <properties> <help>Server to be updated</help> </properties> </leafNode> <leafNode name="ttl"> <properties> <help>Time To Live (default: 600)</help> <valueHelp> <format>u32:1-86400</format> <description>DNS forwarding cache size</description> </valueHelp> <constraint> <validator name="numeric" argument="--range 1-86400"/> </constraint> </properties> <defaultValue>600</defaultValue> </leafNode> <leafNode name="zone"> <properties> <help>Zone to be updated</help> </properties> </leafNode> </children> </tagNode> <tagNode name="service"> <properties> <help>Service being used for Dynamic DNS</help> <completionHelp> <list>afraid changeip cloudflare dnspark dslreports dyndns easydns namecheap noip sitelutions zoneedit</list> </completionHelp> <valueHelp> <format>txt</format> <description>Dynanmic DNS service with a custom name</description> </valueHelp> <valueHelp> <format>afraid</format> <description>afraid.org Services</description> </valueHelp> <valueHelp> <format>changeip</format> <description>changeip.com Services</description> </valueHelp> <valueHelp> <format>cloudflare</format> <description>cloudflare.com Services</description> </valueHelp> <valueHelp> <format>dnspark</format> <description>dnspark.com Services</description> </valueHelp> <valueHelp> <format>dslreports</format> <description>dslreports.com Services</description> </valueHelp> <valueHelp> <format>dyndns</format> <description>dyndns.com Services</description> </valueHelp> <valueHelp> <format>easydns</format> <description>easydns.com Services</description> </valueHelp> <valueHelp> <format>namecheap</format> <description>namecheap.com Services</description> </valueHelp> <valueHelp> <format>noip</format> <description>noip.com Services</description> </valueHelp> <valueHelp> <format>sitelutions</format> <description>sitelutions.com Services</description> </valueHelp> <valueHelp> <format>zoneedit</format> <description>zoneedit.com Services</description> </valueHelp> <constraint> <regex>(custom|afraid|changeip|cloudflare|dnspark|dslreports|dyndns|easydns|namecheap|noip|sitelutions|zoneedit|\w+)</regex> </constraint> <constraintErrorMessage>You can use only predefined list of services or word characters (_, a-z, A-Z, 0-9) as service name</constraintErrorMessage> </properties> <children> <leafNode name="host-name"> <properties> <help>Hostname registered with DDNS service</help> <multi/> </properties> </leafNode> <leafNode name="login"> <properties> <help>Login for DDNS service</help> </properties> </leafNode> <leafNode name="password"> <properties> <help>Password for DDNS service</help> </properties> </leafNode> <leafNode name="protocol"> <properties> <help>ddclient protocol used for DDNS service</help> <completionHelp> <list>changeip cloudflare dnsmadeeasy dnspark dondominio dslreports1 dtdns duckdns dyndns2 easydns freedns freemyip googledomains hammernode1 namecheap nfsn noip sitelutions woima yandex zoneedit1</list> </completionHelp> <valueHelp> <format>changeip</format> <description>ChangeIP protocol</description> </valueHelp> <valueHelp> <format>cloudflare</format> <description>Cloudflare protocol</description> </valueHelp> <valueHelp> <format>dnsmadeeasy</format> <description>DNS Made Easy protocol</description> </valueHelp> <valueHelp> <format>dnspark</format> <description>DNS Park protocol</description> </valueHelp> <valueHelp> <format>dondominio</format> <description>DonDominio protocol</description> </valueHelp> <valueHelp> <format>dslreports1</format> <description>DslReports protocol</description> </valueHelp> <valueHelp> <format>dtdns</format> <description>DtDNS protocol</description> </valueHelp> <valueHelp> <format>duckdns</format> <description>DuckDNS protocol</description> </valueHelp> <valueHelp> <format>dyndns2</format> <description>DynDNS protocol v2</description> </valueHelp> <valueHelp> <format>easydns</format> <description>easyDNS protocol</description> </valueHelp> <valueHelp> <format>freedns</format> <description>FreeDNS protocol</description> </valueHelp> <valueHelp> <format>freemyip</format> <description>freemyip protocol</description> </valueHelp> <valueHelp> <format>googledomains</format> <description>Google domains protocol</description> </valueHelp> <valueHelp> <format>hammernode1</format> <description>Hammernode protocol</description> </valueHelp> <valueHelp> <format>namecheap</format> <description>Namecheap protocol</description> </valueHelp> <valueHelp> <format>nfsn</format> <description>NearlyFreeSpeech DNS protocol</description> </valueHelp> <valueHelp> <format>noip</format> <description>No-IP protocol</description> </valueHelp> <valueHelp> <format>sitelutions</format> <description>Sitelutions protocol</description> </valueHelp> <valueHelp> <format>woima</format> <description>WOIMA protocol</description> </valueHelp> <valueHelp> <format>yandex</format> <description>Yandex.DNS protocol</description> </valueHelp> <valueHelp> <format>zoneedit1</format> <description>Zoneedit protocol</description> </valueHelp> <constraint> <regex>(changeip|cloudflare|dnsmadeeasy|dnspark|dondominio|dslreports1|dtdns|duckdns|dyndns2|easydns|freedns|freemyip|googledomains|hammernode1|namecheap|nfsn|noip|sitelutions|woima|yandex|zoneedit1)</regex> </constraint> <constraintErrorMessage>Please choose from the list of allowed protocols</constraintErrorMessage> </properties> </leafNode> - <leafNode name="server"> - <properties> - <help>Server to send DDNS update to</help> - <valueHelp> - <format>IPv4</format> - <description>IP address of DDNS server</description> - </valueHelp> - <valueHelp> - <format>FQDN</format> - <description>Hostname of DDNS server</description> - </valueHelp> - </properties> - </leafNode> + #include <include/server-ipv4-fqdn.xml.i> <leafNode name="zone"> <properties> <help>DNS zone to update (only available with CloudFlare)</help> </properties> </leafNode> </children> </tagNode> <node name="use-web"> <properties> <help>Web check used for obtaining the external IP address</help> </properties> <children> <leafNode name="skip"> <properties> <help>Skip everything before this on the given URL</help> </properties> </leafNode> <leafNode name="url"> <properties> <help>URL to obtain the current external IP address</help> </properties> </leafNode> </children> </node> <leafNode name="ipv6-enable"> <properties> <help>Allow explicit IPv6 addresses for Dynamic DNS for this interface</help> <valueless/> </properties> </leafNode> </children> </tagNode> </children> </node> </children> </node> </children> </node> </interfaceDefinition> diff --git a/interface-definitions/include/interface/no-peer-dns.xml.i b/interface-definitions/include/interface/no-peer-dns.xml.i new file mode 100644 index 000000000..d663f04c1 --- /dev/null +++ b/interface-definitions/include/interface/no-peer-dns.xml.i @@ -0,0 +1,8 @@ +<!-- include start from interface/no-peer-dns.xml.i --> +<leafNode name="no-peer-dns"> + <properties> + <help>Do not use DNS servers provided by the peer</help> + <valueless/> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/server-ipv4-fqdn.xml.i b/interface-definitions/include/server-ipv4-fqdn.xml.i new file mode 100644 index 000000000..7bab9812c --- /dev/null +++ b/interface-definitions/include/server-ipv4-fqdn.xml.i @@ -0,0 +1,15 @@ +<!-- include start from server-ipv4-fqdn.xml.i --> +<leafNode name="server"> + <properties> + <help>Remote server to connect to</help> + <valueHelp> + <format>ipv4</format> + <description>Server IPv4 address</description> + </valueHelp> + <valueHelp> + <format>hostname</format> + <description>Server hostname/FQDN</description> + </valueHelp> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in index 719060fa9..35c4889ea 100644 --- a/interface-definitions/interfaces-pppoe.xml.in +++ b/interface-definitions/interfaces-pppoe.xml.in @@ -1,118 +1,113 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="interfaces"> <children> <tagNode name="pppoe" owner="${vyos_conf_scripts_dir}/interfaces-pppoe.py"> <properties> <help>Point-to-Point Protocol over Ethernet (PPPoE) Interface</help> <priority>322</priority> <constraint> <regex>pppoe[0-9]+</regex> </constraint> <constraintErrorMessage>PPPoE interface must be named pppoeN</constraintErrorMessage> <valueHelp> <format>pppoeN</format> <description>PPPoE dialer interface name</description> </valueHelp> </properties> <children> #include <include/pppoe-access-concentrator.xml.i> #include <include/interface/authentication.xml.i> #include <include/interface/dial-on-demand.xml.i> #include <include/interface/no-default-route.xml.i> #include <include/interface/default-route-distance.xml.i> #include <include/interface/dhcpv6-options.xml.i> #include <include/interface/description.xml.i> #include <include/interface/disable.xml.i> <leafNode name="idle-timeout"> <properties> <help>Delay before disconnecting idle session (in seconds)</help> <valueHelp> <format>u32:0-86400</format> <description>Idle timeout in seconds</description> </valueHelp> <constraint> <validator name="numeric" argument="--range 0-86400"/> </constraint> <constraintErrorMessage>Timeout must be in range 0 to 86400</constraintErrorMessage> </properties> </leafNode> <node name="ip"> <properties> <help>IPv4 routing parameters</help> </properties> <children> #include <include/interface/adjust-mss.xml.i> #include <include/interface/disable-forwarding.xml.i> #include <include/interface/source-validation.xml.i> </children> </node> <node name="ipv6"> <properties> <help>IPv6 routing parameters</help> </properties> <children> <node name="address"> <properties> <help>IPv6 address configuration modes</help> </properties> <children> #include <include/interface/ipv6-address-autoconf.xml.i> </children> </node> #include <include/interface/adjust-mss.xml.i> #include <include/interface/disable-forwarding.xml.i> </children> </node> #include <include/source-interface.xml.i> <leafNode name="local-address"> <properties> <help>IPv4 address of local end of the PPPoE link</help> <valueHelp> <format>ipv4</format> <description>Address of local end of the PPPoE link</description> </valueHelp> <constraint> <validator name="ipv4-address"/> </constraint> </properties> </leafNode> #include <include/interface/mirror.xml.i> #include <include/interface/mtu-68-1500.xml.i> <leafNode name="mtu"> <defaultValue>1492</defaultValue> </leafNode> - <leafNode name="no-peer-dns"> - <properties> - <help>Do not use DNS servers provided by the peer</help> - <valueless/> - </properties> - </leafNode> + #include <include/interface/no-peer-dns.xml.i> <leafNode name="remote-address"> <properties> <help>IPv4 address of remote end of the PPPoE link</help> <valueHelp> <format>ipv4</format> <description>Address of remote end of the PPPoE link</description> </valueHelp> <constraint> <validator name="ipv4-address"/> </constraint> </properties> </leafNode> <leafNode name="service-name"> <properties> <help>Service name, only connect to access concentrators advertising this</help> <constraint> <regex>[a-zA-Z0-9]+</regex> </constraint> <constraintErrorMessage>Service name must be alphanumeric only</constraintErrorMessage> </properties> </leafNode> #include <include/interface/redirect.xml.i> #include <include/interface/vrf.xml.i> </children> </tagNode> </children> </node> </interfaceDefinition> diff --git a/interface-definitions/interfaces-sstpc.xml.in b/interface-definitions/interfaces-sstpc.xml.in new file mode 100644 index 000000000..30b55a9fa --- /dev/null +++ b/interface-definitions/interfaces-sstpc.xml.in @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="interfaces"> + <children> + <tagNode name="sstpc" owner="${vyos_conf_scripts_dir}/interfaces-sstpc.py"> + <properties> + <help>Secure Socket Tunneling Protocol (SSTP) client Interface</help> + <priority>460</priority> + <constraint> + <regex>sstpc[0-9]+</regex> + </constraint> + <constraintErrorMessage>Secure Socket Tunneling Protocol interface must be named sstpcN</constraintErrorMessage> + <valueHelp> + <format>sstpcN</format> + <description>Secure Socket Tunneling Protocol interface name</description> + </valueHelp> + </properties> + <children> + #include <include/interface/description.xml.i> + #include <include/interface/disable.xml.i> + #include <include/interface/authentication.xml.i> + #include <include/interface/no-default-route.xml.i> + #include <include/interface/default-route-distance.xml.i> + #include <include/interface/no-peer-dns.xml.i> + #include <include/interface/mtu-68-1500.xml.i> + <leafNode name="mtu"> + <defaultValue>1452</defaultValue> + </leafNode> + #include <include/server-ipv4-fqdn.xml.i> + #include <include/port-number.xml.i> + <leafNode name="port"> + <defaultValue>443</defaultValue> + </leafNode> + <node name="ssl"> + <properties> + <help>Secure Sockets Layer (SSL) configuration</help> + </properties> + <children> + #include <include/pki/ca-certificate.xml.i> + </children> + </node> + #include <include/interface/vrf.xml.i> + </children> + </tagNode> + </children> + </node> +</interfaceDefinition> diff --git a/op-mode-definitions/connect.xml.in b/op-mode-definitions/connect.xml.in index d0c93195c..116cd6231 100644 --- a/op-mode-definitions/connect.xml.in +++ b/op-mode-definitions/connect.xml.in @@ -1,30 +1,31 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="connect"> <properties> <help>Establish connection</help> </properties> <children> <tagNode name="console"> <properties> <help>Connect to device attached to serial console server</help> <completionHelp> <path>service console-server device</path> <script>${vyos_completion_dir}/list_consoles.sh</script> </completionHelp> </properties> <command>/usr/bin/console "$3"</command> </tagNode> <tagNode name="interface"> <properties> <help>Bring up a connection-oriented network interface</help> <completionHelp> <path>interfaces pppoe</path> + <path>interfaces sstpc</path> <path>interfaces wwan</path> </completionHelp> </properties> <command>sudo ${vyos_op_scripts_dir}/connect_disconnect.py --connect "$3"</command> </tagNode> </children> </node> </interfaceDefinition> diff --git a/op-mode-definitions/disconnect.xml.in b/op-mode-definitions/disconnect.xml.in index 4415c0ed2..843998c4f 100644 --- a/op-mode-definitions/disconnect.xml.in +++ b/op-mode-definitions/disconnect.xml.in @@ -1,20 +1,21 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="disconnect"> <properties> <help>Take down a connection</help> </properties> <children> <tagNode name="interface"> <properties> <help>Take down a connection-oriented network interface</help> <completionHelp> <path>interfaces pppoe</path> + <path>interfaces sstpc</path> <path>interfaces wwan</path> </completionHelp> </properties> <command>sudo ${vyos_op_scripts_dir}/connect_disconnect.py --disconnect "$3"</command> </tagNode> </children> </node> </interfaceDefinition> diff --git a/op-mode-definitions/monitor-log.xml.in b/op-mode-definitions/monitor-log.xml.in index dccdfaf9a..1b1f53dc2 100644 --- a/op-mode-definitions/monitor-log.xml.in +++ b/op-mode-definitions/monitor-log.xml.in @@ -1,268 +1,285 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="monitor"> <children> <node name="log"> <properties> <help>Monitor last lines of messages file</help> </properties> <command>journalctl --no-hostname --follow --boot</command> <children> <node name="color"> <properties> <help>Output log in a colored fashion</help> </properties> <command>grc journalctl --no-hostname --follow --boot</command> </node> <node name="ids"> <properties> <help>Monitor log for Intrusion Detection System</help> </properties> <children> <leafNode name="ddos-protection"> <properties> <help>Monitor last lines of DDOS protection</help> </properties> <command>journalctl --no-hostname --follow --boot --unit fastnetmon.service</command> </leafNode> </children> </node> <node name="dhcp"> <properties> <help>Monitor last lines of Dynamic Host Control Protocol (DHCP)</help> </properties> <children> <node name="server"> <properties> <help>Monitor last lines of DHCP server</help> </properties> <command>journalctl --no-hostname --follow --boot --unit isc-dhcp-server.service</command> </node> <node name="client"> <properties> <help>Monitor last lines of DHCP client</help> </properties> <command>journalctl --no-hostname --follow --boot --unit "dhclient@*.service"</command> <children> <tagNode name="interface"> <properties> <help>Show DHCP client log on specific interface</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script> </completionHelp> </properties> <command>journalctl --no-hostname --follow --boot --unit "dhclient@$6.service"</command> </tagNode> </children> </node> </children> </node> <node name="dhcpv6"> <properties> <help>Monitor last lines of Dynamic Host Control Protocol IPv6 (DHCPv6)</help> </properties> <children> <node name="server"> <properties> <help>Monitor last lines of DHCPv6 server</help> </properties> <command>journalctl --no-hostname --follow --boot --unit isc-dhcp-server6.service</command> </node> <node name="client"> <properties> <help>Monitor last lines of DHCPv6 client</help> </properties> <command>journalctl --no-hostname --follow --boot --unit "dhcp6c@*.service"</command> <children> <tagNode name="interface"> <properties> <help>Show DHCPv6 client log on specific interface</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> </properties> <command>journalctl --no-hostname --follow --boot --unit "dhcp6c@$6.service"</command> </tagNode> </children> </node> </children> </node> <leafNode name="flow-accounting"> <properties> <help>Monitor last lines of flow-accounting log</help> </properties> <command>journalctl --no-hostname --boot --follow --unit uacctd.service</command> </leafNode> <leafNode name="kernel"> <properties> <help>Monitor last lines of Linux Kernel log</help> </properties> <command>journalctl --no-hostname --boot --follow --dmesg</command> </leafNode> <leafNode name="nhrp"> <properties> <help>Monitor last lines of NHRP log</help> </properties> <command>journalctl --no-hostname --boot --unit opennhrp.service</command> </leafNode> <node name="pppoe"> <properties> <help>Monitor last lines of PPPoE log</help> </properties> <command>journalctl --no-hostname --boot --follow --unit "ppp@pppoe*.service"</command> <children> <tagNode name="interface"> <properties> <help>Monitor last lines of PPPoE log for specific interface</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py -t pppoe</script> </completionHelp> </properties> <command>journalctl --no-hostname --boot --follow --unit "ppp@$5.service"</command> </tagNode> </children> </node> <node name="protocol"> <properties> <help>Monitor log for Routing Protocol</help> </properties> <children> <leafNode name="ospf"> <properties> <help>Monitor log for OSPF</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/ospfd</command> </leafNode> <leafNode name="ospfv3"> <properties> <help>Monitor log for OSPF for IPv6</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/ospf6d</command> </leafNode> <leafNode name="bgp"> <properties> <help>Monitor log for BGP</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/bgpd</command> </leafNode> <leafNode name="rip"> <properties> <help>Monitor log for RIP</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/ripd</command> </leafNode> <leafNode name="ripng"> <properties> <help>Monitor log for RIPng</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/ripngd</command> </leafNode> <leafNode name="static"> <properties> <help>Monitor log for static route</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/staticd</command> </leafNode> <leafNode name="multicast"> <properties> <help>Monitor log for Multicast protocol</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/pimd</command> </leafNode> <leafNode name="isis"> <properties> <help>Monitor log for ISIS</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/isisd</command> </leafNode> <leafNode name="nhrp"> <properties> <help>Monitor log for NHRP</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/nhrpd</command> </leafNode> <leafNode name="bfd"> <properties> <help>Monitor log for BFD</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/bfdd</command> </leafNode> <leafNode name="mpls"> <properties> <help>Monitor log for MPLS</help> </properties> <command>journalctl --follow --no-hostname --boot /usr/lib/frr/ldpd</command> </leafNode> </children> </node> <node name="macsec"> <properties> <help>Monitor last lines of MACsec</help> </properties> <command>journalctl --no-hostname --boot --follow --unit "wpa_supplicant-macsec@*.service"</command> <children> <tagNode name="interface"> <properties> <help>Monitor last lines of specific MACsec interface</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py -t macsec</script> </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> </tagNode> </children> </node> <leafNode name="snmp"> <properties> <help>Monitor last lines of Simple Network Monitoring Protocol (SNMP)</help> </properties> <command>journalctl --no-hostname --boot --follow --unit snmpd.service</command> </leafNode> <leafNode name="ssh"> <properties> <help>Monitor last lines of Secure Shell (SSH)</help> </properties> <command>journalctl --no-hostname --boot --follow --unit ssh.service</command> </leafNode> + <node name="sstpc"> + <properties> + <help>Monitor last lines of SSTP client log</help> + </properties> + <command>journalctl --no-hostname --boot --follow --unit "ppp@sstpc*.service"</command> + <children> + <tagNode name="interface"> + <properties> + <help>Monitor last lines of SSTP client log for specific interface</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py -t sstpc</script> + </completionHelp> + </properties> + <command>journalctl --no-hostname --boot --follow --unit "ppp@$5.service"</command> + </tagNode> + </children> + </node> <node name="vpn"> <properties> <help>Show log for Virtual Private Network (VPN)</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> </leafNode> <leafNode name="ipsec"> <properties> <help>Monitor last lines of IPsec</help> </properties> <command>journalctl --no-hostname --boot --follow --unit strongswan-starter.service</command> </leafNode> <leafNode name="l2tp"> <properties> <help>Monitor last lines of L2TP</help> </properties> <command>journalctl --no-hostname --boot --follow --unit accel-ppp@l2tp.service</command> </leafNode> <leafNode name="pptp"> <properties> <help>Monitor last lines of PPTP</help> </properties> <command>journalctl --no-hostname --boot --follow --unit accel-ppp@pptp.service</command> </leafNode> <leafNode name="sstp"> <properties> <help>Monitor last lines of SSTP</help> </properties> <command>journalctl --no-hostname --boot --follow --unit accel-ppp@sstp.service</command> </leafNode> </children> </node> </children> </node> </children> </node> </interfaceDefinition> diff --git a/op-mode-definitions/show-interfaces-sstpc.xml.in b/op-mode-definitions/show-interfaces-sstpc.xml.in new file mode 100644 index 000000000..e66d3a0ac --- /dev/null +++ b/op-mode-definitions/show-interfaces-sstpc.xml.in @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="show"> + <children> + <node name="interfaces"> + <children> + <tagNode name="sstpc"> + <properties> + <help>Show specified SSTP client interface information</help> + <completionHelp> + <path>interfaces sstpc</path> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/show_interfaces.py --intf="$4"</command> + <children> + <leafNode name="log"> + <properties> + <help>Show specified SSTP client interface log</help> + </properties> + <command>journalctl --no-hostname --boot --follow --unit "ppp@$4".service</command> + </leafNode> + <leafNode name="statistics"> + <properties> + <help>Show specified SSTP client interface statistics</help> + <completionHelp> + <path>interfaces sstpc</path> + </completionHelp> + </properties> + <command>if [ -d "/sys/class/net/$4" ]; then /usr/sbin/pppstats "$4"; fi</command> + </leafNode> + </children> + </tagNode> + <node name="sstpc"> + <properties> + <help>Show SSTP client interface information</help> + </properties> + <command>${vyos_op_scripts_dir}/show_interfaces.py --intf-type=sstpc --action=show-brief</command> + <children> + <leafNode name="detail"> + <properties> + <help>Show detailed SSTP client interface information</help> + </properties> + <command>${vyos_op_scripts_dir}/show_interfaces.py --intf-type=sstpc --action=show</command> + </leafNode> + </children> + </node> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 404de1913..64a54015b 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -1,427 +1,444 @@ <?xml version="1.0"?> <interfaceDefinition> <node name="show"> <children> <node name="log"> <properties> <help>Show contents of current master log file</help> </properties> <command>journalctl --no-hostname --boot</command> <children> <leafNode name="all"> <properties> <help>Show contents of all master log files</help> </properties> <command>sudo bash -c 'eval $(lesspipe); less $_vyatta_less_options --prompt=".logm, file %i of %m., page %dt of %D" -- `printf "%s\n" /var/log/messages* | sort -nr`'</command> </leafNode> <leafNode name="authorization"> <properties> <help>Show listing of authorization attempts</help> </properties> <command>journalctl --no-hostname --boot --quiet SYSLOG_FACILITY=10 SYSLOG_FACILITY=4</command> </leafNode> <leafNode name="cluster"> <properties> <help>Show log for Cluster</help> </properties> <command>cat $(printf "%s\n" /var/log/messages* | sort -nr) | grep -e heartbeat -e cl_status -e mach_down -e ha_log</command> </leafNode> <leafNode name="conntrack-sync"> <properties> <help>Show log for Conntrack-sync</help> </properties> <command>journalctl --no-hostname --boot --unit conntrackd.service</command> </leafNode> <node name="ids"> <properties> <help>Show log for for Intrusion Detection System</help> </properties> <children> <leafNode name="ddos-protection"> <properties> <help>Show log for DDOS protection</help> </properties> <command>journalctl --no-hostname --boot --unit fastnetmon.service</command> </leafNode> </children> </node> <node name="dhcp"> <properties> <help>Show log for Dynamic Host Control Protocol (DHCP)</help> </properties> <children> <node name="server"> <properties> <help>Show log for DHCP server</help> </properties> <command>journalctl --no-hostname --boot --unit isc-dhcp-server.service</command> </node> <node name="client"> <properties> <help>Show DHCP client logs</help> </properties> <command>journalctl --no-hostname --boot --unit "dhclient@*.service"</command> <children> <tagNode name="interface"> <properties> <help>Show DHCP client log on specific interface</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py --broadcast</script> </completionHelp> </properties> <command>journalctl --no-hostname --boot --unit "dhclient@$6.service"</command> </tagNode> </children> </node> </children> </node> <node name="dhcpv6"> <properties> <help>Show log for Dynamic Host Control Protocol IPv6 (DHCPv6)</help> </properties> <children> <node name="server"> <properties> <help>Show log for DHCPv6 server</help> </properties> <command>journalctl --no-hostname --boot --unit isc-dhcp-server6.service</command> </node> <node name="client"> <properties> <help>Show DHCPv6 client logs</help> </properties> <command>journalctl --no-hostname --boot --unit "dhcp6c@*.service"</command> <children> <tagNode name="interface"> <properties> <help>Show DHCPv6 client log on specific interface</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py</script> </completionHelp> </properties> <command>journalctl --no-hostname --boot --unit "dhcp6c@$6.service"</command> </tagNode> </children> </node> </children> </node> <node name="firewall"> <properties> <help>Show log for Firewall</help> </properties> <children> <tagNode name="ipv6-name"> <properties> <help>Show log for a specified firewall (IPv6)</help> <completionHelp> <path>firewall ipv6-name</path> </completionHelp> </properties> <command>cat $(printf "%s\n" /var/log/messages* | sort -nr ) | egrep "\[$5-([0-9]+|default)-[ADR]\]"</command> <children> <tagNode name="rule"> <properties> <help>Show log for a rule in the specified firewall</help> <completionHelp> <path>firewall ipv6-name ${COMP_WORDS[4]} rule</path> </completionHelp> </properties> <command>cat $(printf "%s\n" /var/log/messages* | sort -nr) | grep -e "\[$5-$7-[ADR]\]"</command> </tagNode> </children> </tagNode> <tagNode name="name"> <properties> <help>Show log for a specified firewall (IPv4)</help> <completionHelp> <path>firewall name</path> </completionHelp> </properties> <command>cat $(printf "%s\n" /var/log/messages* | sort -nr ) | egrep "\[$5-([0-9]+|default)-[ADR]\]"</command> <children> <tagNode name="rule"> <properties> <help>Show log for a rule in the specified firewall</help> <completionHelp> <path>firewall name ${COMP_WORDS[4]} rule</path> </completionHelp> </properties> <command>cat $(printf "%s\n" /var/log/messages* | sort -nr) | egrep "\[$5-$7-[ADR]\]"</command> </tagNode> </children> </tagNode> </children> </node> <leafNode name="flow-accounting"> <properties> <help>Show log for flow-accounting</help> </properties> <command>journalctl --no-hostname --boot --unit uacctd.service</command> </leafNode> <leafNode name="https"> <properties> <help>Show log for HTTPs</help> </properties> <command>journalctl --no-hostname --boot --unit nginx.service</command> </leafNode> <tagNode name="image"> <properties> <help>Show contents of master log file for image</help> <completionHelp> <script>compgen -f /lib/live/mount/persistence/boot/ | grep -v grub | sed -e s@/lib/live/mount/persistence/boot/@@</script> </completionHelp> </properties> <command>less $_vyatta_less_options --prompt=".log, page %dt of %D" -- /lib/live/mount/persistence/boot/$4/rw/var/log/messages</command> <children> <leafNode name="all"> <properties> <help>Show contents of all master log files for image</help> </properties> <command>eval $(lesspipe); less $_vyatta_less_options --prompt=".log?m, file %i of %m., page %dt of %D" -- `printf "%s\n" /lib/live/mount/persistence/boot/$4/rw/var/log/messages* | sort -nr`</command> </leafNode> <leafNode name="authorization"> <properties> <help>Show listing of authorization attempts for image</help> </properties> <command>less $_vyatta_less_options --prompt=".log, page %dt of %D" -- /lib/live/mount/persistence/boot/$4/rw/var/log/auth.log</command> </leafNode> <tagNode name="tail"> <properties> <help>Show last changes to messages</help> <completionHelp> <list><NUMBER></list> </completionHelp> </properties> <command>tail -n "$6" /lib/live/mount/persistence/boot/$4/rw/var/log/messages | ${VYATTA_PAGER:-cat}</command> </tagNode> </children> </tagNode> <leafNode name="kernel"> <properties> <help>Show log for Linux Kernel</help> </properties> <command>journalctl --no-hostname --boot --dmesg</command> </leafNode> <leafNode name="lldp"> <properties> <help>Show log for LLDP</help> </properties> <command>journalctl --no-hostname --boot --unit lldpd.service</command> </leafNode> <leafNode name="nat"> <properties> <help>Show log for Network Address Translation (NAT)</help> </properties> <command>egrep -i "kernel:.*\[NAT-[A-Z]{3,}-[0-9]+(-MASQ)?\]" $(find /var/log -maxdepth 1 -type f -name messages\* | sort -t. -k2nr)</command> </leafNode> <leafNode name="nhrp"> <properties> <help>Show log for NHRP</help> </properties> <command>journalctl --no-hostname --boot --unit opennhrp.service</command> </leafNode> <node name="macsec"> <properties> <help>Show log for MACsec</help> </properties> <command>journalctl --no-hostname --boot --unit "wpa_supplicant-macsec@*.service"</command> <children> <tagNode name="interface"> <properties> <help>Show MACsec log on specific interface</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py -t macsec</script> </completionHelp> </properties> <command>SRC=$(cli-shell-api returnValue interfaces macsec "$5" source-interface); journalctl --no-hostname --boot --unit "wpa_supplicant-macsec@$SRC.service"</command> </tagNode> </children> </node> <node name="openvpn"> <properties> <help>Show log for OpenVPN</help> </properties> <command>journalctl --no-hostname --boot --unit openvpn@*.service</command> <children> <tagNode name="interface"> <properties> <help>Show OpenVPN log on specific interface</help> <completionHelp> <path>interfaces openvpn</path> </completionHelp> </properties> <command>journalctl --no-hostname --boot --unit openvpn@$5.service</command> </tagNode> </children> </node> <node name="pppoe"> <properties> <help>Show log for PPPoE</help> </properties> <command>journalctl --no-hostname --boot --unit "ppp@pppoe*.service"</command> <children> <tagNode name="interface"> <properties> <help>Show PPPoE log on specific interface</help> <completionHelp> <script>${vyos_completion_dir}/list_interfaces.py -t pppoe</script> </completionHelp> </properties> <command>journalctl --no-hostname --boot --unit "ppp@$5.service"</command> </tagNode> </children> </node> <node name="protocol"> <properties> <help>Show log for Routing Protocol</help> </properties> <children> <leafNode name="ospf"> <properties> <help>Show log for OSPF</help> </properties> <command>journalctl --boot /usr/lib/frr/ospfd</command> </leafNode> <leafNode name="ospfv3"> <properties> <help>Show log for OSPF for IPv6</help> </properties> <command>journalctl --boot /usr/lib/frr/ospf6d</command> </leafNode> <leafNode name="bgp"> <properties> <help>Show log for BGP</help> </properties> <command>journalctl --boot /usr/lib/frr/bgpd</command> </leafNode> <leafNode name="rip"> <properties> <help>Show log for RIP</help> </properties> <command>journalctl --boot /usr/lib/frr/ripd</command> </leafNode> <leafNode name="ripng"> <properties> <help>Show log for RIPng</help> </properties> <command>journalctl --boot /usr/lib/frr/ripngd</command> </leafNode> <leafNode name="static"> <properties> <help>Show log for static route</help> </properties> <command>journalctl --boot /usr/lib/frr/staticd</command> </leafNode> <leafNode name="multicast"> <properties> <help>Show log for Multicast protocol</help> </properties> <command>journalctl --boot /usr/lib/frr/pimd</command> </leafNode> <leafNode name="isis"> <properties> <help>Show log for ISIS</help> </properties> <command>journalctl --boot /usr/lib/frr/isisd</command> </leafNode> <leafNode name="nhrp"> <properties> <help>Show log for NHRP</help> </properties> <command>journalctl --boot /usr/lib/frr/nhrpd</command> </leafNode> <leafNode name="bfd"> <properties> <help>Show log for BFD</help> </properties> <command>journalctl --boot /usr/lib/frr/bfdd</command> </leafNode> <leafNode name="mpls"> <properties> <help>Show log for MPLS</help> </properties> <command>journalctl --boot /usr/lib/frr/ldpd</command> </leafNode> </children> </node> <leafNode name="snmp"> <properties> <help>Show log for Simple Network Monitoring Protocol (SNMP)</help> </properties> <command>journalctl --no-hostname --boot --unit snmpd.service</command> </leafNode> <leafNode name="ssh"> <properties> <help>Show log for Secure Shell (SSH)</help> </properties> <command>journalctl --no-hostname --boot --unit ssh.service</command> </leafNode> + <node name="sstpc"> + <properties> + <help>Show log for SSTP client</help> + </properties> + <command>journalctl --no-hostname --boot --unit "ppp@sstpc*.service"</command> + <children> + <tagNode name="interface"> + <properties> + <help>Show SSTP client log on specific interface</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py -t sstpc</script> + </completionHelp> + </properties> + <command>journalctl --no-hostname --boot --unit "ppp@$5.service"</command> + </tagNode> + </children> + </node> <tagNode name="tail"> <properties> <help>Show last n changes to messages</help> <completionHelp> <list><NUMBER></list> </completionHelp> </properties> <command>tail -n "$4" /var/log/messages | ${VYATTA_PAGER:-cat}</command> </tagNode> <node name="tail"> <properties> <help>Show last 10 lines of /var/log/messages file</help> </properties> <command>tail -n 10 /var/log/messages</command> </node> <node name="vpn"> <properties> <help>Show log for Virtual Private Network (VPN)</help> </properties> <children> <leafNode name="all"> <properties> <help>Show log for ALL</help> </properties> <command>journalctl --no-hostname --boot --unit strongswan-starter.service --unit accel-ppp@*.service</command> </leafNode> <leafNode name="ipsec"> <properties> <help>Show log for IPsec</help> </properties> <command>journalctl --no-hostname --boot --unit strongswan-starter.service</command> </leafNode> <leafNode name="l2tp"> <properties> <help>Show log for L2TP</help> </properties> <command>journalctl --no-hostname --boot --unit accel-ppp@l2tp.service</command> </leafNode> <leafNode name="pptp"> <properties> <help>Show log for PPTP</help> </properties> <command>journalctl --no-hostname --boot --unit accel-ppp@pptp.service</command> </leafNode> <leafNode name="sstp"> <properties> <help>Show log for SSTP</help> </properties> <command>journalctl --no-hostname --boot --unit accel-ppp@sstp.service</command> </leafNode> </children> </node> <leafNode name="vrrp"> <properties> <help>Show log for Virtual Router Redundancy Protocol (VRRP)</help> </properties> <command>journalctl --no-hostname --boot --unit keepalived.service</command> </leafNode> <leafNode name="webproxy"> <properties> <help>Show log for Webproxy</help> </properties> <command>journalctl --no-hostname --boot --unit squid.service</command> </leafNode> </children> </node> </children> </node> </interfaceDefinition> diff --git a/python/vyos/ifconfig/__init__.py b/python/vyos/ifconfig/__init__.py index d1ddaa13e..206b2bba1 100644 --- a/python/vyos/ifconfig/__init__.py +++ b/python/vyos/ifconfig/__init__.py @@ -1,40 +1,41 @@ -# Copyright 2019-2021 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see <http://www.gnu.org/licenses/>. from vyos.ifconfig.section import Section from vyos.ifconfig.control import Control from vyos.ifconfig.interface import Interface from vyos.ifconfig.operational import Operational from vyos.ifconfig.vrrp import VRRP from vyos.ifconfig.bond import BondIf from vyos.ifconfig.bridge import BridgeIf from vyos.ifconfig.dummy import DummyIf from vyos.ifconfig.ethernet import EthernetIf from vyos.ifconfig.geneve import GeneveIf from vyos.ifconfig.loopback import LoopbackIf from vyos.ifconfig.macvlan import MACVLANIf from vyos.ifconfig.input import InputIf from vyos.ifconfig.vxlan import VXLANIf from vyos.ifconfig.wireguard import WireGuardIf from vyos.ifconfig.vtun import VTunIf from vyos.ifconfig.vti import VTIIf from vyos.ifconfig.pppoe import PPPoEIf from vyos.ifconfig.tunnel import TunnelIf from vyos.ifconfig.wireless import WiFiIf from vyos.ifconfig.l2tpv3 import L2TPv3If from vyos.ifconfig.macsec import MACsecIf from vyos.ifconfig.veth import VethIf from vyos.ifconfig.wwan import WWANIf +from vyos.ifconfig.sstpc import SSTPCIf diff --git a/python/vyos/ifconfig/sstpc.py b/python/vyos/ifconfig/sstpc.py new file mode 100644 index 000000000..50fc6ee6b --- /dev/null +++ b/python/vyos/ifconfig/sstpc.py @@ -0,0 +1,40 @@ +# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see <http://www.gnu.org/licenses/>. + +from vyos.ifconfig.interface import Interface + +@Interface.register +class SSTPCIf(Interface): + iftype = 'sstpc' + definition = { + **Interface.definition, + **{ + 'section': 'sstpc', + 'prefixes': ['sstpc', ], + 'eternal': 'sstpc[0-9]+$', + }, + } + + def _create(self): + # we can not create this interface as it is managed outside + pass + + def _delete(self): + # we can not create this interface as it is managed outside + pass + + def get_mac(self): + """ Get a synthetic MAC address. """ + return self.get_mac_synthetic() diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py index e2fdc7a42..ee4defa0d 100755 --- a/src/conf_mode/interfaces-pppoe.py +++ b/src/conf_mode/interfaces-pppoe.py @@ -1,137 +1,136 @@ #!/usr/bin/env python3 # # Copyright (C) 2019-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 os from sys import exit from copy import deepcopy from netifaces import interfaces from vyos.config import Config from vyos.configdict import get_interface_dict from vyos.configdict import is_node_changed -from vyos.configdict import leaf_node_changed from vyos.configdict import get_pppoe_interfaces from vyos.configverify import verify_authentication from vyos.configverify import verify_source_interface from vyos.configverify import verify_interface_exists from vyos.configverify import verify_vrf from vyos.configverify import verify_mtu_ipv6 from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import PPPoEIf from vyos.template import render from vyos.util import call from vyos.util import is_systemd_service_running 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', 'pppoe'] ifname, pppoe = get_interface_dict(conf, base) # We should only terminate the PPPoE session if critical parameters change. # 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']: if is_node_changed(conf, base + [ifname, options]): pppoe.update({'shutdown_required': {}}) # bail out early - no need to further process other nodes break return pppoe def verify(pppoe): if 'deleted' in pppoe: # bail out early return None verify_source_interface(pppoe) verify_authentication(pppoe) verify_vrf(pppoe) verify_mtu_ipv6(pppoe) verify_mirror_redirect(pppoe) if {'connect_on_demand', 'vrf'} <= set(pppoe): raise ConfigError('On-demand dialing and VRF can not be used at the same time') return None def generate(pppoe): # set up configuration file path variables where our templates will be # rendered into ifname = pppoe['ifname'] config_pppoe = f'/etc/ppp/peers/{ifname}' if 'deleted' in pppoe or 'disable' in pppoe: if os.path.exists(config_pppoe): os.unlink(config_pppoe) return None # Create PPP configuration files render(config_pppoe, 'pppoe/peer.j2', pppoe, permission=0o640) return None def apply(pppoe): ifname = pppoe['ifname'] if 'deleted' in pppoe or 'disable' in pppoe: if os.path.isdir(f'/sys/class/net/{ifname}'): p = PPPoEIf(ifname) p.remove() call(f'systemctl stop ppp@{ifname}.service') return None # reconnect should only be necessary when certain config options change, # like ACS name, authentication ... (see get_config() for details) if ((not is_systemd_service_running(f'ppp@{ifname}.service')) or 'shutdown_required' in pppoe): # cleanup system (e.g. FRR routes first) if os.path.isdir(f'/sys/class/net/{ifname}'): p = PPPoEIf(ifname) p.remove() call(f'systemctl restart ppp@{ifname}.service') # When interface comes "live" a hook is called: # /etc/ppp/ip-up.d/99-vyos-pppoe-callback # which triggers PPPoEIf.update() else: if os.path.isdir(f'/sys/class/net/{ifname}'): p = PPPoEIf(ifname) p.update(pppoe) 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-sstpc.py b/src/conf_mode/interfaces-sstpc.py new file mode 100755 index 000000000..6b8094c51 --- /dev/null +++ b/src/conf_mode/interfaces-sstpc.py @@ -0,0 +1,142 @@ +#!/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/>. + +import os +from sys import exit + +from vyos.config import Config +from vyos.configdict import get_interface_dict +from vyos.configdict import is_node_changed +from vyos.configverify import verify_authentication +from vyos.configverify import verify_vrf +from vyos.ifconfig import SSTPCIf +from vyos.pki import encode_certificate +from vyos.pki import find_chain +from vyos.pki import load_certificate +from vyos.template import render +from vyos.util import call +from vyos.util import dict_search +from vyos.util import is_systemd_service_running +from vyos.util import write_file +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', 'sstpc'] + ifname, sstpc = get_interface_dict(conf, base) + + # We should only terminate the SSTP client session if critical parameters + # change. All parameters that can be changed on-the-fly (like interface + # description) should not lead to a reconnect! + for options in ['authentication', 'no_peer_dns', 'no_default_route', + 'server', 'ssl']: + if is_node_changed(conf, base + [ifname, options]): + sstpc.update({'shutdown_required': {}}) + # bail out early - no need to further process other nodes + break + + # Load PKI certificates for later processing + sstpc['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True) + return sstpc + +def verify(sstpc): + if 'deleted' in sstpc: + return None + + verify_authentication(sstpc) + verify_vrf(sstpc) + + if dict_search('ssl.ca_certificate', sstpc) == None: + raise ConfigError('Missing mandatory CA certificate!') + + return None + +def generate(sstpc): + ifname = sstpc['ifname'] + config_sstpc = f'/etc/ppp/peers/{ifname}' + + sstpc['ca_file_path'] = f'/run/sstpc/{ifname}_ca-cert.pem' + + if 'deleted' in sstpc: + for file in [sstpc['ca_file_path'], config_sstpc]: + if os.path.exists(file): + os.unlink(file) + return None + + ca_name = sstpc['ssl']['ca_certificate'] + pki_ca_cert = sstpc['pki']['ca'][ca_name] + + loaded_ca_cert = load_certificate(pki_ca_cert['certificate']) + loaded_ca_certs = {load_certificate(c['certificate']) + for c in sstpc['pki']['ca'].values()} if 'ca' in sstpc['pki'] else {} + + ca_full_chain = find_chain(loaded_ca_cert, loaded_ca_certs) + + write_file(sstpc['ca_file_path'], '\n'.join(encode_certificate(c) for c in ca_full_chain)) + render(config_sstpc, 'sstp-client/peer.j2', sstpc, permission=0o640) + + return None + +def apply(sstpc): + ifname = sstpc['ifname'] + if 'deleted' in sstpc or 'disable' in sstpc: + if os.path.isdir(f'/sys/class/net/{ifname}'): + p = SSTPCIf(ifname) + p.remove() + call(f'systemctl stop ppp@{ifname}.service') + return None + + # reconnect should only be necessary when specific options change, + # like server, authentication ... (see get_config() for details) + if ((not is_systemd_service_running(f'ppp@{ifname}.service')) or + 'shutdown_required' in sstpc): + + # cleanup system (e.g. FRR routes first) + if os.path.isdir(f'/sys/class/net/{ifname}'): + p = SSTPCIf(ifname) + p.remove() + + call(f'systemctl restart ppp@{ifname}.service') + # When interface comes "live" a hook is called: + # /etc/ppp/ip-up.d/96-vyos-sstpc-callback + # which triggers SSTPCIf.update() + else: + if os.path.isdir(f'/sys/class/net/{ifname}'): + p = SSTPCIf(ifname) + p.update(sstpc) + + 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/etc/ppp/ip-up.d/96-vyos-sstpc-callback b/src/etc/ppp/ip-up.d/96-vyos-sstpc-callback new file mode 100755 index 000000000..4e8804f29 --- /dev/null +++ b/src/etc/ppp/ip-up.d/96-vyos-sstpc-callback @@ -0,0 +1,49 @@ +#!/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/>. + +# This is a Python hook script which is invoked whenever a SSTP client session +# goes "ip-up". It will call into our vyos.ifconfig library and will then +# execute common tasks for the SSTP interface. The reason we have to "hook" this +# is that we can not create a sstpcX interface in advance in linux and then +# connect pppd to this already existing interface. + +from sys import argv +from sys import exit + +from vyos.configquery import ConfigTreeQuery +from vyos.configdict import get_interface_dict +from vyos.ifconfig import SSTPCIf + +# When the ppp link comes up, this script is called with the following +# parameters +# $1 the interface name used by pppd (e.g. ppp3) +# $2 the tty device name +# $3 the tty device speed +# $4 the local IP address for the interface +# $5 the remote IP address +# $6 the parameter specified by the 'ipparam' option to pppd + +if (len(argv) < 7): + exit(1) + +interface = argv[6] + +conf = ConfigTreeQuery() +_, sstpc = get_interface_dict(conf.config, ['interfaces', 'sstpc'], interface) + +# Update the config +p = SSTPCIf(interface) +p.update(sstpc) diff --git a/src/op_mode/connect_disconnect.py b/src/op_mode/connect_disconnect.py index 936c20bcb..d39e88bf3 100755 --- a/src/op_mode/connect_disconnect.py +++ b/src/op_mode/connect_disconnect.py @@ -1,103 +1,103 @@ #!/usr/bin/env python3 # # Copyright (C) 2020-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 os import argparse from psutil import process_iter from vyos.util import call from vyos.util import commit_in_progress from vyos.util import DEVNULL from vyos.util import is_wwan_connected def check_ppp_interface(interface): if not os.path.isfile(f'/etc/ppp/peers/{interface}'): print(f'Interface {interface} does not exist!') exit(1) def check_ppp_running(interface): """ Check if PPP process is running in the interface in question """ for p in process_iter(): if "pppd" in p.name(): if interface in p.cmdline(): return True return False def connect(interface): """ Connect dialer interface """ - if interface.startswith('ppp'): + if interface.startswith('pppoe') or interface.startswith('sstpc'): check_ppp_interface(interface) # Check if interface is already dialed if os.path.isdir(f'/sys/class/net/{interface}'): print(f'Interface {interface}: already connected!') elif check_ppp_running(interface): print(f'Interface {interface}: connection is beeing established!') else: print(f'Interface {interface}: connecting...') call(f'systemctl restart ppp@{interface}.service') elif interface.startswith('wwan'): if is_wwan_connected(interface): print(f'Interface {interface}: already connected!') else: call(f'VYOS_TAGNODE_VALUE={interface} /usr/libexec/vyos/conf_mode/interfaces-wwan.py') else: print(f'Unknown interface {interface}, can not connect. Aborting!') def disconnect(interface): """ Disconnect dialer interface """ - if interface.startswith('ppp'): + if interface.startswith('pppoe') or interface.startswith('sstpc'): check_ppp_interface(interface) # Check if interface is already down if not check_ppp_running(interface): print(f'Interface {interface}: connection is already down') else: print(f'Interface {interface}: disconnecting...') call(f'systemctl stop ppp@{interface}.service') elif interface.startswith('wwan'): if not is_wwan_connected(interface): print(f'Interface {interface}: connection is already down') else: modem = interface.lstrip('wwan') call(f'mmcli --modem {modem} --simple-disconnect', stdout=DEVNULL) else: print(f'Unknown interface {interface}, can not disconnect. Aborting!') def main(): parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument("--connect", help="Bring up a connection-oriented network interface", action="store") group.add_argument("--disconnect", help="Take down connection-oriented network interface", action="store") args = parser.parse_args() if args.connect: if commit_in_progress(): print('Cannot connect while a commit is in progress') exit(1) connect(args.connect) elif args.disconnect: disconnect(args.disconnect) else: parser.print_help() exit(0) if __name__ == '__main__': main()