ppp
ppp copied to clipboard
[RFE] Option to use SystemdCreds to read user+password
To enhance the systemd integration (see #79 and https://github.com/systemd/systemd/issues/481) even more, i suggest to add an option to allow automatic reading of System and Service Credentials or SystemdCreds as i like to name them.
- An option named
sd_credsfor example, the exact naming is up to you.
When this option is used, pppd should automatically read and use:
- The value for
userfrom the SystemdCreds, fe. from thePPPoE-usernamecredential. (the exact naming is up to you) - The value for
passwordfrom the SystemdCreds, fe. from thePPPoE-passwordcredential. (the exact naming is up to you)
To illustrate the usage and workaround until this functionality is implemented
I'm currently using the below self-made scripts and configs in my System, which i post here for others to use till then: (Still a W.I.P. but it already works flawlessly)
Click the arrowed sections to expand and view (and be able to copy them)...
[email protected]
# <configdir>/[email protected]
# SPDX-License-Identifier: CC-BY-NC-SA-4.0
#
# You should enable this unit with the interface as instance name.
# eg. [email protected] / [email protected]
# You can disregard the warning about the adition as a dependency to
# a non-existant unit 'sys-subsystem-net-devices-xxxx.device',
# this is expected behaviour...
#
# VLAN etc usage:
# Your normal network config should create the virtual network device,
# so this service automatically gets started after it.
# eg. a "VLAN=VlanID" inside eth0.network, with a corrosponding
# "VlanID.netdev" (and "VlanID.network" if needed)
[Unit]
Description=Target for %p connections on %I
Documentation=man:systemd.unit(5)#Specifiers
Documentation=man:systemd.target
# This target is NOT a "SysV run-level" like target.
AllowIsolate=no
# See: https://systemd.io/NETWORK_ONLINE/
After=network.target
BindsTo=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
PartOf=sys-subsystem-net-devices-%i.device
# avoid race waiting for systemd-networkd to configure interface
# https://github.com/systemd/systemd/issues/481#issuecomment-1010092917
# systemd guarentees MTU is set before activating (carrier) link
# https://github.com/systemd/systemd/issues/481#issuecomment-1010159176
After=systemd-networkd-wait-online@%i.service
[Install]
WantedBy=sys-subsystem-net-devices-%i.device
# WantedBy=sys-devices-virtual-net-%i.device
[email protected]/DefaultInstance.conf
# <configdir>/[email protected]/DefaultInstance.conf
# SPDX-License-Identifier: CC-BY-NC-SA-4.0
#
# Optional: Default instance to enable when the template is attempted
# to be enabled without an instance name, which isn't allowed.
[Install]
DefaultInstance=vlan35
[email protected]/KernelCommandLine.conf
# <configdir>/[email protected]/KernelCommandLine.conf
# SPDX-License-Identifier: CC-BY-NC-SA-4.0
#
# Optional: Only allow activation when a special KernelCommandLine option is present.
[Unit]
ConditionKernelCommandLine=pppoe
[email protected]/TurkNet.conf
# <configdir>/[email protected]/TurkNet.conf
# SPDX-License-Identifier: CC-BY-NC-SA-4.0
#
# Auto start/restart the instance unit below.
# In this case '%j-%i' will be: 'PPPoE-vlan35'
[Unit]
Upholds=%j-%[email protected]
[email protected]
# <configdir>/[email protected]
# SPDX-License-Identifier: CC-BY-NC-SA-4.0
#
# You should make a copy of this template with the interface name as
# the final component of the prefix as the unit name.
# This final component of the prefix is used as the interface to run the PPPoE
# connection over.
# Eg. to use "vlan35" as interface name to run the PPPoE over you should name
# the template: '[email protected]'
#
# To view journal logs of your instance unit:
# journalctl -u PPPoE-vlan35@MyISP
#
[Unit]
Description=%I connection on PPPoE@%j
Documentation=man:pppd(8)
Documentation=https://github.com/ppp-project/ppp/issues/459
Documentation=https://github.com/systemd/systemd/issues/481#issuecomment-544337575
Documentation=https://github.com/jimdigriz/debian-clearfog-gt-8k#libsystemdsystempppdservice
# Refuse to start without a corrosponding peer file !
# AssertPathExists=/etc/ppp/peers/%I
BindsTo=PPPoE@%j.target
After=PPPoE@%j.target
PartOf=PPPoE@%j.target
# [Install]
# WantedBy=%p.target
[Service]
# https://github.com/ppp-project/ppp/commit/d34159f417620eb7c481bf53f29fe04c86ccd223
# otherwsise you can use 'forking' and replace 'up_sdnotify' with 'updetach'
Type=notify
# Type=oneshot
IPAccounting=yes
# StandardOutput=null
# Environment="pppd_opts0=plugin rp-pppoe.so nic-%J linkname %I ifname %I call %I up_sdnotify"
# Environment="pppd_opts1=persist default-mru nolog noauth debug pppoe-verbose 1 holdoff 5 lcp-echo-adaptive"
Environment="pppd_opts1=default-mru debug pppoe-verbose 1 holdoff 5"
# Maybe add 'noipdefault' but seems NOT needed...
# Environment="pppd_opts2=+ipv6 ipv6cp-use-persistent"
# Optional:
# Environment="pppd_opts3=defaultroute defaultroute6 replacedefaultroute"
# IPv4 default route is needed, IPv6 doesn't seem to need...
Environment="pppd_opts3=defaultroute"
ExecStart=/usr/sbin/pppd $pppd_opts0 $pppd_opts1 $pppd_opts2 $pppd_opts3
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT
RestartKillSignal=SIGHUP
RestartSec=5s
TimeoutStopSec=5s
Restart=on-failure
#
# # https://github.com/systemd/systemd/issues/481#issuecomment-544341423
# # Restart=always
# Pppd terminated because it was sent a SIGINT, SIGTERM or SIGHUP signal.
SuccessExitStatus=5
# The link was established successfully and terminated because it was idle.
SuccessExitStatus=12
# The link was established successfully and terminated because the connect time limit was reached.
SuccessExitStatus=13
# Callback was negotiated and an incoming call should arrive shortly.
# SuccessExitStatus=14
# An error was detected in processing the options given, such as two mutually exclusive options being used.
RestartPreventExitStatus=2
# The kernel does not support PPP, for example, the PPP kernel driver is not included or cannot be loaded.
RestartPreventExitStatus=4
# The connect script failed (returned a non-zero exit status).
RestartPreventExitStatus=8
# The PPP negotiation failed, that is, it didn't reach the point where at least one network protocol (e.g. IP) was running.
# RestartPreventExitStatus=10
# The peer system failed (or refused) to authenticate itself.
RestartPreventExitStatus=11
# The init script failed (returned a non-zero exit status).
RestartPreventExitStatus=18
# The PPP negotiation failed, that is, it didn't reach the point where at least one network protocol (e.g. IP) was running.
RestartForceExitStatus=10
# Callback was negotiated and an incoming call should arrive shortly.
RestartForceExitStatus=14
# The link was terminated because the peer is not responding to echo requests.
RestartForceExitStatus=15
# The link was terminated by the modem hanging up.
RestartForceExitStatus=16
# We failed to authenticate ourselves to the peer.
RestartForceExitStatus=19
# HARDENING
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=strict
# allow /etc/ppp/resolv.conf to be written when using 'usepeerdns'
ReadWritePaths=/run/ /etc/ppp/
# https://github.com/systemd/systemd/issues/481#issuecomment-610951209
#ProtectKernelTunables=yes
ProtectControlGroups=yes
SystemCallFilter=~@mount
SystemCallArchitectures=native
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
[email protected]/KernelCommandLine.conf
# <configdir>/[email protected]/KernelCommandLine.conf
# SPDX-License-Identifier: CC-BY-NC-SA-4.0
#
# Optional: Only allow activation when a special KernelCommandLine option is present.
[Unit]
ConditionKernelCommandLine=pppoe
[email protected]/Credentials.conf
# <configdir>/[email protected]/Credentials.conf
# PPPoE-Credentials for TurkNet@vlan35
[Service]
SetCredentialEncrypted=PPPoE-username: \
Whxqht+dQJax1aZeCGLxmiAAAAABAAAADAAAABAAAADY5KqFUJ+YZhTQOOoAAAAAClClv \
M7s8F3TQIm0e7+0LufdC+6eFdTvtpDSi9ecJUG1FJivZteUua52jVaZ1PuGL8DoqeVFYQ \
pL9A2kXo5zduY7QUO10auWbR6B4Q==
SetCredentialEncrypted=PPPoE-password: \
Whxqht+dQJax1aZeCGLxmiAAAAABAAAADAAAABAAAADEUFVtTvt2IqKxipQAAAAA/IGhP \
x+PfeA5OiDE/I/O7ARi8X7MHGocMrB216kRlaAX37JSXsU4+hVJFBgfH8MN7VcA6/mThc \
6BIR09VLIbiaiY
[email protected]/UseCredentials.conf
# <configdir>/[email protected]/UseCredentials.conf
# SPDX-License-Identifier: CC-BY-NC-SA-4.0
#
[Unit]
Documentation=https://systemd.io/CREDENTIALS
# NOTE: Needed because pppd still lacks ability to read Systemd-Credentials...
[Service]
ExecStartPre= @bash 'AutoConfigGenerator_%p' -c \n"\
printf \"%%s\\t%%s\\n\" \\\n\
\"user\" \"$$(<%d/PPPoE-username)\" \\\n\
\"password\" \"$$(<%d/PPPoE-password)\" \\\n\
\"plugin\" \"rp-pppoe.so\" \\\n\
\"nic-%J\" \"\" \\\n\
\"linkname\" \"%I\" \\\n\
\"ifname\" \"%I\" \\\n\
\"up_sdnotify\" \"\" \\\n\
\"persist\" \"\" \\\n\
\"nolog\" \"\" \\\n\
\"noauth\" \"\" \\\n\
\"lcp-echo-adaptive\" \"\" \\\n\
\"+ipv6\" \"\" \\\n\
\"ipv6cp-use-persistent\" \"\" \\\n\
>/tmp/AutoConfig_%p_%I\n\
"
# ExecStartPre=cat /tmp/AutoConfig_%p_%I
ExecStart=
ExecStart= /usr/sbin/pppd file /tmp/AutoConfig_%p_%I $pppd_opts1 $pppd_opts2 $pppd_opts3
<bin path>/createSystemdCreds-PPPoE
#!/usr/bin/env bash
# SPDX-License-Identifier: CC-BY-NC-SA-4.0
#
# To use the creds you could use one of:
# 1.
# Environment=CRED_USERNAME=%d/PPPoE-username
# Environment=CRED_PASSWORD=%d/PPPoE-password
# cat $CRED_USERNAME
# cat $CRED_PASSWORD
# 2.
# cat %d/PPPoE-username
# cat %d/PPPoE-password
# See: man systemd-creds
# NOTE: The example in the man-page has a bug !
# it doesn't output the section header, so we need to !
#
# $1 = username
# $2 = password
function genSystemdCred () {
local -a opts
local \
credName \
credVal
# Output the header and section name at start
printf "%s\n" \
"# PPPoE-Credentials for ${connection}@${interface}" \
"[Service]"
# Output the creds lines
for credName in username password; do
case "${credName}" in
username) credVal="$1" ;;
password) credVal="$2" ;;
*) ;; # No other posibilities.
esac
opts=(
--pretty
--name="PPPoE-${credName}"
encrypt
# Input = stdin
-
# Output = stdout
-
)
# shellcheck disable=2312
printf "%s" "${credVal}" \
| systemd-creds "${opts[@]}" \
| sed -E 's/\s{2,}/\t/g' # Convert multiple white-space by a single tab.
done
}
function main () {
local -a opts
local \
username \
password \
connection \
interface \
dropInDir \
credName
username="$1"
password="$2"
connection="$3"
interface="$4"
if test -z "${username}" \
-o -z "${password}" \
-o -z "${connection}" \
-o -z "${interface}"
then
printf "%s\n" \
"Missing arguments !" \
"Usage: ${0##*/} <username> <password> <connection> <interface>"
exit 64 # EX_USAGE - Command line usage error
fi
# Generate the drop-in dir
printf -v dropInDir "PPPoE-%s@%s.service.d" \
"${interface}" \
"${connection}"
printf "%s\n" \
"username: ${username}" \
"password: ${password}" \
"connection: ${connection}" \
"interface: ${interface}" \
"drop-in dir: ${dropInDir}" \
""
# Create the drop-in dir if non-existant.
if test ! -d "${dropInDir}"; then
opts=(
--verbose
--directory
--mode=2750
--group=systemd-network
)
install "${opts[@]}" "${dropInDir}"
# Give access to admins.
setfacl --modify g:adm:rwX,g:sudo:rwX,d:g:adm:rwX,d:g:sudo:rwX "${dropInDir}"
fi
genSystemdCred \
"${username}" \
"${password}" \
>"${dropInDir}/Credentials.conf"
}
# We need to run as ROOT !
# shellcheck disable=2312
if test "$(id -u)" -ne 0; then
exec sudo "$0" "$@"
else
main "$@"
fi
The last three are the SystemdCreds specific parts obviously :wink:
- The
[email protected]/Credentials.confdir+file was auto-generated using thecreateSystemdCreds-PPPoEscript... :warning: It will NOT work for you as-is, so you need to generate your own ! - The
[email protected]/UseCredentials.confdrop-in overrides theExecStartof the main template to read a config file that is auto-generated to implement the automatic reading and usage of theSystemdCreds. As you can see the is FAR from optimal because it uses a temporary file which can be eliminated if the functionality asked-for is implemented. (It is still relatively safe to use, because of the private tmp used in the hardening this file is only readable by ROOT...)
[!NOTE] I use the below parts for tearing down DynNS config.
If you don't make/need use of that functionality; you can safely disregard these parts, and you have no need to install the
/etc/ppp/ip-pre-downand/etc/ppp/ipv6-pre-downscripts with accompanying directories they use...
[email protected]/DynNS-TearDown.conf
# <configdir>/[email protected]/DynNS-TearDown.conf
# SPDX-License-Identifier: CC-BY-NC-SA-4.0
#
# For DynNS teardown BEFORE the connection gets terminated...
[Service]
# ExecStop= -run-parts /etc/ppp/ip-pre-down.d
ExecStop= -/etc/ppp/ip-pre-down %I
# ExecStop= -run-parts /etc/ppp/ipv6-pre-down.d
ExecStop= -/etc/ppp/ipv6-pre-down %I
# ExecStop=/bin/kill $MAINPID
/etc/ppp/ip-pre-down
#!/bin/sh
# The environment is cleared before executing this script
# so the path must be reset.
PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin
export PATH
# These variables are for the use of the scripts run by run-parts
PPP_IFACE="$1"
export PPP_IFACE
# If /var/log/ppp-ipupdown.log exists use it for logging.
if [ -e /var/log/ppp-ipupdown.log ]; then
exec >> /var/log/ppp-ipupdown.log 2>&1
echo "$0" "$@"
echo
fi
# This script can be used to override the .d files supplied by other packages.
if [ -x /etc/ppp/ip-pre-down.local ]; then
exec /etc/ppp/ip-pre-down.local "$@"
fi
run-parts /etc/ppp/ip-pre-down.d \
--arg="$1"
/etc/ppp/ipv6-pre-down
#!/bin/sh
# The environment is cleared before executing this script
# so the path must be reset.
PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin
export PATH
# These variables are for the use of the scripts run by run-parts
PPP_IFACE="$1"
export PPP_IFACE
# If /var/log/ppp-ipupdown.log exists use it for logging.
if [ -e /var/log/ppp-ipupdown.log ]; then
exec >> /var/log/ppp-ipupdown.log 2>&1
echo "$0" "$@"
echo
fi
# This script can be used to override the .d files supplied by other packages.
if [ -x /etc/ppp/ipv6-pre-down.local ]; then
exec /etc/ppp/ipv6-pre-down.local "$@"
fi
run-parts /etc/ppp/ipv6-pre-down.d \
--arg="$1"
[!NOTE] To @ppp-project members: You might consider adding this
pre-downfunctionality topppditself, so they get automatically called BEFORE the connection gets teared down, if wanted by the user. :handshake:
And i use these systemd-networked files for the connection configs:
(My onboard Ethernet connection is renamed to utp)
21-pppoe-vlan35.netdev
# <includedir>/.21-pppoe-vlan35.netdev
[NetDev]
Description=Internet VLAN of ISP.
Name=vlan35
Kind=vlan
[VLAN]
Id=35
GVRP=yes
MVRP=yes
ReorderHeader=yes
# <includedir>/.21-pppoe-vlan35.netdev.d/00-Match: KernelCommandLine=pppoe.conf
[Match]
KernelCommandLine=pppoe
21-pppoe-vlan35.network
# <includedir>/.21-pppoe-vlan35.network
[Match]
Name=vlan35
[Network]
Description=Internet VLAN of ISP.
# <includedir>/.21-pppoe-vlan35.network.d/00-Match: KernelCommandLine=pppoe.conf
[Match]
KernelCommandLine=pppoe
# <includedir>/.21-pppoe-vlan35.network.d/01-Link: ARP=yes.conf
[Link]
ARP=yes
# <includedir>/.21-pppoe-vlan35.network.d/01-Link: AllMulticast=yes.conf
[Link]
AllMulticast=yes
# <includedir>/.21-pppoe-vlan35.network.d/01-Link: Group=1.conf
[Link]
Group=1
# <includedir>/.21-pppoe-vlan35.network.d/01-Link: Multicast=yes.conf
[Link]
Multicast=yes
# <includedir>/.21-pppoe-vlan35.network.d/01-Link: RequiredForOnline=carrier.conf
[Link]
RequiredForOnline=carrier
# <includedir>/.21-pppoe-vlan35.network.d/02-Network: BindCarrier=utp.conf
[Network]
BindCarrier=utp
# <includedir>/.21-pppoe-vlan35.network.d/02-Network: LinkLocalAddressing=no.conf
[Network]
LinkLocalAddressing=no
30-pppoe-TurkNet.network
# <includedir>/.30-pppoe-TurkNet.network
[Match]
Name=TurkNet
Type=ppp
# <includedir>/.30-pppoe-TurkNet.network.d/00-Match: KernelCommandLine=pppoe.conf
[Match]
KernelCommandLine=pppoe
# <includedir>/.30-pppoe-TurkNet.network.d/02-Network: BindCarrier=vlan35.conf
[Network]
BindCarrier=vlan35
# <includedir>/.30-pppoe-TurkNet.network.d/02-Network: DHCP=yes.conf
[Network]
DHCP=yes
# <includedir>/.30-pppoe-TurkNet.network.d/04-DHCPv4.conf
[DHCPv4]
Hostname=Linux
UseDNS=no
UseNTP=no
UseMTU=yes
UseDomains=route
SendDecline=yes
UseHostname=no
# <includedir>/.30-pppoe-TurkNet.network.d/04-DHCPv6-uplink.conf
[Network]
IPv6AcceptRA=yes
IPv6PrivacyExtensions=prefer-public
IPv6SendRA=no
DHCPPrefixDelegation=yes
[DHCPv6]
UseHostname=no
UseDNS=no
UseNTP=no
[DHCPPrefixDelegation]
UplinkInterface=:self
SubnetId=::1
Announce=no
Assign=yes
Token=static:::1
[IPv6AcceptRA]
UseDNS=no
UseDomains=route
[!NOTE] This config does NOT make use of the DNS/NTP/etc setting provided by the DHCP-Server from the ISP, if you need to make use of those you can tweak the systemd-networkd config options inside. I use my own settings on my system, that's why i disabled usage of those.
Update:
For easier testing etc of the posted files, i have created a public repo where they can be found. It will also function as a backup for my own setup :wink: https://gitlab.com/trimoon-inc/system/systemd-PPPoE
This all sounds reasonable at first glance. What functions would pppd need to call to read the user and password values?
@paulusmack
It just needs to read the contents of files inside the $CREDENTIALS_DIRECTORY directory.
See: https://systemd.io/CREDENTIALS/#programming-interface-from-service-code
[!NOTE]
$CREDENTIALS_DIRECTORYis an environment variable provided for processes executed by the service.$CREDENTIALS_DIRECTORY=%din unit files...
If you use the names i used in my examples those files would be:
${CREDENTIALS_DIRECTORY}/PPPoE-username(The contents will already be the decrypted value to be used)${CREDENTIALS_DIRECTORY}/PPPoE-password(The contents will already be the decrypted value to be used)
But as said you're free to choose other names, or even let the user choose which names to use :wink:
It basically boils down to automatically read the contents of those files and use them "as-if" the user provided those options with their values.... That is what i am actually doing in these lines:
[email protected]/UseCredentials.conf
\"user\" \"$$(<%d/PPPoE-username)\" \\\n\ \"password\" \"$$(<%d/PPPoE-password)\" \\\n\
@paulusmack a followup from your side would be appreciated :wink:
@paulusmack: Have you seen latest @TriMoon comments?