summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/rsyslog/rsyslog.conf59
-rw-r--r--debian/control3
-rw-r--r--interface-definitions/dhcp-server.xml8
-rw-r--r--interface-definitions/dhcpv6-server.xml316
-rw-r--r--interface-definitions/mdns-repeater.xml8
-rw-r--r--interface-definitions/syslog.xml1317
-rw-r--r--interface-definitions/wireguard.xml13
-rw-r--r--op-mode-definitions/dhcp.xml111
-rw-r--r--op-mode-definitions/traffic-dump.xml8
-rw-r--r--op-mode-definitions/wireguard.xml12
-rw-r--r--python/vyos/configtree.py37
-rw-r--r--python/vyos/validate.py5
-rwxr-xr-xsrc/conf_mode/bcast_relay.py1
-rwxr-xr-xsrc/conf_mode/dhcp_server.py64
-rwxr-xr-xsrc/conf_mode/dhcpv6_server.py451
-rwxr-xr-xsrc/conf_mode/mdns_repeater.py92
-rwxr-xr-xsrc/conf_mode/ntp.py2
-rwxr-xr-xsrc/conf_mode/snmp.py206
-rwxr-xr-xsrc/conf_mode/syslog.py14
-rwxr-xr-xsrc/conf_mode/tftp_server.py12
-rwxr-xr-xsrc/conf_mode/wireguard.py37
-rwxr-xr-xsrc/migration-scripts/quagga/2-to-3186
-rwxr-xr-xsrc/migration-scripts/system/8-to-932
-rwxr-xr-xsrc/op_mode/show_dhcp.py160
-rwxr-xr-xsrc/op_mode/show_dhcpv6.py82
-rwxr-xr-xsrc/op_mode/wireguard.py (renamed from src/op_mode/wireguard_key.py)22
26 files changed, 2399 insertions, 859 deletions
diff --git a/data/templates/rsyslog/rsyslog.conf b/data/templates/rsyslog/rsyslog.conf
new file mode 100644
index 000000000..0910bd662
--- /dev/null
+++ b/data/templates/rsyslog/rsyslog.conf
@@ -0,0 +1,59 @@
+# /etc/rsyslog.conf Configuration file for rsyslog.
+#
+
+#################
+#### MODULES ####
+#################
+
+$ModLoad imuxsock # provides support for local system logging
+$ModLoad imklog # provides kernel logging support (previously done by rklogd)
+#$ModLoad immark # provides --MARK-- message capability
+
+$OmitLocalLogging no
+$SystemLogSocketName /run/systemd/journal/syslog
+
+$KLogPath /proc/kmsg
+
+# provides UDP syslog reception
+#$ModLoad imudp
+#$UDPServerRun 514
+
+# provides TCP syslog reception
+#$ModLoad imtcp
+#$InputTCPServerRun 514
+
+###########################
+#### GLOBAL DIRECTIVES ####
+###########################
+
+#
+# Use traditional timestamp format.
+# To enable high precision timestamps, comment out the following line.
+#
+$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
+
+# Filter duplicated messages
+$RepeatedMsgReduction on
+
+#
+# Set the default permissions for all log files.
+#
+$FileOwner root
+$FileGroup adm
+$FileCreateMode 0640
+$DirCreateMode 0755
+$Umask 0022
+
+
+#
+# Include all config files in /etc/rsyslog.d/
+#
+$IncludeConfig /etc/rsyslog.d/*.conf
+
+###############
+#### RULES ####
+###############
+# Emergencies are sent to everybody logged in.
+
+*.emerg :omusrmsg:*
+
diff --git a/debian/control b/debian/control
index 04b228737..0912acbcb 100644
--- a/debian/control
+++ b/debian/control
@@ -21,6 +21,8 @@ Depends: python3,
python3-pystache,
python3-psutil,
python3-tabulate,
+ python3-six,
+ python3-isc-dhcp-leases,
ipaddrcheck,
tcpdump,
bmon,
@@ -36,6 +38,7 @@ Depends: python3,
iputils-arping,
libvyosconfig0,
beep,
+ isc-dhcp-server,
keepalived (>=2.0.5),
wireguard,
tftpd-hpa,
diff --git a/interface-definitions/dhcp-server.xml b/interface-definitions/dhcp-server.xml
index 0fcb79454..2002f0c65 100644
--- a/interface-definitions/dhcp-server.xml
+++ b/interface-definitions/dhcp-server.xml
@@ -218,13 +218,13 @@
<properties>
<help>Lease timeout in seconds (default: 86400)</help>
<valueHelp>
- <format>0-2592000</format>
- <description>DHCP lease time must be 0 to 2592000 (30 days)</description>
+ <format>0-4294967295</format>
+ <description>DHCP lease time in seconds must be between 0 and 4294967295 (49 days)</description>
</valueHelp>
<constraint>
- <validator name="numeric" argument="--range 0-2592000"/>
+ <validator name="numeric" argument="--range 0-4294967295"/>
</constraint>
- <constraintErrorMessage>DHCP lease time must be 0 to 2592000</constraintErrorMessage>
+ <constraintErrorMessage>DHCP lease time must be 0 to 4294967295</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="ntp-server">
diff --git a/interface-definitions/dhcpv6-server.xml b/interface-definitions/dhcpv6-server.xml
new file mode 100644
index 000000000..e63eb2242
--- /dev/null
+++ b/interface-definitions/dhcpv6-server.xml
@@ -0,0 +1,316 @@
+<?xml version="1.0"?>
+<!-- DHCPv6 server configuration -->
+<interfaceDefinition>
+ <node name="service">
+ <children>
+ <node name="dhcpv6-server" owner="${vyos_conf_scripts_dir}/dhcpv6_server.py">
+ <properties>
+ <help>DHCP for IPv6 (DHCPv6) server</help>
+ <priority>900</priority>
+ </properties>
+ <children>
+ <leafNode name="disable">
+ <properties>
+ <help>Option to disable DHCPv6 server</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="preference">
+ <properties>
+ <help>Preference of this DHCPv6 server compared with others</help>
+ <valueHelp>
+ <format>0-255</format>
+ <description>DHCPv6 server preference (0-255)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0-255"/>
+ </constraint>
+ <constraintErrorMessage>Preference must be between 0 and 255</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <tagNode name="shared-network-name">
+ <properties>
+ <help>DHCPv6 shared network name [REQUIRED]</help>
+ <constraint>
+ <regex>^[-_a-zA-Z0-9.]+$</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid DHCPv6 pool name</constraintErrorMessage>
+ </properties>
+ <children>
+ <leafNode name="disable">
+ <properties>
+ <help>Option to disable DHCPv6 configuration for shared-network</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <tagNode name="subnet">
+ <properties>
+ <help>IPv6 DHCP subnet for this shared network [REQUIRED]</help>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-prefix"/>
+ </constraint>
+ </properties>
+ <children>
+ <node name="address-range">
+ <properties>
+ <help>Parameters setting ranges for assigning IPv6 addresses</help>
+ </properties>
+ <children>
+ <tagNode name="prefix">
+ <properties>
+ <help>IPv6 prefix defining range of addresses to assign</help>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-prefix"/>
+ </constraint>
+ </properties>
+ <children>
+ <leafNode name="temporary">
+ <properties>
+ <help>Address range will be used for temporary addresses</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ <tagNode name="start">
+ <properties>
+ <help>First in range of consecutive IPv6 addresses to assign</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ </properties>
+ <children>
+ <leafNode name="stop">
+ <properties>
+ <help>Last in range of consecutive IPv6 addresses</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+ <leafNode name="domain-search">
+ <properties>
+ <help>Domain name for client to search</help>
+ <constraint>
+ <regex>^[-_a-zA-Z0-9.]+$</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid domain name syntax</constraintErrorMessage>
+ <multi/>
+ </properties>
+ </leafNode>
+ <node name="lease-time">
+ <properties>
+ <help>Parameters relating to the lease time</help>
+ </properties>
+ <children>
+ <leafNode name="default">
+ <properties>
+ <help>Default time (in seconds) that will be assigned to a lease</help>
+ </properties>
+ </leafNode>
+ <leafNode name="maximum">
+ <properties>
+ <help>Maximum time (in seconds) that will be assigned to a lease</help>
+ </properties>
+ </leafNode>
+ <leafNode name="minimum">
+ <properties>
+ <help>Minimum time (in seconds) that will be assigned to a lease</help>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="name-server">
+ <properties>
+ <help>IPv6 address of a Recursive DNS Server</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address of DNS name server</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="nis-domain">
+ <properties>
+ <help>NIS domain name for client to use</help>
+ <constraint>
+ <regex>^[-_a-zA-Z0-9.]+$</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid NIS domain name syntax</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="nis-server">
+ <properties>
+ <help>IPv6 address of a NIS Server</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address of NIS server</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="nisplus-domain">
+ <properties>
+ <help>NIS+ domain name for client to use</help>
+ <constraint>
+ <regex>^[-_a-zA-Z0-9.]+$</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid NIS+ domain name syntax</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="nisplus-server">
+ <properties>
+ <help>IPv6 address of a NIS+ Server</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address of NIS+ server</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <node name="prefix-delegation">
+ <properties>
+ <help>Parameters relating to IPv6 prefix delegation</help>
+ </properties>
+ <children>
+ <tagNode name="start">
+ <properties>
+ <help>First in range of IPv6 addresses to be used in prefix delegation</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address used in prefix delegation</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ </properties>
+ <children>
+ <leafNode name="prefix-length">
+ <properties>
+ <help>Length in bits of prefixes to be delegated</help>
+ <valueHelp>
+ <format>0-255</format>
+ <description>DHCPv6 server preference (0-255)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0-255"/>
+ </constraint>
+ <constraintErrorMessage>Preference must be between 0 and 255</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="stop">
+ <properties>
+ <help>Last in range of IPv6 addresses to be used in prefix delegation</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address used in prefix delegation</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+ <leafNode name="sip-server-address">
+ <properties>
+ <help>IPv6 address of SIP server</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address of SIP server</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="sip-server-name">
+ <properties>
+ <help>SIP server name</help>
+ <constraint>
+ <regex>^[-_a-zA-Z0-9.]+$</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid SIP server name syntax</constraintErrorMessage>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="sntp-server">
+ <properties>
+ <help>IPv6 address of an SNTP Server for client to use</help>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ <tagNode name="static-mapping">
+ <properties>
+ <help>Name of static mapping</help>
+ </properties>
+ <children>
+ <leafNode name="disable">
+ <properties>
+ <help>Option to disable static-mapping</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="identifier">
+ <properties>
+ <help>Client identifier for this static mapping</help>
+ </properties>
+ </leafNode>
+ <leafNode name="ipv6-address">
+ <properties>
+ <help>Client IPv5 address for this static mapping</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address for this tatic mapping</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/interface-definitions/mdns-repeater.xml b/interface-definitions/mdns-repeater.xml
index d74e203d6..a59321294 100644
--- a/interface-definitions/mdns-repeater.xml
+++ b/interface-definitions/mdns-repeater.xml
@@ -14,9 +14,15 @@
<priority>990</priority>
</properties>
<children>
+ <leafNode name="disable">
+ <properties>
+ <help>Disable mDNS repeater service</help>
+ <valueless/>
+ </properties>
+ </leafNode>
<leafNode name="interface">
<properties>
- <help>Interface to repeat mdns advertisements to [REQUIRED]</help>
+ <help>Interface to repeat mDNS advertisements [REQUIRED]</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces.py</script>
</completionHelp>
diff --git a/interface-definitions/syslog.xml b/interface-definitions/syslog.xml
index 0776fff56..aafa91b55 100644
--- a/interface-definitions/syslog.xml
+++ b/interface-definitions/syslog.xml
@@ -1,5 +1,4 @@
<?xml version="1.0"?>
-
<interfaceDefinition>
<node name="system">
<children>
@@ -9,660 +8,662 @@
<priority>400</priority>
</properties>
<children>
- <tagNode name="user">
- <properties>
- <help>Logging to specific user's terminal</help>
- <constraint>
- <regex>^[a-z_][a-z0-9_-]{1,31}[$]?</regex>
- </constraint>
- <constraintErrorMessage>illegal characters in user</constraintErrorMessage>
- <valueHelp>
- <format>username</format>
- <description>user login name</description>
- </valueHelp>
- </properties>
- <children>
- <tagNode name="facility">
- <properties>
- <help>Facility for logging</help>
- <completionHelp>
- <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
- </completionHelp>
- <valueHelp>
- <format>all</format>
- <description>All facilities excluding "mark"</description>
- </valueHelp>
- <valueHelp>
- <format>auth</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>authpriv</format>
- <description>Non-system authorization</description>
- </valueHelp>
- <valueHelp>
- <format>cron</format>
- <description>Cron daemon</description>
- </valueHelp>
- <valueHelp>
- <format>daemon</format>
- <description>System daemons</description>
- </valueHelp>
- <valueHelp>
- <format>kern</format>
- <description>Kernel</description>
- </valueHelp>
- <valueHelp>
- <format>lpr</format>
- <description>Line printer spooler</description>
- </valueHelp>
- <valueHelp>
- <format>mail</format>
- <description>Mail subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>mark</format>
- <description>Timestamp</description>
- </valueHelp>
- <valueHelp>
- <format>news</format>
- <description>USENET subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>protocols</format>
- <description>depricated will be set to local7</description>
- </valueHelp>
- <valueHelp>
- <format>security</format>
- <description>depricated will be set to auth</description>
- </valueHelp>
- <valueHelp>
- <format>syslog</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>user</format>
- <description>Application processes</description>
- </valueHelp>
- <valueHelp>
- <format>uucp</format>
- <description>UUCP subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>local0</format>
- <description>Local facility 0</description>
- </valueHelp>
- <valueHelp>
- <format>local1</format>
- <description>Local facility 1</description>
- </valueHelp>
- <valueHelp>
- <format>local2</format>
- <description>Local facility 2</description>
- </valueHelp>
- <valueHelp>
- <format>local3</format>
- <description>Local facility 3</description>
- </valueHelp>
- <valueHelp>
- <format>local4</format>
- <description>Local facility 4</description>
- </valueHelp>
- <valueHelp>
- <format>local5</format>
- <description>Local facility 5</description>
- </valueHelp>
- <valueHelp>
- <format>local6</format>
- <description>Local facility 6</description>
- </valueHelp>
- <valueHelp>
- <format>local7</format>
- <description>Local facility 7</description>
- </valueHelp>
- </properties>
- <children>
- <leafNode name="level">
- <properties>
- <help>Logging level</help>
- <completionHelp>
- <list>emerg alert crit err warning notice info debug all</list>
- </completionHelp>
- <valueHelp>
- <format>emerg</format>
- <description>Emergency messages</description>
- </valueHelp>
- <valueHelp>
- <format>alert</format>
- <description>Urgent messages</description>
- </valueHelp>
- <valueHelp>
- <format>crit</format>
- <description>Critical messages</description>
- </valueHelp>
- <valueHelp>
- <format>err</format>
- <description>Error messages</description>
- </valueHelp>
- <valueHelp>
- <format>warning</format>
- <description>Warning messages</description>
- </valueHelp>
- <valueHelp>
- <format>notice</format>
- <description>Messages for further investigation</description>
- </valueHelp>
- <valueHelp>
- <format>info</format>
- <description>Informational messages</description>
- </valueHelp>
- <valueHelp>
- <format>debug</format>
- <description>Debug messages</description>
- </valueHelp>
- <valueHelp>
- <format>all</format>
- <description>Log everything</description>
- </valueHelp>
- </properties>
- </leafNode>
- </children>
- </tagNode>
- </children>
- </tagNode>
- <tagNode name="host">
- <properties>
- <help>Logging to a remote host</help>
- <constraint>
- <!-- at least let's make sure whitespace isn't allowed, ideally it should be checked for IPv4/IPv6 address or fqdn/hostname -->
- <regex>[^ ]{1,63}</regex>
- </constraint>
- <constraintErrorMessage>illegal characters in user</constraintErrorMessage>
- <valueHelp>
- <format>x.x.x.x or host.domain.tld</format>
- <description>Remote host name or IP address</description>
- </valueHelp>
- </properties>
- <children>
- <tagNode name="facility">
- <properties>
- <help>Facility for logging</help>
- <completionHelp>
- <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
- </completionHelp>
- <valueHelp>
- <format>all</format>
- <description>All facilities excluding "mark"</description>
- </valueHelp>
- <valueHelp>
- <format>auth</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>authpriv</format>
- <description>Non-system authorization</description>
- </valueHelp>
- <valueHelp>
- <format>cron</format>
- <description>Cron daemon</description>
- </valueHelp>
- <valueHelp>
- <format>daemon</format>
- <description>System daemons</description>
- </valueHelp>
- <valueHelp>
- <format>kern</format>
- <description>Kernel</description>
- </valueHelp>
- <valueHelp>
- <format>lpr</format>
- <description>Line printer spooler</description>
- </valueHelp>
- <valueHelp>
- <format>mail</format>
- <description>Mail subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>mark</format>
- <description>Timestamp</description>
- </valueHelp>
- <valueHelp>
- <format>news</format>
- <description>USENET subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>protocols</format>
- <description>depricated will be set to local7</description>
- </valueHelp>
- <valueHelp>
- <format>security</format>
- <description>depricated will be set to auth</description>
- </valueHelp>
- <valueHelp>
- <format>syslog</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>user</format>
- <description>Application processes</description>
- </valueHelp>
- <valueHelp>
- <format>uucp</format>
- <description>UUCP subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>local0</format>
- <description>Local facility 0</description>
- </valueHelp>
- <valueHelp>
- <format>local1</format>
- <description>Local facility 1</description>
- </valueHelp>
- <valueHelp>
- <format>local2</format>
- <description>Local facility 2</description>
- </valueHelp>
- <valueHelp>
- <format>local3</format>
- <description>Local facility 3</description>
- </valueHelp>
- <valueHelp>
- <format>local4</format>
- <description>Local facility 4</description>
- </valueHelp>
- <valueHelp>
- <format>local5</format>
- <description>Local facility 5</description>
- </valueHelp>
- <valueHelp>
- <format>local6</format>
- <description>Local facility 6</description>
- </valueHelp>
- <valueHelp>
- <format>local7</format>
- <description>Local facility 7</description>
- </valueHelp>
- </properties>
- <children>
- <leafNode name="protocol">
- <properties>
- <help>syslog communication protocol</help>
- <valueHelp>
- <format>udp</format>
- <description>send log messages to remote syslog server over udp</description>
- </valueHelp>
- <valueHelp>
- <format>tcp</format>
- <description>send log messages to remote syslog server over tdp</description>
- </valueHelp>
- </properties>
- </leafNode>
-
- <leafNode name="level">
- <properties>
- <help>Logging level</help>
- <completionHelp>
- <list>emerg alert crit err warning notice info debug all</list>
- </completionHelp>
- <valueHelp>
- <format>emerg</format>
- <description>Emergency messages</description>
- </valueHelp>
- <valueHelp>
- <format>alert</format>
- <description>Urgent messages</description>
- </valueHelp>
- <valueHelp>
- <format>crit</format>
- <description>Critical messages</description>
- </valueHelp>
- <valueHelp>
- <format>err</format>
- <description>Error messages</description>
- </valueHelp>
- <valueHelp>
- <format>warning</format>
- <description>Warning messages</description>
- </valueHelp>
- <valueHelp>
- <format>notice</format>
- <description>Messages for further investigation</description>
- </valueHelp>
- <valueHelp>
- <format>info</format>
- <description>Informational messages</description>
- </valueHelp>
- <valueHelp>
- <format>debug</format>
- <description>Debug messages</description>
- </valueHelp>
- <valueHelp>
- <format>all</format>
- <description>Log everything</description>
- </valueHelp>
- </properties>
- </leafNode>
- </children>
- </tagNode>
- </children>
- </tagNode>
- <node name="global">
- <children>
- <node name="archive">
- <properties>
- <help>Log file size and rotation characteristics</help>
- </properties>
- <children>
- <leafNode name="file">
- <properties>
- <help>Number of saved files (default is 5)</help>
- <constraint>
- <regex>^[0-9]+</regex>
- </constraint>
- <constraintErrorMessage>illegal characters in number of files</constraintErrorMessage>
- </properties>
- </leafNode>
- <leafNode name="size">
- <properties>
- <help>Size of log files (in kbytes, default is 256)</help>
- <constraint>
- <regex>^[0-9]+</regex>
- </constraint>
- <constraintErrorMessage>illegal characters in size</constraintErrorMessage>
- </properties>
- </leafNode>
- </children>
- </node>
- <tagNode name="facility">
- <properties>
- <help>Facility for logging</help>
- <completionHelp>
- <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
- </completionHelp>
- <valueHelp>
- <format>all</format>
- <description>All facilities excluding "mark"</description>
- </valueHelp>
- <valueHelp>
- <format>auth</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>authpriv</format>
- <description>Non-system authorization</description>
- </valueHelp>
- <valueHelp>
- <format>cron</format>
- <description>Cron daemon</description>
- </valueHelp>
- <valueHelp>
- <format>daemon</format>
- <description>System daemons</description>
- </valueHelp>
- <valueHelp>
- <format>kern</format>
- <description>Kernel</description>
- </valueHelp>
- <valueHelp>
- <format>lpr</format>
- <description>Line printer spooler</description>
- </valueHelp>
- <valueHelp>
- <format>mail</format>
- <description>Mail subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>mark</format>
- <description>Timestamp</description>
- </valueHelp>
- <valueHelp>
- <format>news</format>
- <description>USENET subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>protocols</format>
- <description>depricated will be set to local7</description>
- </valueHelp>
- <valueHelp>
- <format>security</format>
- <description>depricated will be set to auth</description>
- </valueHelp>
- <valueHelp>
- <format>syslog</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>user</format>
- <description>Application processes</description>
- </valueHelp>
- <valueHelp>
- <format>uucp</format>
- <description>UUCP subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>local0</format>
- <description>Local facility 0</description>
- </valueHelp>
- <valueHelp>
- <format>local1</format>
- <description>Local facility 1</description>
- </valueHelp>
- <valueHelp>
- <format>local2</format>
- <description>Local facility 2</description>
- </valueHelp>
- <valueHelp>
- <format>local3</format>
- <description>Local facility 3</description>
- </valueHelp>
- <valueHelp>
- <format>local4</format>
- <description>Local facility 4</description>
- </valueHelp>
- <valueHelp>
- <format>local5</format>
- <description>Local facility 5</description>
- </valueHelp>
- <valueHelp>
- <format>local6</format>
- <description>Local facility 6</description>
- </valueHelp>
- <valueHelp>
- <format>local7</format>
- <description>Local facility 7</description>
- </valueHelp>
- </properties>
- <children>
- <leafNode name="level">
- <properties>
- <help>Logging level</help>
- <completionHelp>
- <list>emerg alert crit err warning notice info debug all</list>
- </completionHelp>
- <valueHelp>
- <format>emerg</format>
- <description>Emergency messages</description>
- </valueHelp>
- <valueHelp>
- <format>alert</format>
- <description>Urgent messages</description>
- </valueHelp>
- <valueHelp>
- <format>crit</format>
- <description>Critical messages</description>
- </valueHelp>
- <valueHelp>
- <format>err</format>
- <description>Error messages</description>
- </valueHelp>
- <valueHelp>
- <format>warning</format>
- <description>Warning messages</description>
- </valueHelp>
- <valueHelp>
- <format>notice</format>
- <description>Messages for further investigation</description>
- </valueHelp>
- <valueHelp>
- <format>info</format>
- <description>Informational messages</description>
- </valueHelp>
- <valueHelp>
- <format>debug</format>
- <description>Debug messages</description>
- </valueHelp>
- <valueHelp>
- <format>all</format>
- <description>Log everything</description>
- </valueHelp>
- </properties>
- </leafNode>
- </children>
- </tagNode>
- </children>
- </node>
- <tagNode name="file">
- <properties>
- <help>Logging to a file</help>
- <constraint>
- <regex>^[a-zA-Z0-9\-_.]{1,255}</regex>
+ <tagNode name="user">
+ <properties>
+ <help>Logging to specific user's terminal</help>
+ <constraint>
+ <regex>^[a-z_][a-z0-9_-]{1,31}[$]?</regex>
+ </constraint>
+ <constraintErrorMessage>illegal characters in user</constraintErrorMessage>
+ <valueHelp>
+ <format>username</format>
+ <description>user login name</description>
+ </valueHelp>
+ </properties>
+ <children>
+ <tagNode name="facility">
+ <properties>
+ <help>Facility for logging</help>
+ <completionHelp>
+ <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
+ </completionHelp>
+ <valueHelp>
+ <format>all</format>
+ <description>All facilities excluding "mark"</description>
+ </valueHelp>
+ <valueHelp>
+ <format>auth</format>
+ <description>Authentication and authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>authpriv</format>
+ <description>Non-system authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>cron</format>
+ <description>Cron daemon</description>
+ </valueHelp>
+ <valueHelp>
+ <format>daemon</format>
+ <description>System daemons</description>
+ </valueHelp>
+ <valueHelp>
+ <format>kern</format>
+ <description>Kernel</description>
+ </valueHelp>
+ <valueHelp>
+ <format>lpr</format>
+ <description>Line printer spooler</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mail</format>
+ <description>Mail subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mark</format>
+ <description>Timestamp</description>
+ </valueHelp>
+ <valueHelp>
+ <format>news</format>
+ <description>USENET subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>protocols</format>
+ <description>depricated will be set to local7</description>
+ </valueHelp>
+ <valueHelp>
+ <format>security</format>
+ <description>depricated will be set to auth</description>
+ </valueHelp>
+ <valueHelp>
+ <format>syslog</format>
+ <description>Authentication and authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>user</format>
+ <description>Application processes</description>
+ </valueHelp>
+ <valueHelp>
+ <format>uucp</format>
+ <description>UUCP subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local0</format>
+ <description>Local facility 0</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local1</format>
+ <description>Local facility 1</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local2</format>
+ <description>Local facility 2</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local3</format>
+ <description>Local facility 3</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local4</format>
+ <description>Local facility 4</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local5</format>
+ <description>Local facility 5</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local6</format>
+ <description>Local facility 6</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local7</format>
+ <description>Local facility 7</description>
+ </valueHelp>
+ </properties>
+ <children>
+ <leafNode name="level">
+ <properties>
+ <help>Logging level</help>
+ <completionHelp>
+ <list>emerg alert crit err warning notice info debug all</list>
+ </completionHelp>
+ <valueHelp>
+ <format>emerg</format>
+ <description>Emergency messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>alert</format>
+ <description>Urgent messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>crit</format>
+ <description>Critical messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>err</format>
+ <description>Error messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>warning</format>
+ <description>Warning messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>notice</format>
+ <description>Messages for further investigation</description>
+ </valueHelp>
+ <valueHelp>
+ <format>info</format>
+ <description>Informational messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>debug</format>
+ <description>Debug messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>all</format>
+ <description>Log everything</description>
+ </valueHelp>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
+ <tagNode name="host">
+ <properties>
+ <help>Logging to a remote host</help>
+ <constraint>
+ <!-- at least let's make sure whitespace isn't allowed, ideally it should be checked for IPv4/IPv6 address or fqdn/hostname -->
+ <regex>[^ ]{1,63}</regex>
+ </constraint>
+ <constraintErrorMessage>illegal characters in user</constraintErrorMessage>
+ <valueHelp>
+ <format>x.x.x.x or host.domain.tld</format>
+ <description>Remote host name or IP address</description>
+ </valueHelp>
+ </properties>
+ <children>
+ <tagNode name="facility">
+ <properties>
+ <help>Facility for logging</help>
+ <completionHelp>
+ <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
+ </completionHelp>
+ <valueHelp>
+ <format>all</format>
+ <description>All facilities excluding "mark"</description>
+ </valueHelp>
+ <valueHelp>
+ <format>auth</format>
+ <description>Authentication and authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>authpriv</format>
+ <description>Non-system authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>cron</format>
+ <description>Cron daemon</description>
+ </valueHelp>
+ <valueHelp>
+ <format>daemon</format>
+ <description>System daemons</description>
+ </valueHelp>
+ <valueHelp>
+ <format>kern</format>
+ <description>Kernel</description>
+ </valueHelp>
+ <valueHelp>
+ <format>lpr</format>
+ <description>Line printer spooler</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mail</format>
+ <description>Mail subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mark</format>
+ <description>Timestamp</description>
+ </valueHelp>
+ <valueHelp>
+ <format>news</format>
+ <description>USENET subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>protocols</format>
+ <description>depricated will be set to local7</description>
+ </valueHelp>
+ <valueHelp>
+ <format>security</format>
+ <description>depricated will be set to auth</description>
+ </valueHelp>
+ <valueHelp>
+ <format>syslog</format>
+ <description>Authentication and authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>user</format>
+ <description>Application processes</description>
+ </valueHelp>
+ <valueHelp>
+ <format>uucp</format>
+ <description>UUCP subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local0</format>
+ <description>Local facility 0</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local1</format>
+ <description>Local facility 1</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local2</format>
+ <description>Local facility 2</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local3</format>
+ <description>Local facility 3</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local4</format>
+ <description>Local facility 4</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local5</format>
+ <description>Local facility 5</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local6</format>
+ <description>Local facility 6</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local7</format>
+ <description>Local facility 7</description>
+ </valueHelp>
+ </properties>
+ <children>
+ <leafNode name="protocol">
+ <properties>
+ <help>syslog communication protocol</help>
+ <valueHelp>
+ <format>udp</format>
+ <description>send log messages to remote syslog server over udp</description>
+ </valueHelp>
+ <valueHelp>
+ <format>tcp</format>
+ <description>send log messages to remote syslog server over tdp</description>
+ </valueHelp>
+ </properties>
+ </leafNode>
+ <leafNode name="level">
+ <properties>
+ <help>Logging level</help>
+ <completionHelp>
+ <list>emerg alert crit err warning notice info debug all</list>
+ </completionHelp>
+ <valueHelp>
+ <format>emerg</format>
+ <description>Emergency messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>alert</format>
+ <description>Urgent messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>crit</format>
+ <description>Critical messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>err</format>
+ <description>Error messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>warning</format>
+ <description>Warning messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>notice</format>
+ <description>Messages for further investigation</description>
+ </valueHelp>
+ <valueHelp>
+ <format>info</format>
+ <description>Informational messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>debug</format>
+ <description>Debug messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>all</format>
+ <description>Log everything</description>
+ </valueHelp>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
+ <node name="global">
+ <properties>
+ <help>Logging to system standard location</help>
+ </properties>
+ <children>
+ <node name="archive">
+ <properties>
+ <help>Log file size and rotation characteristics</help>
+ </properties>
+ <children>
+ <leafNode name="file">
+ <properties>
+ <help>Number of saved files (default is 5)</help>
+ <constraint>
+ <regex>^[0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>illegal characters in number of files</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="size">
+ <properties>
+ <help>Size of log files (in kbytes, default is 256)</help>
+ <constraint>
+ <regex>^[0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>illegal characters in size</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <tagNode name="facility">
+ <properties>
+ <help>Facility for logging</help>
+ <completionHelp>
+ <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
+ </completionHelp>
+ <valueHelp>
+ <format>all</format>
+ <description>All facilities excluding "mark"</description>
+ </valueHelp>
+ <valueHelp>
+ <format>auth</format>
+ <description>Authentication and authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>authpriv</format>
+ <description>Non-system authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>cron</format>
+ <description>Cron daemon</description>
+ </valueHelp>
+ <valueHelp>
+ <format>daemon</format>
+ <description>System daemons</description>
+ </valueHelp>
+ <valueHelp>
+ <format>kern</format>
+ <description>Kernel</description>
+ </valueHelp>
+ <valueHelp>
+ <format>lpr</format>
+ <description>Line printer spooler</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mail</format>
+ <description>Mail subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mark</format>
+ <description>Timestamp</description>
+ </valueHelp>
+ <valueHelp>
+ <format>news</format>
+ <description>USENET subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>protocols</format>
+ <description>depricated will be set to local7</description>
+ </valueHelp>
+ <valueHelp>
+ <format>security</format>
+ <description>depricated will be set to auth</description>
+ </valueHelp>
+ <valueHelp>
+ <format>syslog</format>
+ <description>Authentication and authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>user</format>
+ <description>Application processes</description>
+ </valueHelp>
+ <valueHelp>
+ <format>uucp</format>
+ <description>UUCP subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local0</format>
+ <description>Local facility 0</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local1</format>
+ <description>Local facility 1</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local2</format>
+ <description>Local facility 2</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local3</format>
+ <description>Local facility 3</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local4</format>
+ <description>Local facility 4</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local5</format>
+ <description>Local facility 5</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local6</format>
+ <description>Local facility 6</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local7</format>
+ <description>Local facility 7</description>
+ </valueHelp>
+ </properties>
+ <children>
+ <leafNode name="level">
+ <properties>
+ <help>Logging level</help>
+ <completionHelp>
+ <list>emerg alert crit err warning notice info debug all</list>
+ </completionHelp>
+ <valueHelp>
+ <format>emerg</format>
+ <description>Emergency messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>alert</format>
+ <description>Urgent messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>crit</format>
+ <description>Critical messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>err</format>
+ <description>Error messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>warning</format>
+ <description>Warning messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>notice</format>
+ <description>Messages for further investigation</description>
+ </valueHelp>
+ <valueHelp>
+ <format>info</format>
+ <description>Informational messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>debug</format>
+ <description>Debug messages</description>
+ </valueHelp>
+ <valueHelp>
+ <format>all</format>
+ <description>Log everything</description>
+ </valueHelp>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+ <tagNode name="file">
+ <properties>
+ <help>Logging to a file</help>
+ <constraint>
+ <regex>^[a-zA-Z0-9\-_.]{1,255}</regex>
</constraint>
<constraintErrorMessage>illegal characters in filename or filename longer than 255 characters</constraintErrorMessage>
- </properties>
- <children>
- <node name="archive">
- <properties>
- <help>Log file size and rotation characteristics</help>
- </properties>
- <children>
- <leafNode name="file">
- <properties>
- <help>Number of saved files (default is 5)</help>
- <constraint>
- <regex>^[0-9]+</regex>
- </constraint>
- <constraintErrorMessage>illegal characters in number of files</constraintErrorMessage>
- </properties>
- </leafNode>
- <leafNode name="size">
- <properties>
- <help>Size of log files (in kbytes, default is 256)</help>
- <constraint>
- <regex>^[0-9]+</regex>
- </constraint>
- <constraintErrorMessage>illegal characters in size</constraintErrorMessage>
- </properties>
- </leafNode>
- </children>
- </node>
- <tagNode name="facility">
- <properties>
- <help>Facility for logging</help>
- <completionHelp>
- <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
- </completionHelp>
- <valueHelp>
- <format>all</format>
- <description>All facilities excluding "mark"</description>
- </valueHelp>
- <valueHelp>
- <format>auth</format>
- <description>Authentication and authorization</description>
- </valueHelp>
- <valueHelp>
- <format>authpriv</format>
- <description>Non-system authorization</description>
- </valueHelp>
- <valueHelp>
- <format>cron</format>
- <description>Cron daemon</description>
- </valueHelp>
- <valueHelp>
- <format>daemon</format>
- <description>System daemons</description>
- </valueHelp>
- <valueHelp>
- <format>kern</format>
- <description>Kernel</description>
- </valueHelp>
- <valueHelp>
- <format>lpr</format>
- <description>Line printer spooler</description>
- </valueHelp>
- <valueHelp>
- <format>mail</format>
- <description>Mail subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>mark</format>
- <description>Timestamp</description>
- </valueHelp>
- <valueHelp>
- <format>news</format>
- <description>USENET subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>protocols</format>
- <description>depricated will be set to local7</description>
- </valueHelp>
- <valueHelp>
- <format>security</format>
- <description>depricated will be set to auth</description>
- </valueHelp>
- <valueHelp>
- <format>syslog</format>
+ </properties>
+ <children>
+ <node name="archive">
+ <properties>
+ <help>Log file size and rotation characteristics</help>
+ </properties>
+ <children>
+ <leafNode name="file">
+ <properties>
+ <help>Number of saved files (default is 5)</help>
+ <constraint>
+ <regex>^[0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>illegal characters in number of files</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="size">
+ <properties>
+ <help>Size of log files (in kbytes, default is 256)</help>
+ <constraint>
+ <regex>^[0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>illegal characters in size</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <tagNode name="facility">
+ <properties>
+ <help>Facility for logging</help>
+ <completionHelp>
+ <list>auth authpriv cron daemon kern lpr mail mark news protocols security syslog user uucp local0 local1 local2 local3 local4 local5 local6 local7 all</list>
+ </completionHelp>
+ <valueHelp>
+ <format>all</format>
+ <description>All facilities excluding "mark"</description>
+ </valueHelp>
+ <valueHelp>
+ <format>auth</format>
+ <description>Authentication and authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>authpriv</format>
+ <description>Non-system authorization</description>
+ </valueHelp>
+ <valueHelp>
+ <format>cron</format>
+ <description>Cron daemon</description>
+ </valueHelp>
+ <valueHelp>
+ <format>daemon</format>
+ <description>System daemons</description>
+ </valueHelp>
+ <valueHelp>
+ <format>kern</format>
+ <description>Kernel</description>
+ </valueHelp>
+ <valueHelp>
+ <format>lpr</format>
+ <description>Line printer spooler</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mail</format>
+ <description>Mail subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>mark</format>
+ <description>Timestamp</description>
+ </valueHelp>
+ <valueHelp>
+ <format>news</format>
+ <description>USENET subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>protocols</format>
+ <description>depricated will be set to local7</description>
+ </valueHelp>
+ <valueHelp>
+ <format>security</format>
+ <description>depricated will be set to auth</description>
+ </valueHelp>
+ <valueHelp>
+ <format>syslog</format>
<description>Authentication and authorization</description>
</valueHelp>
- <valueHelp>
- <format>user</format>
- <description>Application processes</description>
- </valueHelp>
- <valueHelp>
- <format>uucp</format>
- <description>UUCP subsystem</description>
- </valueHelp>
- <valueHelp>
- <format>local0</format>
- <description>Local facility 0</description>
- </valueHelp>
- <valueHelp>
- <format>local1</format>
- <description>Local facility 1</description>
- </valueHelp>
- <valueHelp>
- <format>local2</format>
- <description>Local facility 2</description>
- </valueHelp>
- <valueHelp>
- <format>local3</format>
- <description>Local facility 3</description>
- </valueHelp>
- <valueHelp>
- <format>local4</format>
- <description>Local facility 4</description>
- </valueHelp>
- <valueHelp>
- <format>local5</format>
- <description>Local facility 5</description>
- </valueHelp>
- <valueHelp>
- <format>local6</format>
- <description>Local facility 6</description>
- </valueHelp>
- <valueHelp>
- <format>local7</format>
- <description>Local facility 7</description>
- </valueHelp>
- </properties>
- <children>
- <leafNode name="level">
- <properties>
- <help>Logging level</help>
- <completionHelp>
- <list>emerg alert crit err warning notice info debug all</list>
- </completionHelp>
- <valueHelp>
- <format>emerg</format>
+ <valueHelp>
+ <format>user</format>
+ <description>Application processes</description>
+ </valueHelp>
+ <valueHelp>
+ <format>uucp</format>
+ <description>UUCP subsystem</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local0</format>
+ <description>Local facility 0</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local1</format>
+ <description>Local facility 1</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local2</format>
+ <description>Local facility 2</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local3</format>
+ <description>Local facility 3</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local4</format>
+ <description>Local facility 4</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local5</format>
+ <description>Local facility 5</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local6</format>
+ <description>Local facility 6</description>
+ </valueHelp>
+ <valueHelp>
+ <format>local7</format>
+ <description>Local facility 7</description>
+ </valueHelp>
+ </properties>
+ <children>
+ <leafNode name="level">
+ <properties>
+ <help>Logging level</help>
+ <completionHelp>
+ <list>emerg alert crit err warning notice info debug all</list>
+ </completionHelp>
+ <valueHelp>
+ <format>emerg</format>
<description>Emergency messages</description>
</valueHelp>
<valueHelp>
@@ -697,12 +698,12 @@
<format>all</format>
<description>Log everything</description>
</valueHelp>
- </properties>
- </leafNode>
- </children>
- </tagNode>
- </children>
- </tagNode>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
<node name="console">
<properties>
<help>logging to serial console</help>
@@ -757,7 +758,7 @@
<valueHelp>
<format>protocols</format>
<description>depricated will be set to local7</description>
- </valueHelp>
+ </valueHelp>
<valueHelp>
<format>security</format>
<description>depricated will be set to auth</description>
diff --git a/interface-definitions/wireguard.xml b/interface-definitions/wireguard.xml
index cf25124fa..5e9c41ace 100644
--- a/interface-definitions/wireguard.xml
+++ b/interface-definitions/wireguard.xml
@@ -88,16 +88,25 @@
<constraintErrorMessage>Key is not valid 44-character (32-bytes) base64</constraintErrorMessage>
</properties>
</leafNode>
+ <leafNode name="preshared-key">
+ <properties>
+ <help>base64 encoded preshared key</help>
+ <constraint>
+ <regex>^[0-9a-zA-Z\+/]{43}=$</regex>
+ </constraint>
+ <constraintErrorMessage>Key is not valid 44-character (32-bytes) base64</constraintErrorMessage>
+ </properties>
+ </leafNode>
<leafNode name="allowed-ips">
<properties>
<help>IP addresses allowed to traverse the peer</help>
<multi/>
</properties>
</leafNode>
- <!-- check format IP:port -->
+ <!-- eventually check format IP:port -->
<leafNode name="endpoint">
<properties>
- <help>Remote endpoint</help>
+ <help>Remote endpoint (IP:port)</help>
</properties>
</leafNode>
<leafNode name="persistent-keepalive">
diff --git a/op-mode-definitions/dhcp.xml b/op-mode-definitions/dhcp.xml
new file mode 100644
index 000000000..eb57f8f1f
--- /dev/null
+++ b/op-mode-definitions/dhcp.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interfaceDefinition>
+ <node name="show">
+ <children>
+ <node name="dhcp">
+ <properties>
+ <help>Show DHCP (Dynamic Host Configuration Protocol) information</help>
+ </properties>
+ <children>
+ <node name="server">
+ <properties>
+ <help>Show DHCP information</help>
+ </properties>
+ <children>
+ <node name="leases">
+ <properties>
+ <help>Show DHCP server leases</help>
+ </properties>
+ <command>sudo ${vyos_op_scripts_dir}/show_dhcp.py --leases</command>
+ <children>
+ <tagNode name="pool">
+ <properties>
+ <help>Show DHCP leases for a specific pool</help>
+ </properties>
+ <command>sudo ${vyos_op_scripts_dir}/show_dhcp.py --leases --pool $4</command>
+ </tagNode>
+ </children>
+ </node>
+ <node name="statistics">
+ <properties>
+ <help>Show DHCP server statistics</help>
+ </properties>
+ <command>sudo ${vyos_op_scripts_dir}/show_dhcp.py --statistics</command>
+ <children>
+ <tagNode name="pool">
+ <properties>
+ <help>Show DHCP server statistics for a specific pool</help>
+ </properties>
+ <command>sudo ${vyos_op_scripts_dir}/show_dhcp.py --statistics --pool $4</command>
+ </tagNode>
+ </children>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+ <node name="dhcpv6">
+ <properties>
+ <help>Show DHCPv6 (IPv6 Dynamic Host Configuration Protocol) information</help>
+ </properties>
+ <children>
+ <node name="server">
+ <properties>
+ <help>Show DHCPv6 server information</help>
+ </properties>
+ <children>
+ <node name="leases">
+ <properties>
+ <help>Show DHCPv6 server leases</help>
+ </properties>
+ <command>sudo ${vyos_op_scripts_dir}/show_dhcpv6.py --leases</command>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+ <node name="restart">
+ <children>
+ <node name="dhcp">
+ <properties>
+ <help>Restart DHCP processes</help>
+ </properties>
+ <children>
+ <node name="server">
+ <properties>
+ <help>Restart the DHCP server process</help>
+ </properties>
+ <command>sudo systemctl restart isc-dhcp-server.service</command>
+ </node>
+ <node name="relay-agent">
+ <properties>
+ <help>Restart the DHCP server process</help>
+ </properties>
+ <command>sudo /opt/vyatta/sbin/dhcrelay-starter.pl --op-mode --init='/opt/vyatta/sbin/dhcrelay.init'</command>
+ </node>
+ </children>
+ </node>
+ <node name="dhcpv6">
+ <properties>
+ <help>Restart DHCPv6 processes</help>
+ </properties>
+ <children>
+ <node name="server">
+ <properties>
+ <help>Restart the DHCPv6 server process</help>
+ </properties>
+ <command>sudo systemctl restart isc-dhcpv6-server.service</command>
+ </node>
+ <node name="relay-agent">
+ <properties>
+ <help>Restart the DHCP server process</help>
+ </properties>
+ <command>sudo /opt/vyatta/sbin/dhcv6relay-starter.pl --op_mode --config_action ACTIVE</command>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/op-mode-definitions/traffic-dump.xml b/op-mode-definitions/traffic-dump.xml
index a6810644e..00a809a7c 100644
--- a/op-mode-definitions/traffic-dump.xml
+++ b/op-mode-definitions/traffic-dump.xml
@@ -8,7 +8,7 @@
</properties>
<children>
<tagNode name="interface">
- <command>tcpdump -i $4</command>
+ <command>sudo tcpdump -i $4</command>
<properties>
<help>Monitor traffic dump from an interface</help>
<completionHelp>
@@ -17,19 +17,19 @@
</properties>
<children>
<tagNode name="filter">
- <command>tcpdump -n -i $4 $6</command>
+ <command>sudo tcpdump -n -i $4 $6</command>
<properties>
<help>Monitor traffic matching filter conditions</help>
</properties>
</tagNode>
<tagNode name="save">
- <command>tcpdump -n -i $4 -w $6</command>
+ <command>sudo tcpdump -n -i $4 -w $6</command>
<properties>
<help>Save traffic dump from an interface to a file</help>
</properties>
<children>
<tagNode name="filter">
- <command>tcpdump -n -i $4 -w $6 $8</command>
+ <command>sudo tcpdump -n -i $4 -w $6 $8</command>
<properties>
<help>Save a dump of traffic matching filter conditions to a file</help>
</properties>
diff --git a/op-mode-definitions/wireguard.xml b/op-mode-definitions/wireguard.xml
index a7e156d8d..dd62f0f2f 100644
--- a/op-mode-definitions/wireguard.xml
+++ b/op-mode-definitions/wireguard.xml
@@ -12,8 +12,14 @@
<properties>
<help>generate a wireguard keypair</help>
</properties>
- <command>${vyos_op_scripts_dir}/wireguard_key.py --genkey</command>
+ <command>${vyos_op_scripts_dir}/wireguard.py --genkey</command>
</leafNode>
+ <leafNode name="preshared-key">
+ <properties>
+ <help>generate a wireguard preshared key</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/wireguard.py --genpsk</command>
+ </leafNode>
</children>
</node>
</children>
@@ -26,13 +32,13 @@
<properties>
<help>show wireguard public key</help>
</properties>
- <command>${vyos_op_scripts_dir}/wireguard_key.py --showpub</command>
+ <command>${vyos_op_scripts_dir}/wireguard.py --showpub</command>
</leafNode>
<leafNode name="privkey">
<properties>
<help>show wireguard private key</help>
</properties>
- <command>${vyos_op_scripts_dir}/wireguard_key.py --showpriv</command>
+ <command>${vyos_op_scripts_dir}/wireguard.py --showpriv</command>
</leafNode>
</children>
</node>
diff --git a/python/vyos/configtree.py b/python/vyos/configtree.py
index 4b46a1fb3..39fe41669 100644
--- a/python/vyos/configtree.py
+++ b/python/vyos/configtree.py
@@ -24,6 +24,7 @@ def strip_comments(s):
IN_COMMENT = 1
i = len(s) - 1
+
state = INITIAL
config_end = 0
@@ -42,14 +43,11 @@ def strip_comments(s):
break
elif (state == INITIAL) and (c == '/'):
# A comment begins, or it's a stray slash
- try:
- if (s[i-1] == '*'):
- state = IN_COMMENT
- i -= 2
- else:
- raise ValueError("Invalid syntax")
- except:
- raise ValueError("Invalid syntax")
+ if (s[i-1] == '*'):
+ state = IN_COMMENT
+ i -= 2
+ else:
+ raise ValueError("Invalid syntax: stray slash at character {0}".format(i + 1))
elif (state == INITIAL) and (c == '}'):
# We are not inside a comment, that's the end of the last node
config_end = i + 1
@@ -61,12 +59,12 @@ def strip_comments(s):
state = INITIAL
i -= 2
except:
- raise ValueError("Invalid syntax")
+ raise ValueError("Invalid syntax: malformed commend end at character {0}".format(i + 1))
elif (state == IN_COMMENT) and (c != '*'):
# Ignore everything inside comments, including braces
i -= 1
else:
- raise ValueError("Invalid syntax")
+ raise ValueError("Invalid syntax at character {0}: invalid character {1}".format(i + 1, c))
return (s[0:config_end], s[config_end+1:])
@@ -92,6 +90,10 @@ class ConfigTree(object):
self.__from_string.argtypes = [c_char_p]
self.__from_string.restype = c_void_p
+ self.__get_error = self.__lib.get_error
+ self.__get_error.argtypes = []
+ self.__get_error.restype = c_char_p
+
self.__to_string = self.__lib.to_string
self.__to_string.argtypes = [c_void_p]
self.__to_string.restype = c_char_p
@@ -112,6 +114,10 @@ class ConfigTree(object):
self.__delete.argtypes = [c_void_p, c_char_p]
self.__delete.restype = c_int
+ self.__rename = self.__lib.rename_node
+ self.__rename.argtypes = [c_void_p, c_char_p, c_char_p]
+ self.__rename.restype = c_int
+
self.__set_replace_value = self.__lib.set_replace_value
self.__set_replace_value.argtypes = [c_void_p, c_char_p, c_char_p]
self.__set_replace_value.restype = c_int
@@ -150,10 +156,12 @@ class ConfigTree(object):
config_section, comments_section = strip_comments(config_string)
config = self.__from_string(config_section.encode())
if config is None:
- raise ValueError("Parse error")
+ msg = self.__get_error().decode()
+ raise ValueError("Failed to parse config: {0}".format(msg))
else:
self.__config = config
self.__comments = comments_section
+
def __del__(self):
if self.__config is not None:
self.__destroy(self.__config)
@@ -193,6 +201,13 @@ class ConfigTree(object):
self.__delete_value(self.__config, path_str, value.encode())
+ def rename(self, path, newname):
+ check_path(path)
+ path_str = " ".join(map(str, path)).encode()
+ newname_str = newname.encode()
+
+ self.__rename(self.__config, path_str, newname_str)
+
def exists(self, path):
check_path(path)
path_str = " ".join(map(str, path)).encode()
diff --git a/python/vyos/validate.py b/python/vyos/validate.py
index b681edc5e..1b77f196a 100644
--- a/python/vyos/validate.py
+++ b/python/vyos/validate.py
@@ -68,7 +68,8 @@ def is_subnet_connected(subnet, primary=False):
system.
primary check if the subnet is reachable via the primary IP address of this
- interface. E.g. ISC DHCP can only listen on primary addresses.
+ interface, or in other words has a broadcast address configured. ISC DHCP
+ for instance will complain if it should listen on non broadcast interfaces.
Return True/False
"""
@@ -81,7 +82,7 @@ def is_subnet_connected(subnet, primary=False):
for interface in netifaces.interfaces():
# check if the requested address type is configured at all
if addr_type not in netifaces.ifaddresses(interface).keys():
- return False
+ continue
# An interface can have multiple addresses, but some software components
# only support the primary address :(
diff --git a/src/conf_mode/bcast_relay.py b/src/conf_mode/bcast_relay.py
index 8cc948610..d1257d4a5 100755
--- a/src/conf_mode/bcast_relay.py
+++ b/src/conf_mode/bcast_relay.py
@@ -19,7 +19,6 @@
import sys
import os
import fnmatch
-import subprocess
import jinja2
from vyos.config import Config
diff --git a/src/conf_mode/dhcp_server.py b/src/conf_mode/dhcp_server.py
index 1458ed1d0..2a2b1fe6c 100755
--- a/src/conf_mode/dhcp_server.py
+++ b/src/conf_mode/dhcp_server.py
@@ -38,8 +38,8 @@ config_tmpl = """
# For options please consult the following website:
# https://www.isc.org/wp-content/uploads/2017/08/dhcp43options.html
-
-log-facility local7;
+#
+# log-facility local7;
{% if hostfile_update %}
on commit {
@@ -112,12 +112,12 @@ failover peer "{{ subnet.failover_name }}" {
{% for network in shared_network %}
{%- if not network.disabled -%}
shared-network {{ network.name }} {
- {% if network.authoritative %}authoritative;{% endif %}
+ {{ "authoritative;" if network.authoritative }}
{%- if network.network_parameters %}
# The following {{ network.network_parameters | length }} line(s) were added as shared-network-parameters in the CLI and have not been validated
{%- for param in network.network_parameters %}
{{ param }}
- {%- endfor -%}
+ {%- endfor %}
{%- endif %}
{%- for subnet in network.subnet %}
subnet {{ subnet.address }} netmask {{ subnet.netmask }} {
@@ -195,9 +195,19 @@ shared-network {{ network.name }} {
}
{%- endif %}
{%- endfor %}
+ {%- if subnet.failover_name %}
+ pool {
+ failover peer "{{ subnet.failover_name }}";
+ deny dynamic bootp clients;
+ {%- for range in subnet.range %}
+ range {{ range.start }} {{ range.stop }};
+ {%- endfor %}
+ }
+ {%- else %}
{%- for range in subnet.range %}
range {{ range.start }} {{ range.stop }};
{%- endfor %}
+ {%- endif %}
}
{%- endfor %}
on commit { set shared-networkname = "{{ network.name }}"; }
@@ -606,17 +616,17 @@ def verify(dhcp):
raise ConfigError('No DHCP shared networks configured.\n' \
'At least one DHCP shared network must be configured.')
+ # Inspect shared-network/subnet
+ failover_names = []
+ listen_ok = False
+ subnets = []
+
# A shared-network requires a subnet definition
for network in dhcp['shared_network']:
if len(network['subnet']) == 0:
raise ConfigError('No DHCP lease subnets configured for {0}. At least one\n' \
'lease subnet must be configured for each shared network.'.format(network['name']))
- # Inspect our subnet configuration
- failover_names = []
- listen_ok = False
- subnets = []
- for network in dhcp['shared_network']:
for subnet in network['subnet']:
# Subnet static route declaration requires destination and router
if subnet['static_subnet'] or subnet['static_router']:
@@ -650,34 +660,34 @@ def verify(dhcp):
stop = range['stop']
# DHCP stop IP required after start IP
if start and not stop:
- raise ConfigError('Stop IP address in DHCP range for start {0} is not defined!'.format(start))
+ raise ConfigError('DHCP range stop address for start {0} is not defined!'.format(start))
# Start address must be inside network
if not ipaddress.ip_address(start) in ipaddress.ip_network(subnet['network']):
- raise ConfigError('Start IP address {0} of DHCP range is not in subnet {1}\n' \
+ raise ConfigError('DHCP range start address {0} is not in subnet {1}\n' \
'specified for shared network {2}!'.format(start, subnet['network'], network['name']))
# Stop address must be inside network
if not ipaddress.ip_address(stop) in ipaddress.ip_network(subnet['network']):
- raise ConfigError('Stop IP address {0} of DHCP range is not in subnet {1}\n' \
+ raise ConfigError('DHCP range stop address {0} is not in subnet {1}\n' \
'specified for shared network {2}!'.format(stop, subnet['network'], network['name']))
# Stop address must be greater or equal to start address
if not ipaddress.ip_address(stop) >= ipaddress.ip_address(start):
- raise ConfigError('Stop IP address {0} of DHCP range should be greater or equal\n' \
- 'to the start IP address {1} of this range!'.format(stop, start))
+ raise ConfigError('DHCP range stop address {0} must be greater or equal\n' \
+ 'to the range start address {1}!'.format(stop, start))
# Range start address must be unique
if start in range_start:
raise ConfigError('Conflicting DHCP lease range:\n' \
- 'Pool start IP address {0} defined multipe times!'.format(range['start']))
+ 'Pool start address {0} defined multipe times!'.format(start))
else:
range_start.append(start)
# Range stop address must be unique
if stop in range_stop:
raise ConfigError('Conflicting DHCP lease range:\n' \
- 'Pool stop IP address {0} defined multipe times!'.format(range['stop']))
+ 'Pool stop address {0} defined multipe times!'.format(stop))
else:
range_stop.append(stop)
@@ -705,18 +715,18 @@ def verify(dhcp):
for mapping in subnet['static_mapping']:
# Static IP address must be configured
if not mapping['ip_address']:
- raise ConfigError('No static lease IP address specified for static mapping {0}\n' \
- 'under shared network name {1}!'.format(mapping['name'], network['name']))
+ raise ConfigError('DHCP static lease IP address not specified for static mapping\n' \
+ '{0} under shared network name {1}!'.format(mapping['name'], network['name']))
# Static IP address must be in bound
if not ipaddress.ip_address(mapping['ip_address']) in ipaddress.ip_network(subnet['network']):
- raise ConfigError('Static DHCP lease IP address {0} under static mapping {1}\n' \
- 'in shared network {2} is outside DHCP lease network {3}!' \
+ raise ConfigError('DHCP static lease IP address {0} for static mapping {1}\n' \
+ 'in shared network {2} is outside DHCP lease subnet {3}!' \
.format(mapping['ip_address'], mapping['name'], network['name'], subnet['network']))
# Static mapping requires MAC address
if not mapping['mac_address']:
- raise ConfigError('No static lease MAC address specified for static mapping\n' \
+ raise ConfigError('DHCP static lease MAC address not specified for static mapping\n' \
'{0} under shared network name {1}!'.format(mapping['name'], network['name']))
# There must be one subnet connected to a listen interface.
@@ -725,28 +735,24 @@ def verify(dhcp):
if vyos.validate.is_subnet_connected(subnet['network'], primary=True):
listen_ok = True
- #
# Subnets must be non overlapping
- #
if subnet['network'] in subnets:
- raise ConfigError('Subnets must be unique! Subnet {0} defined multiple times!'.format(subnet))
+ raise ConfigError('DHCP subnets must be unique! Subnet {0} defined multiple times!'.format(subnet))
else:
subnets.append(subnet['network'])
- #
# Check for overlapping subnets
- #
net = ipaddress.ip_network(subnet['network'])
for n in subnets:
net2 = ipaddress.ip_network(n)
- if (net.compare_networks(net2) != 0):
+ if (net != net2):
if net.overlaps(net2):
- raise ConfigError('Conflicting subnet ranges: {0} overlaps with {1}'.format(net, net2))
+ raise ConfigError('DHCP conflicting subnet ranges: {0} overlaps {1}'.format(net, net2))
if not listen_ok:
raise ConfigError('None of the DHCP lease subnets are inside any configured subnet on\n' \
'broadcast interfaces. At least one lease subnet must be set such that\n' \
- 'DHCP server listens on a one broadcast interface')
+ 'DHCP server listens on a one broadcast interface!')
return None
diff --git a/src/conf_mode/dhcpv6_server.py b/src/conf_mode/dhcpv6_server.py
new file mode 100755
index 000000000..bb3e6e90d
--- /dev/null
+++ b/src/conf_mode/dhcpv6_server.py
@@ -0,0 +1,451 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#
+
+import sys
+import os
+import ipaddress
+
+import jinja2
+
+import vyos.validate
+
+from vyos.config import Config
+from vyos import ConfigError
+
+config_file = r'/etc/dhcp/dhcpd6.conf'
+lease_file = r'/config/dhcpd6.leases'
+daemon_config_file = r'/etc/default/isc-dhcpv6-server'
+
+# Please be careful if you edit the template.
+config_tmpl = """
+### Autogenerated by dhcpv6_server.py ###
+
+# For options please consult the following website:
+# https://www.isc.org/wp-content/uploads/2017/08/dhcp43options.html
+
+log-facility local7;
+{%- if preference %}
+option dhcp6.preference {{ preference }};
+{%- endif %}
+
+# Shared network configration(s)
+{% for network in shared_network %}
+{%- if not network.disabled -%}
+shared-network {{ network.name }} {
+ {%- for subnet in network.subnet %}
+ subnet6 {{ subnet.network }} {
+ {%- for range in subnet.range6_prefix %}
+ range6 {{ range.prefix }}{{ " temporary" if range.temporary }};
+ {%- endfor %}
+ {%- for range in subnet.range6 %}
+ range6 {{ range.start }} {{ range.stop }};
+ {%- endfor %}
+ {%- if subnet.domain_search %}
+ option dhcp6.domain-search {{ subnet.domain_search | join(', ') }};
+ {%- endif %}
+ {%- if subnet.lease_def %}
+ default-lease-time {{ subnet.lease_def }};
+ {%- endif %}
+ {%- if subnet.lease_max %}
+ max-lease-time {{ subnet.lease_max }};
+ {%- endif %}
+ {%- if subnet.lease_min %}
+ min-lease-time {{ subnet.lease_min }};
+ {%- endif %}
+ {%- if subnet.dns_server %}
+ option dhcp6.name-servers {{ subnet.dns_server | join(', ') }};
+ {%- endif %}
+ {%- if subnet.nis_domain %}
+ option dhcp6.nis-domain-name "{{ subnet.nis_domain }}";
+ {%- endif %}
+ {%- if subnet.nis_server %}
+ option dhcp6.nis-servers {{ subnet.nis_server | join(', ') }};
+ {%- endif %}
+ {%- if subnet.nisp_domain %}
+ option dhcp6.nisp-domain-name "{{ subnet.nisp_domain }}";
+ {%- endif %}
+ {%- if subnet.nisp_server %}
+ option dhcp6.nisp-servers {{ subnet.nisp_server | join(', ') }};
+ {%- endif %}
+ {%- if subnet.sip_address %}
+ option dhcp6.sip-servers-addresses {{ subnet.sip_address | join(', ') }};
+ {%- endif %}
+ {%- if subnet.sip_hostname %}
+ option dhcp6.sip-servers-names {{ subnet.sip_hostname | join(', ') }};
+ {%- endif %}
+ {%- if subnet.sntp_server %}
+ option dhcp6.sntp-servers {{ subnet.sntp_server | join(', ') }};
+ {%- endif %}
+ {%- for host in subnet.static_mapping %}
+ {% if not host.disabled -%}
+ host {{ network.name }}_{{ host.name }} {
+ host-identifier option dhcp6.client-id "{{ host.client_identifier }}";
+ fixed-address6 {{ host.ipv6_address }};
+ }
+ {%- endif %}
+ {%- endfor %}
+ }
+ {%- endfor %}
+}
+{%- endif %}
+{% endfor %}
+
+"""
+
+daemon_tmpl = """
+### Autogenerated by dhcp_server.py ###
+
+# sourced by /etc/init.d/isc-dhcpv6-server
+
+DHCPD_CONF=/etc/dhcp/dhcpd6.conf
+DHCPD_PID=/var/run/dhcpd6.pid
+OPTIONS="-6 -lf {{ lease_file }}"
+INTERFACES=""
+"""
+
+default_config_data = {
+ 'lease_file': lease_file,
+ 'preference': '',
+ 'disabled': False,
+ 'shared_network': []
+}
+
+def get_config():
+ dhcpv6 = default_config_data
+ conf = Config()
+ if not conf.exists('service dhcpv6-server'):
+ return None
+ else:
+ conf.set_level('service dhcpv6-server')
+
+ # Check for global disable of DHCPv6 service
+ if conf.exists('disable'):
+ dhcpv6['disabled'] = True
+ return dhcpv6
+
+ # Preference of this DHCPv6 server compared with others
+ if conf.exists('preference'):
+ dhcpv6['preference'] = conf.return_value('preference')
+
+ # check for multiple, shared networks served with DHCPv6 addresses
+ if conf.exists('shared-network-name'):
+ for network in conf.list_nodes('shared-network-name'):
+ conf.set_level('service dhcpv6-server shared-network-name {0}'.format(network))
+ config = {
+ 'name': network,
+ 'disabled': False,
+ 'subnet': []
+ }
+
+ # If disabled, the shared-network configuration becomes inactive
+ if conf.exists('disable'):
+ config['disabled'] = True
+
+ # check for multiple subnet configurations in a shared network
+ if conf.exists('subnet'):
+ for net in conf.list_nodes('subnet'):
+ conf.set_level('service dhcpv6-server shared-network-name {0} subnet {1}'.format(network, net))
+ subnet = {
+ 'network': net,
+ 'range6_prefix': [],
+ 'range6': [],
+ 'default_router': '',
+ 'dns_server': [],
+ 'domain_name': '',
+ 'domain_search': [],
+ 'lease_def': '',
+ 'lease_min': '',
+ 'lease_max': '',
+ 'nis_domain': '',
+ 'nis_server': [],
+ 'nisp_domain': '',
+ 'nisp_server': [],
+ 'sip_address': [],
+ 'sip_hostname': [],
+ 'sntp_server': [],
+ 'static_mapping': []
+ }
+
+ # For any subnet on which addresses will be assigned dynamically, there must be at
+ # least one address range statement. The range statement gives the lowest and highest
+ # IP addresses in a range. All IP addresses in the range should be in the subnet in
+ # which the range statement is declared.
+ if conf.exists('address-range prefix'):
+ for prefix in conf.list_nodes('address-range prefix'):
+ range = {
+ 'prefix': prefix,
+ 'temporary': False
+ }
+
+ # Address range will be used for temporary addresses
+ if conf.exists('address-range prefix {0} temporary'.format(range['prefix'])):
+ range['temporary'] = True
+
+ # Append to subnet temporary range6 list
+ subnet['range6_prefix'].append(range)
+
+ if conf.exists('address-range start'):
+ for range in conf.list_nodes('address-range start'):
+ range = {
+ 'start': range,
+ 'stop': conf.return_value('address-range start {0} stop'.format(range))
+ }
+
+ # Append to subnet range6 list
+ subnet['range6'].append(range)
+
+ # The domain-search option specifies a 'search list' of Domain Names to be used
+ # by the client to locate not-fully-qualified domain names.
+ if conf.exists('domain-search'):
+ for domain in conf.return_values('domain-search'):
+ subnet['domain_search'].append('"' + domain + '"')
+
+ # IPv6 address valid lifetime
+ # (at the end the address is no longer usable by the client)
+ # (set to 30 days, the usual IPv6 default)
+ if conf.exists('lease-time default'):
+ subnet['lease_def'] = conf.return_value('lease-time default')
+
+ # Time should be the maximum length in seconds that will be assigned to a lease.
+ # The only exception to this is that Dynamic BOOTP lease lengths, which are not
+ # specified by the client, are not limited by this maximum.
+ if conf.exists('lease-time maximum'):
+ subnet['lease_max'] = conf.return_value('lease-time maximum')
+
+ # Time should be the minimum length in seconds that will be assigned to a lease
+ if conf.exists('lease-time minimum'):
+ subnet['lease_min'] = conf.return_value('lease-time minimum')
+
+ # Specifies a list of Domain Name System name servers available to the client.
+ # Servers should be listed in order of preference.
+ if conf.exists('name-server'):
+ subnet['dns_server'] = conf.return_values('name-server')
+
+ # Ancient NIS (Network Information Service) domain name
+ if conf.exists('nis-domain'):
+ subnet['nis_domain'] = conf.return_value('nis-domain')
+
+ # Ancient NIS (Network Information Service) servers
+ if conf.exists('nis-server'):
+ subnet['nis_server'] = conf.return_values('nis-server')
+
+ # Ancient NIS+ (Network Information Service) domain name
+ if conf.exists('nisplus-domain'):
+ subnet['nisp_domain'] = conf.return_value('nisplus-domain')
+
+ # Ancient NIS+ (Network Information Service) servers
+ if conf.exists('nisplus-server'):
+ subnet['nisp_server'] = conf.return_values('nisplus-server')
+
+ # Prefix Delegation (RFC 3633)
+ if conf.exists('prefix-delegation'):
+ print('TODO: This option is actually not implemented right now!')
+
+ # Local SIP server that is to be used for all outbound SIP requests - IPv6 address
+ if conf.exists('sip-server-address'):
+ subnet['sip_address'] = conf.return_values('sip-server-address')
+
+ # Local SIP server that is to be used for all outbound SIP requests - hostname
+ if conf.exists('sip-server-name'):
+ for hostname in conf.return_values('sip-server-name'):
+ subnet['sip_hostname'].append('"' + hostname + '"')
+
+ # List of local SNTP servers available for the client to synchronize their clocks
+ if conf.exists('sntp-server'):
+ subnet['sntp_server'] = conf.return_values('sntp-server')
+
+ #
+ # Static DHCP v6 leases
+ #
+ if conf.exists('static-mapping'):
+ for mapping in conf.list_nodes('static-mapping'):
+ conf.set_level('service dhcpv6-server shared-network-name {0} subnet {1} static-mapping {2}'.format(network, net, mapping))
+ mapping = {
+ 'name': mapping,
+ 'disabled': False,
+ 'ipv6_address': '',
+ 'client_identifier': '',
+ }
+
+ # This static lease is disabled
+ if conf.exists('disable'):
+ mapping['disabled'] = True
+
+ # IPv6 address used for this DHCP client
+ if conf.exists('ipv6-address'):
+ mapping['ipv6_address'] = conf.return_value('ipv6-address')
+
+ # This option specifies the client’s DUID identifier. DUIDs are similar but different from DHCPv4 client identifiers
+ if conf.exists('identifier'):
+ mapping['client_identifier'] = conf.return_value('identifier')
+
+ # append static mapping configuration tu subnet list
+ subnet['static_mapping'].append(mapping)
+
+ # append subnet configuration to shared network subnet list
+ config['subnet'].append(subnet)
+
+
+ # append shared network configuration to config dictionary
+ dhcpv6['shared_network'].append(config)
+
+ return dhcpv6
+
+def verify(dhcpv6):
+ if dhcpv6 is None:
+ return None
+
+ if dhcpv6['disabled']:
+ return None
+
+ # If DHCP is enabled we need one share-network
+ if len(dhcpv6['shared_network']) == 0:
+ raise ConfigError('No DHCPv6 shared networks configured.\n' \
+ 'At least one DHCPv6 shared network must be configured.')
+
+ # Inspect shared-network/subnet
+ subnets = []
+ listen_ok = False
+
+ for network in dhcpv6['shared_network']:
+ # A shared-network requires a subnet definition
+ if len(network['subnet']) == 0:
+ raise ConfigError('No DHCPv6 lease subnets configured for {0}. At least one\n' \
+ 'lease subnet must be configured for each shared network.'.format(network['name']))
+
+ range6_start = []
+ range6_stop = []
+ for subnet in network['subnet']:
+ # Ususal range declaration with a start and stop address
+ for range6 in subnet['range6']:
+ # shorten names
+ start = range6['start']
+ stop = range6['stop']
+
+ # DHCPv6 stop address is required
+ if start and not stop:
+ raise ConfigError('DHCPv6 range stop address for start {0} is not defined!'.format(start))
+
+ # Start address must be inside network
+ if not ipaddress.ip_address(start) in ipaddress.ip_network(subnet['network']):
+ raise ConfigError('DHCPv6 range start address {0} is not in subnet {1}\n' \
+ 'specified for shared network {2}!'.format(start, subnet['network'], network['name']))
+
+ # Stop address must be inside network
+ if not ipaddress.ip_address(stop) in ipaddress.ip_network(subnet['network']):
+ raise ConfigError('DHCPv6 range stop address {0} is not in subnet {1}\n' \
+ 'specified for shared network {2}!'.format(stop, subnet['network'], network['name']))
+
+ # Stop address must be greater or equal to start address
+ if not ipaddress.ip_address(stop) >= ipaddress.ip_address(start):
+ raise ConfigError('DHCPv6 range stop address {0} must be greater or equal\n' \
+ 'to the range start address {1}!'.format(stop, start))
+
+ # DHCPv6 range start address must be unique - two ranges can't
+ # start with the same address - makes no sense
+ if start in range6_start:
+ raise ConfigError('Conflicting DHCPv6 lease range:\n' \
+ 'Pool start address {0} defined multipe times!'.format(start))
+ else:
+ range6_start.append(start)
+
+ # DHCPv6 range stop address must be unique - two ranges can't
+ # end with the same address - makes no sense
+ if stop in range6_stop:
+ raise ConfigError('Conflicting DHCPv6 lease range:\n' \
+ 'Pool stop address {0} defined multipe times!'.format(stop))
+ else:
+ range6_stop.append(stop)
+
+ # We also have prefixes that require checking
+ for prefix in subnet['range6_prefix']:
+ # If configured prefix does not match our subnet, we have to check that it's inside
+ if ipaddress.ip_network(prefix['prefix']) != ipaddress.ip_network(subnet['network']):
+ # Configured prefixes must be inside our network
+ if not ipaddress.ip_network(prefix['prefix']) in ipaddress.ip_network(subnet['network']):
+ raise ConfigError('DHCPv6 prefix {0} is not in subnet {1}\n' \
+ 'specified for shared network {2}!'.format(prefix['prefix'], subnet['network'], network['name']))
+
+ # DHCPv6 requires at least one configured address range or one static mapping
+ if not network['disabled']:
+ if vyos.validate.is_subnet_connected(subnet['network']):
+ listen_ok = True
+
+ # DHCPv6 subnet must not overlap. ISC DHCP also complains about overlapping
+ # subnets: "Warning: subnet 2001:db8::/32 overlaps subnet 2001:db8:1::/32"
+ net = ipaddress.ip_network(subnet['network'])
+ for n in subnets:
+ net2 = ipaddress.ip_network(n)
+ if (net != net2):
+ if net.overlaps(net2):
+ raise ConfigError('DHCPv6 conflicting subnet ranges: {0} overlaps {1}'.format(net, net2))
+
+ if not listen_ok:
+ raise ConfigError('None of the DHCPv6 subnets are connected to a subnet6 on\n' \
+ 'this machine. At least one subnet6 must be connected such that\n' \
+ 'DHCPv6 listens on an interface!')
+
+
+ return None
+
+def generate(dhcpv6):
+ if dhcpv6 is None:
+ return None
+
+ if dhcpv6['disabled']:
+ print('Warning: DHCPv6 server will be deactivated because it is disabled')
+ return None
+
+ tmpl = jinja2.Template(config_tmpl)
+ config_text = tmpl.render(dhcpv6)
+ with open(config_file, 'w') as f:
+ f.write(config_text)
+
+ tmpl = jinja2.Template(daemon_tmpl)
+ config_text = tmpl.render(dhcpv6)
+ with open(daemon_config_file, 'w') as f:
+ f.write(config_text)
+
+ return None
+
+def apply(dhcpv6):
+ if (dhcpv6 is None) or dhcpv6['disabled']:
+ # DHCP server is removed in the commit
+ os.system('sudo systemctl stop isc-dhcpv6-server.service')
+ if os.path.exists(config_file):
+ os.unlink(config_file)
+ if os.path.exists(daemon_config_file):
+ os.unlink(daemon_config_file)
+ else:
+ # If our file holding DHCPv6 leases does yet not exist - create it
+ if not os.path.exists(lease_file):
+ os.mknod(lease_file)
+
+ os.system('sudo systemctl restart isc-dhcpv6-server.service')
+
+ return None
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ sys.exit(1)
diff --git a/src/conf_mode/mdns_repeater.py b/src/conf_mode/mdns_repeater.py
index 474a6a5cf..cef735c0d 100755
--- a/src/conf_mode/mdns_repeater.py
+++ b/src/conf_mode/mdns_repeater.py
@@ -18,7 +18,7 @@
import sys
import os
-
+import jinja2
import netifaces
from vyos.config import Config
@@ -26,60 +26,78 @@ from vyos import ConfigError
config_file = r'/etc/default/mdns-repeater'
-def get_config():
- interface_list = []
+config_tmpl = """
+### Autogenerated by mdns_repeater.py ###
+DAEMON_ARGS="{{ interfaces | join(' ') }}"
+"""
+
+default_config_data = {
+ 'disabled': False,
+ 'interfaces': []
+}
+def get_config():
+ mdns = default_config_data
conf = Config()
- conf.set_level('service mdns repeater')
- if not conf.exists(''):
- return interface_list
+ if not conf.exists('service mdns repeater'):
+ return None
+ else:
+ conf.set_level('service mdns repeater')
- if conf.exists('interface'):
- intfs_names = []
- intfs_names = conf.return_values('interface')
+ # Service can be disabled by user
+ if conf.exists('disable'):
+ mdns['disabled'] = True
+ return mdns
- for name in intfs_names:
- interface_list.append(name)
+ # Interface to repeat mDNS advertisements
+ if conf.exists('interface'):
+ mdns['interfaces'] = conf.return_values('interface')
- return interface_list
+ return mdns
def verify(mdns):
- # '0' interfaces are possible, think of service deletion. Only '1' is not supported!
- if len(mdns) == 1:
- raise ConfigError('At least 2 interfaces must be specified but %d given!' % len(mdns))
-
- # For mdns-repeater to work it is essential that the interfaces
- # have an IP address assigned
- for intf in mdns:
- try:
- netifaces.ifaddresses(intf)[netifaces.AF_INET]
- except KeyError as e:
- raise ConfigError('No IP address configured for interface "%s"!' % intf)
+ if mdns is None:
+ return None
+
+ if mdns['disabled']:
+ return None
+
+ # We need at least two interfaces to repeat mDNS advertisments
+ if len(mdns['interfaces']) < 2:
+ raise ConfigError('mDNS repeater requires at least 2 configured interfaces!')
+
+ # For mdns-repeater to work it is essential that the interfaces has
+ # an IPv4 address assigned
+ for interface in mdns['interfaces']:
+ if netifaces.AF_INET in netifaces.ifaddresses(interface).keys():
+ if len(netifaces.ifaddresses(interface)[netifaces.AF_INET]) < 1:
+ raise ConfigError('mDNS repeater requires an IPv6 address configured on interface %s!'.format(interface))
return None
def generate(mdns):
- config_header = '### Autogenerated by mdns_repeater.py ###\n'
- if len(mdns) > 0:
- config_args = 'DAEMON_ARGS="' + ' '.join(str(e) for e in mdns) + '"\n'
- else:
- config_args = 'DAEMON_ARGS=""\n'
+ if mdns is None:
+ return None
+
+ if mdns['disabled']:
+ print('Warning: mDNS repeater will be deactivated because it is disabled')
+ return None
- # write new configuration file
- f = open(config_file, 'w')
- f.write(config_header)
- f.write(config_args)
- f.close()
+ tmpl = jinja2.Template(config_tmpl)
+ config_text = tmpl.render(mdns)
+ with open(config_file, 'w') as f:
+ f.write(config_text)
return None
def apply(mdns):
- if len(mdns) == 0:
- cmd = "sudo systemctl stop mdns-repeater"
+ if (mdns is None) or mdns['disabled']:
+ os.system('sudo systemctl stop mdns-repeater')
+ if os.path.exists(config_file):
+ os.unlink(config_file)
else:
- cmd = "sudo systemctl restart mdns-repeater"
+ os.system('sudo systemctl restart mdns-repeater')
- os.system(cmd)
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py
index 8533411cc..0abb2746a 100755
--- a/src/conf_mode/ntp.py
+++ b/src/conf_mode/ntp.py
@@ -36,7 +36,7 @@ config_tmpl = """
#
driftfile /var/lib/ntp/ntp.drift
# By default, only allow ntpd to query time sources, ignore any incoming requests
-restrict default ignore
+restrict default noquery nopeer notrap nomodify
# Local users have unrestricted access, allowing reconfiguration via ntpdc
restrict 127.0.0.1
restrict -6 ::1
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index b98741913..69952e5e2 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -21,7 +21,6 @@ import os
import shutil
import stat
import pwd
-import time
import jinja2
import random
@@ -38,6 +37,7 @@ config_file_client = r'/etc/snmp/snmp.conf'
config_file_daemon = r'/etc/snmp/snmpd.conf'
config_file_access = r'/usr/share/snmp/snmpd.conf'
config_file_user = r'/var/lib/snmp/snmpd.conf'
+config_file_init = r'/etc/default/snmpd'
# SNMP OIDs used to mark auth/priv type
OIDs = {
@@ -59,34 +59,32 @@ clientaddr {{ trap_source }}
# SNMPS template - be careful if you edit the template.
access_config_tmpl = """
### Autogenerated by snmp.py ###
-{% if v3_users %}
-{% for u in v3_users %}
+{%- for u in v3_users %}
{{ u.mode }}user {{ u.name }}
-{% endfor %}
-{% endif -%}
+{%- endfor %}
+
rwuser {{ vyos_user }}
+
"""
# SNMPS template - be careful if you edit the template.
user_config_tmpl = """
### Autogenerated by snmp.py ###
# user
-{% if v3_users %}
-{% for u in v3_users %}
-{% if u.authOID == 'none' %}
+{%- for u in v3_users %}
+{%- if u.authOID == 'none' %}
createUser {{ u.name }}
-{% elif u.authPassword %}
+{%- elif u.authPassword %}
createUser {{ u.name }} {{ u.authProtocol | upper }} "{{ u.authPassword }}" {{ u.privProtocol | upper }} {{ u.privPassword }}
-{% else %}
+{%- else %}
usmUser 1 3 {{ u.engineID }} "{{ u.name }}" "{{ u.name }}" NULL {{ u.authOID }} {{ u.authMasterKey }} {{ u.privOID }} {{ u.privMasterKey }} 0x
-{% endif %}
-{% endfor %}
-{% endif %}
+{%- endif %}
+{%- endfor %}
createUser {{ vyos_user }} MD5 "{{ vyos_user_pass }}" DES
-{% if v3_engineid %}
+{%- if v3_engineid %}
oldEngineID {{ v3_engineid }}
-{%- endif -%}
+{%- endif %}
"""
# SNMPS template - be careful if you edit the template.
@@ -123,112 +121,108 @@ monitor -r 10 -e linkDownTrap "Generate linkDown" ifOperStatus == 2
########################
# configurable section #
########################
-
{% if v3_tsm_key %}
[snmp] localCert {{ v3_tsm_key }}
-{% endif %}
+{%- endif %}
# Default system description is VyOS version
sysDescr VyOS {{ version }}
-{% if description -%}
+{% if description %}
# Description
SysDescr {{ description }}
-{% endif %}
+{%- endif %}
# Listen
agentaddress unix:/run/snmpd.socket{% if listen_on %}{% for li in listen_on %},{{ li }}{% endfor %}{% else %},udp:161,udp6:161{% endif %}{% if v3_tsm_key %},tlstcp:{{ v3_tsm_port }},dtlsudp::{{ v3_tsm_port }}{% endif %}
# SNMP communities
-{% if communities -%}
-{% for c in communities %}
-{% if c.network -%}
-{% for network in c.network_v4 %}
+{%- for c in communities %}
+{%- if c.network_v4 %}
+{%- for network in c.network_v4 %}
{{ c.authorization }}community {{ c.name }} {{ network }}
-{% endfor %}
-{% for network in c.network_v6 %}
-{{ c.authorization }}community6 {{ c.name }} {{ network }}
-{% endfor %}
-{% else %}
+{%- endfor %}
+{%- else %}
{{ c.authorization }}community {{ c.name }}
+{%- endif %}
+{%- if c.network_v6 %}
+{%- for network in c.network_v6 %}
+{{ c.authorization }}community6 {{ c.name }} {{ network }}
+{%- endfor %}
+{%- else %}
{{ c.authorization }}community6 {{ c.name }}
-{% endif %}
-{% endfor %}
-{% endif %}
+{%- endif %}
+{%- endfor %}
-{% if contact -%}
+{% if contact %}
# system contact information
SysContact {{ contact }}
-{% endif %}
+{%- endif %}
-{% if location -%}
+{% if location %}
# system location information
SysLocation {{ location }}
-{% endif %}
+{%- endif %}
{% if smux_peers -%}
# additional smux peers
-{% for sp in smux_peers %}
+{%- for sp in smux_peers %}
smuxpeer {{ sp }}
-{% endfor %}
-{% endif %}
+{%- endfor %}
+{%- endif %}
{% if trap_targets -%}
# if there is a problem - tell someone!
-{% for t in trap_targets %}
+{%- for t in trap_targets %}
trap2sink {{ t.target }}{% if t.port -%}:{{ t.port }}{% endif %} {{ t.community }}
-{% endfor %}
-{% endif %}
+{%- endfor %}
+{%- endif %}
+{%- if v3_enabled %}
#
# SNMPv3 stuff goes here
#
-{% if v3_enabled %}
-
# views
-{% if v3_views -%}
-{% for v in v3_views %}
-{% for oid in v.oids %}
+{%- for v in v3_views %}
+{%- for oid in v.oids %}
view {{ v.name }} included .{{ oid.oid }}
-{% endfor %}
-{% endfor %}
-{% endif %}
+{%- endfor %}
+{%- endfor %}
# access
# context sec.model sec.level match read write notif
-{% if v3_groups -%}
-{% for g in v3_groups %}
-{% if g.mode == 'ro' %}
-access {{ g.name }} "" usm {{ g.seclevel }} exact {{ g.view }} none none
-access {{ g.name }} "" tsm {{ g.seclevel }} exact {{ g.view }} none none
-{% elif g.mode == 'rw' %}
-access {{ g.name }} "" usm {{ g.seclevel }} exact {{ g.view }} {{ g.view }} none
-access {{ g.name }} "" tsm {{ g.seclevel }} exact {{ g.view }} {{ g.view }} none
-{% endif %}
-{% endfor -%}
-{% endif %}
+{%- for g in v3_groups %}
+access {{ g.name }} "" usm {{ g.seclevel }} exact {{ g.view }} {% if g.mode == 'ro' %}none{% else %}{{ g.view }}{% endif %} none
+access {{ g.name }} "" tsm {{ g.seclevel }} exact {{ g.view }} {% if g.mode == 'ro' %}none{% else %}{{ g.view }}{% endif %} none
+{%- endfor %}
# trap-target
-{% if v3_traps -%}
-{% for t in v3_traps %}
+{%- for t in v3_traps %}
trapsess -v 3 {{ '-Ci' if t.type == 'inform' }} -e {{ t.engineID }} -u {{ t.secName }} -l {{ t.secLevel }} -a {{ t.authProtocol }} {% if t.authPassword %}-A {{ t.authPassword }}{% elif t.authMasterKey %}-3m {{ t.authMasterKey }}{% endif %} -x {{ t.privProtocol }} {% if t.privPassword %}-X {{ t.privPassword }}{% elif t.privMasterKey %}-3M {{ t.privMasterKey }}{% endif %} {{ t.ipProto }}:{{ t.ipAddr }}:{{ t.ipPort }}
-{% endfor -%}
-{% endif %}
+{%- endfor %}
# group
-{% if v3_users -%}
-{% for u in v3_users %}
+{%- for u in v3_users %}
group {{ u.group }} usm {{ u.name }}
group {{ u.group }} tsm {{ u.name }}
{% endfor %}
-{% endif %}
+{%- endif %}
+"""
-{% endif %}
+init_config_tmpl = """
+### Autogenerated by snmp.py ###
+# This file controls the activity of snmpd
+# snmpd control (yes means start daemon).
+SNMPDRUN=yes
+
+# snmpd options (use syslog, close stdin/out/err).
+SNMPDOPTS='-LSed -u snmp -g snmp -p /run/snmpd.pid'
"""
default_config_data = {
'listen_on': [],
+ 'listen_address': [],
'communities': [],
'smux_peers': [],
'location' : '',
@@ -281,12 +275,21 @@ def get_config():
if conf.exists('community {0} authorization'.format(name)):
community['authorization'] = conf.return_value('community {0} authorization'.format(name))
+ # Subnet of SNMP client(s) allowed to contact system
if conf.exists('community {0} network'.format(name)):
for addr in conf.return_values('community {0} network'.format(name)):
if vyos.validate.is_ipv4(addr):
- community['network_v4'] = addr
+ community['network_v4'].append(addr)
else:
- community['network_v6'] = addr
+ community['network_v6'].append(addr)
+
+ # IP address of SNMP client allowed to contact system
+ if conf.exists('community {0} client'.format(name)):
+ for addr in conf.return_values('community {0} client'.format(name)):
+ if vyos.validate.is_ipv4(addr):
+ community['network_v4'].append(addr)
+ else:
+ community['network_v6'].append(addr)
snmp['communities'].append(community)
@@ -298,19 +301,20 @@ def get_config():
if conf.exists('listen-address'):
for addr in conf.list_nodes('listen-address'):
- listen = ''
port = '161'
if conf.exists('listen-address {0} port'.format(addr)):
port = conf.return_value('listen-address {0} port'.format(addr))
- if vyos.validate.is_ipv4(addr):
- # udp:127.0.0.1:161
- listen = 'udp:' + addr + ':' + port
- else:
- # udp6:[::1]:161
- listen = 'udp6:' + '[' + addr + ']' + ':' + port
+ snmp['listen_address'].append((addr, port))
- snmp['listen_on'].append(listen)
+ # Always listen on localhost if an explicit address has been configured
+ # This is a safety measure to not end up with invalid listen addresses
+ # that are not configured on this system. See https://phabricator.vyos.net/T850
+ if not '127.0.0.1' in conf.list_nodes('listen-address'):
+ snmp['listen_address'].append(('127.0.0.1', '161'))
+
+ if not '::1' in conf.list_nodes('listen-address'):
+ snmp['listen_address'].append(('::1', '161'))
if conf.exists('location'):
snmp['location'] = conf.return_value('location')
@@ -585,6 +589,24 @@ def verify(snmp):
if not os.path.isfile('/config/snmp/tls/certs/' + snmp['v3_tsm_key']):
raise ConfigError('TSM key must be fingerprint or filename in "/config/snmp/tls/certs/" folder')
+ for listen in snmp['listen_address']:
+ addr = listen[0]
+ port = listen[1]
+
+ if vyos.validate.is_ipv4(addr):
+ # example: udp:127.0.0.1:161
+ listen = 'udp:' + addr + ':' + port
+ else:
+ # example: udp6:[::1]:161
+ listen = 'udp6:' + '[' + addr + ']' + ':' + port
+
+ # We only wan't to configure addresses that exist on the system.
+ # Hint the user if they don't exist
+ if vyos.validate.is_addr_assigned(addr):
+ snmp['listen_on'].append(listen)
+ else:
+ print('WARNING: SNMP listen address {0} not configured!'.format(addr))
+
if 'v3_groups' in snmp.keys():
for group in snmp['v3_groups']:
#
@@ -711,29 +733,35 @@ def generate(snmp):
return None
# Write client config file
- tmpl = jinja2.Template(client_config_tmpl, trim_blocks=True)
+ tmpl = jinja2.Template(client_config_tmpl)
config_text = tmpl.render(snmp)
with open(config_file_client, 'w') as f:
f.write(config_text)
# Write server config file
- tmpl = jinja2.Template(daemon_config_tmpl, trim_blocks=True)
+ tmpl = jinja2.Template(daemon_config_tmpl)
config_text = tmpl.render(snmp)
with open(config_file_daemon, 'w') as f:
f.write(config_text)
# Write access rights config file
- tmpl = jinja2.Template(access_config_tmpl, trim_blocks=True)
+ tmpl = jinja2.Template(access_config_tmpl)
config_text = tmpl.render(snmp)
with open(config_file_access, 'w') as f:
f.write(config_text)
# Write access rights config file
- tmpl = jinja2.Template(user_config_tmpl, trim_blocks=True)
+ tmpl = jinja2.Template(user_config_tmpl)
config_text = tmpl.render(snmp)
with open(config_file_user, 'w') as f:
f.write(config_text)
+ # Write init config file
+ tmpl = jinja2.Template(init_config_tmpl)
+ config_text = tmpl.render(snmp)
+ with open(config_file_init, 'w') as f:
+ f.write(config_text)
+
return None
def apply(snmp):
@@ -767,9 +795,17 @@ def apply(snmp):
# start SNMP daemon
os.system("sudo systemctl restart snmpd.service")
- # the passwords are not available immediately so this is a workaround
- # and should be changed to polling
- time.sleep(2)
+ # Passwords are not available immediately in the configuration file,
+ # after daemon startup - we wait until they have been processed by
+ # snmpd, which we see when a magic line appears in this file.
+ snmpReady = False
+ while not snmpReady:
+ with open(config_file_user, 'r') as f:
+ for line in f:
+ # Search for our magic string inside the file
+ if '**** DO NOT EDIT THIS FILE ****' in line:
+ snmpReady = True
+ break
# Back in the Perl days the configuration was re-read and any
# plaintext password inside the configuration was replaced by
diff --git a/src/conf_mode/syslog.py b/src/conf_mode/syslog.py
index 5dfc6f390..f652cf3d0 100755
--- a/src/conf_mode/syslog.py
+++ b/src/conf_mode/syslog.py
@@ -93,7 +93,7 @@ def get_config():
config_data['files'].update(
{
'global' : {
- 'log-file' : '/var/log/vyos-rsyslog',
+ 'log-file' : '/var/log/messages',
'max-size' : 262144,
'action-on-max-size' : '/usr/sbin/logrotate /etc/logrotate.d/vyos-rsyslog',
'selectors' : '*.notice;local7.debug',
@@ -229,6 +229,18 @@ def generate(c):
f.write(config_text)
def verify(c):
+ #
+ # /etc/rsyslog.conf is generated somewhere and copied over the original (exists in /opt/vyatta/etc/rsyslog.conf)
+ # it interferes with the global logging, to make sure we are using a single base, template is enforced here
+ #
+
+ if not os.path.islink('/etc/rsyslog.conf'):
+ os.remove('/etc/rsyslog.conf')
+ os.symlink('/usr/share/vyos/templates/rsyslog/rsyslog.conf', '/etc/rsyslog.conf')
+
+ # /var/log/vyos-rsyslog were the old files, we may want to clean those up, but currently there
+ # is a chance that someone still needs it, so I don't automatically remove them
+
if c == None:
return None
diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py
index b6cf5c09e..0984b4545 100755
--- a/src/conf_mode/tftp_server.py
+++ b/src/conf_mode/tftp_server.py
@@ -96,12 +96,20 @@ def verify(tftpd):
raise ConfigError('TFTP server listen address must be configured!')
for addr in tftpd['listen_ipv4']:
+ # we always bind to localhost
+ if '127.0.0.1' not in tftpd['listen_ipv4']:
+ tftpd['listen_ipv4'].append('127.0.0.1')
+
if not vyos.validate.is_addr_assigned(addr):
- raise ConfigError('TFTP server IPv4 listen address "{0}" not configured!'.format(addr))
+ print('WARNING: TFTP server listen address {0} not configured!'.format(addr))
for addr in tftpd['listen_ipv6']:
+ # we always bind to localhost
+ if '::1' not in tftpd['listen_ipv6']:
+ tftpd['listen_ipv6'].append('::1')
+
if not vyos.validate.is_addr_assigned(addr):
- raise ConfigError('TFTP server IPv6 listen address "{0}" not configured!'.format(addr))
+ print('WARNING: TFTP server listen address {0} not configured!'.format(addr))
return None
diff --git a/src/conf_mode/wireguard.py b/src/conf_mode/wireguard.py
index 9848914e3..c6440ad81 100755
--- a/src/conf_mode/wireguard.py
+++ b/src/conf_mode/wireguard.py
@@ -28,6 +28,7 @@ from vyos import ConfigError
dir = r'/config/auth/wireguard'
pk = dir + '/private.key'
pub = dir + '/public.key'
+psk_file = r'/tmp/psk'
def check_kmod():
if not os.path.exists('/sys/module/wireguard'):
@@ -117,7 +118,9 @@ def get_config():
config_data['interfaces'][intfc]['peer'][p]['endpoint'] = c.return_value(cnf + ' peer ' + p + ' endpoint')
if c.exists(cnf + ' peer ' + p + ' persistent-keepalive'):
config_data['interfaces'][intfc]['peer'][p]['persistent-keepalive'] = c.return_value(cnf + ' peer ' + p + ' persistent-keepalive')
-
+ if c.exists(cnf + ' peer ' + p + ' preshared-key'):
+ config_data['interfaces'][intfc]['peer'][p]['psk'] = c.return_value(cnf + ' peer ' + p + ' preshared-key')
+
return config_data
def verify(c):
@@ -225,24 +228,22 @@ def apply(c):
fh.write(str(cnf_descr))
def configure_interface(c, intf):
- wg_config = {
+ for p in c['interfaces'][intf]['peer']:
+ ## config init for wg call
+ wg_config = {
'interface' : intf,
- 'port' : 0,
- 'private-key' : '/config/auth/wireguard/private.key',
- 'peer' :
- {
- 'pubkey' : ''
- },
+ 'port' : 0,
+ 'private-key' : pk,
+ 'pubkey' : '',
+ 'psk' : '/dev/null',
'allowed-ips' : [],
'fwmark' : 0x00,
'endpoint' : None,
'keepalive' : 0
-
}
- for p in c['interfaces'][intf]['peer']:
## mandatory settings
- wg_config['peer']['pubkey'] = c['interfaces'][intf]['peer'][p]['pubkey']
+ wg_config['pubkey'] = c['interfaces'][intf]['peer'][p]['pubkey']
wg_config['allowed-ips'] = c['interfaces'][intf]['peer'][p]['allowed-ips']
## optional settings
@@ -258,11 +259,19 @@ def configure_interface(c, intf):
if 'persistent-keepalive' in c['interfaces'][intf]['peer'][p]:
wg_config['keepalive'] = c['interfaces'][intf]['peer'][p]['persistent-keepalive']
+ ## preshared-key - is only read from a file, it's called via sudo redirection doesn't work either
+ if 'psk' in c['interfaces'][intf]['peer'][p]:
+ old_umask = os.umask(0o077)
+ open(psk_file, 'w').write(str(c['interfaces'][intf]['peer'][p]['psk']))
+ os.umask(old_umask)
+ wg_config['psk'] = psk_file
+
### assemble wg command
cmd = "sudo wg set " + intf
cmd += " listen-port " + str(wg_config['port'])
cmd += " private-key " + wg_config['private-key']
- cmd += " peer " + wg_config['peer']['pubkey']
+ cmd += " peer " + wg_config['pubkey']
+ cmd += " preshared-key " + wg_config['psk']
cmd += " allowed-ips "
for ap in wg_config['allowed-ips']:
if ap != wg_config['allowed-ips'][-1]:
@@ -279,7 +288,11 @@ def configure_interface(c, intf):
cmd += " persistent-keepalive 0"
sl.syslog(sl.LOG_NOTICE, cmd)
+ #print (cmd)
subprocess.call([cmd], shell=True)
+ """ remove psk_file """
+ if os.path.exists(psk_file):
+ os.remove(psk_file)
def add_addr(intf, addr):
ret = subprocess.call(['ip a a dev ' + intf + ' ' + addr + ' &>/dev/null'], shell=True)
diff --git a/src/migration-scripts/quagga/2-to-3 b/src/migration-scripts/quagga/2-to-3
new file mode 100755
index 000000000..99d96a0aa
--- /dev/null
+++ b/src/migration-scripts/quagga/2-to-3
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#
+
+import sys
+
+from vyos.configtree import ConfigTree
+
+
+if (len(sys.argv) < 1):
+ print("Must specify file name!")
+ sys.exit(1)
+
+file_name = sys.argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+config = ConfigTree(config_file)
+
+def migrate_neighbor(config, neighbor_path, neighbor):
+ if config.exists(neighbor_path):
+ neighbors = config.list_nodes(neighbor_path)
+ for neighbor in neighbors:
+ # Move the valueless options: as-override, next-hop-self, route-reflector-client, route-server-client,
+ # remove-private-as
+ for valueless_option in ['as-override', 'nexthop-self', 'route-reflector-client', 'route-server-client',
+ 'remove-private-as']:
+ if config.exists(neighbor_path + [neighbor, valueless_option]):
+ config.set(neighbor_path + [neighbor] + af_path + [valueless_option])
+ config.delete(neighbor_path + [neighbor, valueless_option])
+
+ # Move filter options: distribute-list, filter-list, prefix-list, and route-map
+ # They share the same syntax inside so we can group them
+ for filter_type in ['distribute-list', 'filter-list', 'prefix-list', 'route-map']:
+ if config.exists(neighbor_path + [neighbor, filter_type]):
+ for filter_dir in ['import', 'export']:
+ if config.exists(neighbor_path + [neighbor, filter_type, filter_dir]):
+ filter_name = config.return_value(neighbor_path + [neighbor, filter_type, filter_dir])
+ config.set(neighbor_path + [neighbor] + af_path + [filter_type, filter_dir], value=filter_name)
+ config.delete(neighbor_path + [neighbor, filter_type])
+
+ # Move simple leaf node options: maximum-prefix, unsuppress-map, weight
+ for leaf_option in ['maximum-prefix', 'unsuppress-map', 'weight']:
+ if config.exists(neighbor_path + [neighbor, leaf_option]):
+ if config.exists(neighbor_path + [neighbor, leaf_option]):
+ leaf_opt_value = config.return_value(neighbor_path + [neighbor, leaf_option])
+ config.set(neighbor_path + [neighbor] + af_path + [leaf_option], value=leaf_opt_value)
+ config.delete(neighbor_path + [neighbor, leaf_option])
+
+ # The rest is special cases, for better or worse
+
+ # Move allowas-in
+ if config.exists(neighbor_path + [neighbor, 'allowas-in']):
+ if config.exists(neighbor_path + [neighbor, 'allowas-in', 'number']):
+ allowas_in = config.return_value(neighbor_path + [neighbor, 'allowas-in', 'number'])
+ config.set(neighbor_path + [neighbor] + af_path + ['allowas-in', 'number'], value=allowas_in)
+ config.delete(neighbor_path + [neighbor, 'allowas-in'])
+
+ # Move attribute-unchanged options
+ if config.exists(neighbor_path + [neighbor, 'attribute-unchanged']):
+ for attr in ['as-path', 'med', 'next-hop']:
+ if config.exists(neighbor_path + [neighbor, 'attribute-unchanged', attr]):
+ config.set(neighbor_path + [neighbor] + af_path + ['attribute-unchanged', attr])
+ config.delete(neighbor_path + [neighbor, 'attribute-unchanged', attr])
+ config.delete(neighbor_path + [neighbor, 'attribute-unchanged'])
+
+ # Move capability options
+ if config.exists(neighbor_path + [neighbor, 'capability']):
+ # "capability dynamic" is a peer-global option, we only migrate ORF
+ if config.exists(neighbor_path + [neighbor, 'capability', 'orf']):
+ if config.exists(neighbor_path + [neighbor, 'capability', 'orf', 'prefix-list']):
+ for orf in ['send', 'receive']:
+ if config.exists(neighbor_path + [neighbor, 'capability', 'orf', 'prefix-list', orf]):
+ config.set(neighbor_path + [neighbor] + af_path + ['capability', 'orf', 'prefix-list', orf])
+ config.delete(neighbor_path + [neighbor, 'capability', 'orf', 'prefix-list', orf])
+ config.delete(neighbor_path + [neighbor, 'capability', 'orf', 'prefix-list'])
+ config.delete(neighbor_path + [neighbor, 'capability', 'orf'])
+
+ # Move default-originate
+ if config.exists(neighbor_path + [neighbor, 'default-originate']):
+ if config.exists(neighbor_path + [neighbor, 'default-originate', 'route-map']):
+ route_map = config.return_value(neighbor_path + [neighbor, 'default-originate', 'route-map'])
+ config.set(neighbor_path + [neighbor] + af_path + ['default-originate', 'route-map'], value=route_map)
+ else:
+ # Empty default-originate node is meaningful so we re-create it
+ config.set(neighbor_path + [neighbor] + af_path + ['default-originate'])
+ config.delete(neighbor_path + [neighbor, 'default-originate'])
+
+ # Move soft-reconfiguration
+ if config.exists(neighbor_path + [neighbor, 'soft-reconfiguration']):
+ if config.exists(neighbor_path + [neighbor, 'soft-reconfiguration', 'inbound']):
+ config.set(neighbor_path + [neighbor] + af_path + ['soft-reconfiguration', 'inbound'])
+ # Empty soft-reconfiguration is meaningless, so we just remove it
+ config.delete(neighbor_path + [neighbor, 'soft-reconfiguration'])
+
+ # Move disable-send-community
+ if config.exists(neighbor_path + [neighbor, 'disable-send-community']):
+ for comm_type in ['standard', 'extended']:
+ if config.exists(neighbor_path + [neighbor, 'disable-send-community', comm_type]):
+ config.set(neighbor_path + [neighbor] + af_path + ['disable-send-community', comm_type])
+ config.delete(neighbor_path + [neighbor, 'disable-send-community', comm_type])
+ config.delete(neighbor_path + [neighbor, 'disable-send-community'])
+
+
+if not config.exists(['protocols', 'bgp']):
+ # Nothing to do
+ sys.exit(0)
+else:
+ # Just to avoid writing it so many times
+ af_path = ['address-family', 'ipv4-unicast']
+
+ # Check if BGP is actually configured and obtain the ASN
+ asn_list = config.list_nodes(['protocols', 'bgp'])
+ if asn_list:
+ # There's always just one BGP node, if any
+ asn = asn_list[0]
+ bgp_path = ['protocols', 'bgp', asn]
+ else:
+ # There's actually no BGP, just its empty shell
+ sys.exit(0)
+
+ ## Move global IPv4-specific BGP options to "address-family ipv4-unicast"
+
+ # Move networks
+ network_path = ['protocols', 'bgp', asn, 'network']
+ if config.exists(network_path):
+ config.set(bgp_path + af_path + ['network'])
+ config.set_tag(bgp_path + af_path + ['network'])
+
+ networks = config.list_nodes(network_path)
+ for network in networks:
+ config.set(bgp_path + af_path + ['network', network])
+ if config.exists(network_path + [network, 'route-map']):
+ route_map = config.return_value(network_path + [network, 'route-map'])
+ config.set(bgp_path + af_path + ['network', network, 'route-map'], value=route_map)
+ config.delete(network_path)
+
+ # Move aggregate-address statements
+ aggregate_path = ['protocols', 'bgp', asn, 'aggregate-address']
+ if config.exists(aggregate_path):
+ config.set(bgp_path + af_path + ['aggregate-address'])
+ config.set_tag(bgp_path + af_path + ['aggregate-address'])
+
+ aggregates = config.list_nodes(aggregate_path)
+ for aggregate in aggregates:
+ config.set(bgp_path + af_path + ['aggregate-address', aggregate])
+ if config.exists(aggregate_path + [aggregate, 'as-set']):
+ config.set(bgp_path + af_path + ['aggregate-address', aggregate, 'as-set'])
+ if config.exists(aggregate_path + [aggregate, 'summary-only']):
+ config.set(bgp_path + af_path + ['aggregate-address', aggregate, 'summary-only'])
+ config.delete(aggregate_path)
+
+ ## Migrate neighbor options
+ neighbor_path = ['protocols', 'bgp', asn, 'neighbor']
+ if config.exists(neighbor_path):
+ neighbors = config.list_nodes(neighbor_path)
+ for neighbor in neighbors:
+ migrate_neighbor(config, neighbor_path, neighbor)
+
+ peer_group_path = ['protocols', 'bgp', asn, 'peer-group']
+ if config.exists(peer_group_path):
+ peer_groups = config.list_nodes(peer_group_path)
+ for peer_group in peer_groups:
+ migrate_neighbor(config, peer_group_path, peer_group)
+
+ try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+ except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ sys.exit(1)
diff --git a/src/migration-scripts/system/8-to-9 b/src/migration-scripts/system/8-to-9
new file mode 100755
index 000000000..db3fefdea
--- /dev/null
+++ b/src/migration-scripts/system/8-to-9
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3
+
+# Deletes "system package" option as it is deprecated
+
+import sys
+
+from vyos.configtree import ConfigTree
+
+if (len(sys.argv) < 1):
+ print("Must specify file name!")
+ sys.exit(1)
+
+file_name = sys.argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+config = ConfigTree(config_file)
+
+if not config.exists(['system', 'package']):
+ # Nothing to do
+ sys.exit(0)
+else:
+ # Delete the node with the old syntax
+ config.delete(['system', 'package'])
+
+ try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+ except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ sys.exit(1)
diff --git a/src/op_mode/show_dhcp.py b/src/op_mode/show_dhcp.py
new file mode 100755
index 000000000..e76fc3a14
--- /dev/null
+++ b/src/op_mode/show_dhcp.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import json
+import argparse
+import ipaddress
+
+import tabulate
+
+import vyos.config
+
+from isc_dhcp_leases import Lease, IscDhcpLeases
+
+
+lease_file = "/config/dhcpd.leases"
+pool_key = "shared-networkname"
+
+def in_pool(lease, pool):
+ if pool_key in lease.sets:
+ if lease.sets[pool_key] == pool:
+ return True
+
+ return False
+
+def get_lease_data(lease):
+ data = {}
+
+ # End time may not be present in backup leases
+ try:
+ data["expires"] = lease.end.strftime("%Y/%m/%d %H:%M:%S")
+ except:
+ data["expires"] = ""
+
+ data["hardware_address"] = lease.ethernet
+ data["hostname"] = lease.hostname
+ data["ip"] = lease.ip
+
+ try:
+ data["pool"] = lease.sets[pool_key]
+ except:
+ data["pool"] = ""
+
+ return data
+
+def get_leases(leases, state=None, pool=None):
+ leases = IscDhcpLeases(lease_file).get()
+
+ if state is not None:
+ leases = list(filter(lambda x: x.binding_state == 'active', leases))
+
+ if pool is not None:
+ leases = list(filter(lambda x: in_pool(x, pool), leases))
+
+ return list(map(get_lease_data, leases))
+
+def show_leases(leases):
+ headers = ["IP address", "Hardware address", "Lease expiration", "Pool", "Client Name"]
+
+ lease_list = []
+ for l in leases:
+ lease_list.append([l["ip"], l["hardware_address"], l["expires"], l["pool"], l["hostname"]])
+
+ output = tabulate.tabulate(lease_list, headers)
+
+ print(output)
+
+def get_pool_size(config, pool):
+ size = 0
+ subnets = config.list_effective_nodes("service dhcp-server shared-network-name {0} subnet".format(pool))
+ for s in subnets:
+ ranges = config.list_effective_nodes("service dhcp-server shared-network-name {0} subnet {1} range".format(pool, s))
+ for r in ranges:
+ start = config.return_effective_value("service dhcp-server shared-network-name {0} subnet {1} range {2} start".format(pool, s, r))
+ stop = config.return_effective_value("service dhcp-server shared-network-name {0} subnet {1} range {2} stop".format(pool, s, r))
+
+ size += int(ipaddress.IPv4Address(stop)) - int(ipaddress.IPv4Address(start))
+
+ return size
+
+def show_pool_stats(stats):
+ headers = ["Pool", "Size", "Leases", "Available", "Usage"]
+ output = tabulate.tabulate(stats, headers)
+
+ print(output)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument("-l", "--leases", action="store_true", help="Show DHCP leases")
+ group.add_argument("-s", "--statistics", action="store_true", help="Show DHCP statistics")
+
+ parser.add_argument("-e", "--expired", action="store_true", help="Show expired leases")
+ parser.add_argument("-p", "--pool", type=str, action="store", help="Show lease for specific pool")
+ parser.add_argument("-j", "--json", action="store_true", default=False, help="Product JSON output")
+
+ args = parser.parse_args()
+
+ if args.leases:
+ if args.expired:
+ if args.pool:
+ leases = get_leases(lease_file, state='free', pool=args.pool)
+ else:
+ leases = get_leases(lease_file, state='free')
+ else:
+ if args.pool:
+ leases = get_leases(lease_file, state='active', pool=args.pool)
+ else:
+ leases = get_leases(lease_file, state='active')
+
+ if args.json:
+ print(json.dumps(leases, indent=4))
+ else:
+ show_leases(leases)
+ elif args.statistics:
+ config = vyos.config.Config()
+
+ pools = []
+
+ # Get relevant pools
+ if args.pool:
+ pools = [args.pool]
+ else:
+ pools = config.list_effective_nodes("service dhcp-server shared-network-name")
+
+ # Get pool usage stats
+ stats = []
+ for p in pools:
+ size = get_pool_size(config, p)
+ leases = len(get_leases(lease_file, state='active', pool=args.pool))
+ use_percentage = round(leases / size) * 100
+ if args.json:
+ pool_stats = {"pool": p, "size": size, "leases": leases,
+ "available": (size - leases), "percentage": use_percentage}
+ else:
+ # For tabulate
+ pool_stats = [p, size, leases, size - leases, "{0}%".format(use_percentage)]
+ stats.append(pool_stats)
+
+ # Print stats
+ if args.json:
+ print(json.dumps(stats, indent=4))
+ else:
+ show_pool_stats(stats)
+ else:
+ print("Use either --leases or --statistics option")
diff --git a/src/op_mode/show_dhcpv6.py b/src/op_mode/show_dhcpv6.py
new file mode 100755
index 000000000..8879a45c5
--- /dev/null
+++ b/src/op_mode/show_dhcpv6.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import json
+import argparse
+import ipaddress
+
+import tabulate
+
+import vyos.config
+
+from isc_dhcp_leases import Lease, IscDhcpLeases
+
+
+lease_file = "/config/dhcpdv6.leases"
+
+def get_lease_data(lease):
+ data = {}
+
+ # End time may not be present in backup leases
+ try:
+ data["expires"] = lease.end.strftime("%Y/%m/%d %H:%M:%S")
+ except:
+ data["expires"] = ""
+
+ data["duid"] = lease.host_identifier_string
+ data["ip"] = lease.ip
+
+ return data
+
+def get_leases(leases, state=None):
+ leases = IscDhcpLeases(lease_file).get()
+
+ if state is not None:
+ leases = list(filter(lambda x: x.binding_state == 'active', leases))
+
+ return list(map(get_lease_data, leases))
+
+def show_leases(leases):
+ headers = ["IPv6 address", "Lease expiration", "DUID"]
+
+ lease_list = []
+ for l in leases:
+ lease_list.append([l["ip"], l["expires"], l["duid"]])
+
+ output = tabulate.tabulate(lease_list, headers)
+
+ print(output)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument("-l", "--leases", action="store_true", help="Show DHCP leases")
+ group.add_argument("-s", "--statistics", action="store_true", help="Show DHCP statistics")
+
+ parser.add_argument("-p", "--pool", type=str, action="store", help="Show lease for specific pool")
+ parser.add_argument("-j", "--json", action="store_true", default=False, help="Product JSON output")
+
+ args = parser.parse_args()
+
+ if args.leases:
+ leases = get_leases(lease_file, state='active')
+ show_leases(leases)
+ elif args.statistics:
+ print("DHCPv6 statistics option is not available")
+ else:
+ print("Invalid option")
diff --git a/src/op_mode/wireguard_key.py b/src/op_mode/wireguard.py
index 811cff1ca..14ee66aaf 100755
--- a/src/op_mode/wireguard_key.py
+++ b/src/op_mode/wireguard.py
@@ -19,18 +19,18 @@
import argparse
import os
import sys
-import syslog as sl
import subprocess
+import syslog as sl
from vyos import ConfigError
dir = r'/config/auth/wireguard'
pk = dir + '/private.key'
pub = dir + '/public.key'
+psk = dir + '/preshared.key'
-### check_kmod may be removed in the future,
-### once it's loaded automatically
def check_kmod():
+ """ check if kmod is loaded, if not load it """
if not os.path.exists('/sys/module/wireguard'):
sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod")
if os.system('sudo modprobe wireguard') != 0:
@@ -38,6 +38,7 @@ def check_kmod():
raise ConfigError("modprobe wireguard failed")
def generate_keypair():
+ """ generates a keypair which is stored in /config/auth/wireguard """
ret = subprocess.call(['wg genkey | tee ' + pk + '|wg pubkey > ' + pub], shell=True)
if ret != 0:
raise ConfigError("wireguard key-pair generation failed")
@@ -45,18 +46,20 @@ def generate_keypair():
sl.syslog(sl.LOG_NOTICE, "new keypair wireguard key generated in " + dir)
def genkey():
- ### if umask 077 makes trouble, 027 will work
+ """ helper function to check, regenerate the keypair """
old_umask = os.umask(0o077)
if os.path.exists(pk) and os.path.exists(pub):
- choice = input("You have a wireguard key-pair already, do you want to re-generate? [y/n] ")
+ choice = input("You already have a wireguard key-pair already, do you want to re-generate? [y/n] ")
if choice == 'y' or choice == 'Y':
generate_keypair()
else:
- os.mkdir(dir)
+ if not os.path.exists(dir):
+ os.mkdir(dir)
generate_keypair()
os.umask(old_umask)
def showkey(key):
+ """ helper function to show privkey or pubkey """
if key == "pub":
if os.path.exists(pub):
print ( open(pub).read().strip() )
@@ -69,6 +72,10 @@ def showkey(key):
else:
print("no private key found")
+def genpsk():
+ """ generates a preshared key and shows it on stdout, it's stroed only in the config """
+ subprocess.call(['wg genpsk'], shell=True)
+
if __name__ == '__main__':
check_kmod()
@@ -76,6 +83,7 @@ if __name__ == '__main__':
parser.add_argument('--genkey', action="store_true", help='generate key-pair')
parser.add_argument('--showpub', action="store_true", help='shows public key')
parser.add_argument('--showpriv', action="store_true", help='shows private key')
+ parser.add_argument('--genpsk', action="store_true", help='generates preshared-key')
args = parser.parse_args()
try:
@@ -85,6 +93,8 @@ if __name__ == '__main__':
showkey("pub")
if args.showpriv:
showkey("pk")
+ if args.genpsk:
+ genpsk()
except ConfigError as e:
print(e)