summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/CONTRIBUTING.md26
-rw-r--r--.github/RELEASE.md12
-rw-r--r--CODING_STYLE17
-rw-r--r--Makefile.am8
-rw-r--r--TODO5
-rw-r--r--catalog/systemd.be.catalog71
-rw-r--r--catalog/systemd.be@latin.catalog76
-rw-r--r--hwdb/70-mouse.hwdb6
-rw-r--r--man/machinectl.xml7
-rw-r--r--man/os-release.xml16
-rw-r--r--man/systemd-nspawn.xml13
-rw-r--r--man/systemd-resolve.xml6
-rw-r--r--man/systemd-resolved.service.xml22
-rw-r--r--man/systemd.exec.xml27
-rw-r--r--man/systemd.network.xml130
-rw-r--r--man/systemd.nspawn.xml9
-rw-r--r--man/systemd.service.xml7
-rw-r--r--po/be.po109
-rw-r--r--po/be@latin.po109
-rw-r--r--po/es.po81
-rw-r--r--po/tr.po110
-rw-r--r--rules/60-persistent-storage.rules2
-rw-r--r--shell-completion/bash/machinectl2
-rw-r--r--shell-completion/zsh/_machinectl1
-rw-r--r--src/basic/exit-status.c18
-rw-r--r--src/basic/exit-status.h16
-rw-r--r--src/basic/in-addr-util.c105
-rw-r--r--src/basic/in-addr-util.h5
-rw-r--r--src/basic/macro.h9
-rw-r--r--src/basic/missing.h8
-rw-r--r--src/basic/process-util.c19
-rw-r--r--src/basic/random-util.c2
-rw-r--r--src/basic/time-util.c72
-rw-r--r--src/basic/time-util.h27
-rw-r--r--src/basic/unaligned.h18
-rw-r--r--src/cgtop/cgtop.c4
-rw-r--r--src/core/execute.c83
-rw-r--r--src/core/execute.h3
-rw-r--r--src/core/load-fragment.c17
-rw-r--r--src/core/manager.c15
-rw-r--r--src/core/mount.c1
-rw-r--r--src/fstab-generator/fstab-generator.c6
-rw-r--r--src/hwdb/hwdb.c8
-rw-r--r--src/libsystemd-network/icmp6-util.c7
-rw-r--r--src/libsystemd-network/lldp-internal.h2
-rw-r--r--src/libsystemd-network/lldp-neighbor.c49
-rw-r--r--src/libsystemd-network/lldp-neighbor.h8
-rw-r--r--src/libsystemd-network/ndisc-internal.h49
-rw-r--r--src/libsystemd-network/ndisc-router.c779
-rw-r--r--src/libsystemd-network/ndisc-router.h62
-rw-r--r--src/libsystemd-network/network-internal.c15
-rw-r--r--src/libsystemd-network/sd-lldp.c105
-rw-r--r--src/libsystemd-network/sd-ndisc.c551
-rw-r--r--src/libsystemd-network/test-lldp.c8
-rw-r--r--src/libsystemd-network/test-ndisc-rs.c163
-rw-r--r--src/libsystemd/sd-event/sd-event.c56
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c10
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c5
-rw-r--r--src/login/logind-action.c4
-rw-r--r--src/machine/machinectl.c1
-rw-r--r--src/network/networkd-address.c72
-rw-r--r--src/network/networkd-address.h2
-rw-r--r--src/network/networkd-brvlan.c329
-rw-r--r--src/network/networkd-brvlan.h29
-rw-r--r--src/network/networkd-dhcp6.c15
-rw-r--r--src/network/networkd-fdb.c34
-rw-r--r--src/network/networkd-fdb.h4
-rw-r--r--src/network/networkd-link.c106
-rw-r--r--src/network/networkd-link.h8
-rw-r--r--src/network/networkd-ndisc.c534
-rw-r--r--src/network/networkd-ndisc.h39
-rw-r--r--src/network/networkd-netdev-gperf.gperf5
-rw-r--r--src/network/networkd-netdev-vlan.c15
-rw-r--r--src/network/networkd-netdev-vlan.h4
-rw-r--r--src/network/networkd-network-bus.c2
-rw-r--r--src/network/networkd-network-gperf.gperf8
-rw-r--r--src/network/networkd-network.c9
-rw-r--r--src/network/networkd-network.h15
-rw-r--r--src/network/networkd-route.c126
-rw-r--r--src/network/networkd-route.h8
-rw-r--r--src/nspawn/nspawn-gperf.gperf1
-rw-r--r--src/nspawn/nspawn-settings.h4
-rw-r--r--src/nspawn/nspawn.c195
-rw-r--r--src/resolve/resolve-tool.c36
-rw-r--r--src/resolve/resolved-bus.c36
-rw-r--r--src/resolve/resolved-conf.c12
-rw-r--r--src/resolve/resolved-dns-scope.c15
-rw-r--r--src/resolve/resolved-dns-server.c36
-rw-r--r--src/resolve/resolved-dns-server.h7
-rw-r--r--src/resolve/resolved-link-bus.c53
-rw-r--r--src/resolve/resolved-link.c4
-rw-r--r--src/resolve/resolved-manager.c31
-rw-r--r--src/resolve/resolved-manager.h3
-rw-r--r--src/resolve/resolved-resolv-conf.c25
-rw-r--r--src/resolve/resolved.c9
-rw-r--r--src/shared/bus-util.c13
-rw-r--r--src/shared/vlan-util.c69
-rw-r--r--src/shared/vlan-util.h35
-rw-r--r--src/systemctl/systemctl.c257
-rw-r--r--src/systemd/sd-lldp.h15
-rw-r--r--src/systemd/sd-ndisc.h114
-rw-r--r--src/systemd/sd-netlink.h2
-rw-r--r--src/sysv-generator/sysv-generator.c27
-rw-r--r--src/test/test-process-util.c79
-rw-r--r--src/test/test-socket-util.c51
-rw-r--r--src/test/test-unaligned.c24
-rw-r--r--src/udev/udev-builtin-blkid.c10
-rwxr-xr-xtest/networkd-test.py4
-rw-r--r--units/systemd-hostnamed.service.in2
-rw-r--r--units/systemd-importd.service.in2
-rw-r--r--units/systemd-journald.service.in2
-rw-r--r--units/systemd-localed.service.in2
-rw-r--r--units/systemd-logind.service.in2
-rw-r--r--units/systemd-machined.service.in2
-rw-r--r--units/systemd-networkd.service.m4.in2
-rw-r--r--units/systemd-resolved.service.m4.in2
-rw-r--r--units/systemd-timedated.service.in2
-rw-r--r--units/systemd-timesyncd.service.in2
118 files changed, 4391 insertions, 1342 deletions
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 60f0fb9bef..4857e94733 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -1,34 +1,26 @@
# Contributing
-We welcome contributions from everyone. However, please follow the following guidelines when posting a GitHub Pull
-Request or filing a GitHub Issue on the systemd project:
+We welcome contributions from everyone. However, please follow the following guidelines when posting a GitHub Pull Request or filing a GitHub Issue on the systemd project:
## Filing Issues
-* We use GitHub Issues **exclusively** for tracking **bugs** and **feature** **requests** of systemd. If you are
- looking for help, please contact our [mailing list](http://lists.freedesktop.org/mailman/listinfo/systemd-devel)
- instead.
-* We only track bugs in the **two** **most** **recently** **released** **versions** of systemd in the GitHub Issue
- tracker. If you are using an older version of systemd, please contact your distribution's bug tracker instead.
-* When filing an issue, specify the **systemd** **version** you are experiencing the issue with. Also, indicate which
- **distribution** you are using.
+* We use GitHub Issues **exclusively** for tracking **bugs** and **feature** **requests** of systemd. If you are looking for help, please contact our [mailing list](http://lists.freedesktop.org/mailman/listinfo/systemd-devel) instead.
+* We only track bugs in the **two** **most** **recently** **released** **versions** of systemd in the GitHub Issue tracker. If you are using an older version of systemd, please contact your distribution's bug tracker instead.
+* When filing an issue, specify the **systemd** **version** you are experiencing the issue with. Also, indicate which **distribution** you are using.
* Please include an explanation how to reproduce the issue you are pointing out.
-Following these guidelines makes it easier for us to process your issue, and ensures we won't close your issue
-right-away for being misfiled.
+Following these guidelines makes it easier for us to process your issue, and ensures we won't close your issue right-away for being misfiled.
## Posting Pull Requests
* Make sure to post PRs only relative to a very recent git master.
-* Follow our [Coding Style](https://raw.githubusercontent.com/systemd/systemd/master/CODING_STYLE) when contributing
- code. This is a requirement for all code we merge.
-* Make sure to run "make check" locally, before posting your PR. We use a CI system, meaning we don't even look at your
- PR, if the build and tests don't pass.
+* Follow our [Coding Style](https://raw.githubusercontent.com/systemd/systemd/master/CODING_STYLE) when contributing code. This is a requirement for all code we merge.
+* Make sure to run "make check" locally, before posting your PR. We use a CI system, meaning we don't even look at your PR, if the build and tests don't pass.
* If you need to update the code in an existing PR, force-push into the same branch, overriding old commits with new versions.
+* After you have pushed a new version, try to remove the `reviewed/needs-rework` label. Also add a comment about the new version (no notification is sent just for the commits, so it's easy to miss the update without an explicit comment).
## Final Words
-We'd like to apologize in advance if we are not able to process and reply to your issue or PR right-away. We have a lot
-of work to do, but we are trying our best!
+We'd like to apologize in advance if we are not able to process and reply to your issue or PR right-away. We have a lot of work to do, but we are trying our best!
Thank you very much for your contributions!
diff --git a/.github/RELEASE.md b/.github/RELEASE.md
new file mode 100644
index 0000000000..2807667a30
--- /dev/null
+++ b/.github/RELEASE.md
@@ -0,0 +1,12 @@
+# Steps to a successful release
+
+1. Add all items to NEWS
+2. Update the contributors list in NEWS ("make git-contrib")
+3. Update the time and place in NEWS
+4. Update version in configure.ac and library numbers in Makefile.am
+5. Check that "make distcheck" works
+6. Tag the release ("make git-tag")
+7. Upload the documentation ("make doc-sync")
+8. Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
+9. Send announcement to systemd-devel, with a copy&paste from NEWS
+10. Update IRC topic ("/msg chanserv TOPIC #systemd Version NNN released")
diff --git a/CODING_STYLE b/CODING_STYLE
index b689355c9a..e762d42edb 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -382,3 +382,20 @@
tools, and we should continue to do so, as it makes it easy to
identify command line parameter variables, and makes it clear why it
is OK that they are global variables.
+
+- When exposing public C APIs, be careful what function parameters you make
+ "const". For example, a parameter taking a context object should probably not
+ be "const", even if you are writing an other-wise read-only accessor function
+ for it. The reason is that making it "const" fixates the contract that your
+ call won't alter the object ever, as part of the API. However, that's often
+ quite a promise, given that this even prohibits object-internal caching or
+ lazy initialization of object variables. Moreover it's usually not too useful
+ for client applications. Hence: please be careful and avoid "const" on object
+ parameters, unless you are very sure "const" is appropriate.
+
+- Make sure to enforce limits on every user controllable resource. If the user
+ can allocate resources in your code, your code must enforce some form of
+ limits after which it will refuse operation. It's fine if it is hardcoded (at
+ least initially), but it needs to be there. This is particularly important
+ for objects that unprivileged users may allocate, but also matters for
+ everything else any user may allocated.
diff --git a/Makefile.am b/Makefile.am
index de3013567e..e8b50ce054 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1047,6 +1047,8 @@ libshared_la_SOURCES = \
src/shared/resolve-util.h \
src/shared/bus-unit-util.c \
src/shared/bus-unit-util.h \
+ src/shared/vlan-util.h \
+ src/shared/vlan-util.c \
src/shared/tests.h \
src/shared/tests.c
@@ -3435,6 +3437,9 @@ libsystemd_network_la_SOURCES = \
src/libsystemd-network/network-internal.c \
src/libsystemd-network/network-internal.h \
src/libsystemd-network/sd-ndisc.c \
+ src/libsystemd-network/ndisc-internal.h \
+ src/libsystemd-network/ndisc-router.h \
+ src/libsystemd-network/ndisc-router.c \
src/libsystemd-network/icmp6-util.h \
src/libsystemd-network/icmp6-util.c \
src/libsystemd-network/sd-dhcp6-client.c \
@@ -5481,6 +5486,7 @@ libnetworkd_core_la_SOURCES = \
src/network/networkd-ipv4ll.c \
src/network/networkd-dhcp4.c \
src/network/networkd-dhcp6.c \
+ src/network/networkd-ndisc.h \
src/network/networkd-ndisc.c \
src/network/networkd-network.h \
src/network/networkd-network.c \
@@ -5493,6 +5499,8 @@ libnetworkd_core_la_SOURCES = \
src/network/networkd-manager-bus.c \
src/network/networkd-fdb.h \
src/network/networkd-fdb.c \
+ src/network/networkd-brvlan.h \
+ src/network/networkd-brvlan.c \
src/network/networkd-address-pool.h \
src/network/networkd-address-pool.c \
src/network/networkd-util.h \
diff --git a/TODO b/TODO
index ecd36c1142..aeed0c84d2 100644
--- a/TODO
+++ b/TODO
@@ -51,6 +51,9 @@ Features:
* journalctl: make sure -f ends when the container indicated by -M terminates
+* expose the "privileged" flag of ExecCommand on the bus, and open it up to
+ transient units
+
* rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the
kernel doesn't support linkat() that replaces existing files, currently)
@@ -70,6 +73,8 @@ Features:
* optionally, also require WATCHDOG=1 notifications during service start-up and shutdown
+* resolved: when routing queries, make sure only look for the *longest* suffix...
+
* resolved: maybe, after all, implement local listening for DNS packets on port
127.0.0.53:53.
diff --git a/catalog/systemd.be.catalog b/catalog/systemd.be.catalog
index 051f49492f..cd62d9786e 100644
--- a/catalog/systemd.be.catalog
+++ b/catalog/systemd.be.catalog
@@ -1,7 +1,7 @@
# This file is part of systemd.
#
# Copyright 2012 Lennart Poettering
-# Copyright 2015 Viktar Vaŭčkievič
+# Copyright 2015, 2016 Viktar Vaŭčkievič
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
@@ -19,7 +19,6 @@
# Message catalog for systemd's own messages
# Belarusian translation
-# The catalog format is documented on
# Фармат каталога апісаны на старонцы
# http://www.freedesktop.org/wiki/Software/systemd/catalog
@@ -40,6 +39,22 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Працэс сістэмнага журналявання спыніўся і закрыў усе файлы.
+-- ec387f577b844b8fa948f33cad9a75e6
+Subject: Дыскавае месца, занятае часопісам
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@JOURNAL_NAME@ (@JOURNAL_PATH@) цяпер займае @CURRENT_USE_PRETTY@.
+Максімальна дазволены памер складае @MAX_USE_PRETTY@.
+Пакідаем вольнымі не меньш за @DISK_KEEP_FREE_PRETTY@ (даступна на дыску
+@DISK_AVAILABLE_PRETTY@).
+Такім чынам, ліміт складае @LIMIT_PRETTY@, з якіх @AVAILABLE_PRETTY@
+даступна.
+
+Ліміты на памер наладжваецца з дапамогай SystemMaxUse=, SystemKeepFree=,
+SystemMaxFileSize=, RuntimeMaxUse=, RuntimeKeepFree=, RuntimeMaxFileSize= у
+файле /etc/systemd/journald.conf. Глядзіце journald.conf(5) для дэталей.
+
-- a596d6fe7bfa4994828e72309e95d61e
Subject: Паведамленні з сэрвісу адкінуты
Defined-By: systemd
@@ -52,9 +67,9 @@ Documentation: man:journald.conf(5)
Майце на ўвазе, што былі адкінуты паведамлення толькі гэтага сэрвісу.
Паведамленні іншых сэрвісаў засталіся.
-Мяжа, пасля якой паведамленні будуць адкінуты, наладжваецца з
-дапамогай RateLimitIntervalSec= і RateLimitBurst= у файле
-/etc/systemd/journald.conf. Глядзіце journald.conf(5) для дэталей.
+Мяжа, пасля якой паведамленні будуць адкінуты, наладжваецца з дапамогай
+RateLimitIntervalSec= і RateLimitBurst= у файле /etc/systemd/journald.conf.
+Глядзіце journald.conf(5) для дэталей.
-- e9bf28e6e834481bb6f48f548ad13606
Subject: Паведамленні страчаны
@@ -239,10 +254,10 @@ Subject: Кропка мантавання не пустая
Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Каталог @WHERE@ указаны як кропка мантавання (другое поле ў /etc/fstab
-ці Where= поле ў файле юніта systemd) і не пусты. Гэта не перашкаджае
-мантаванню, але існуючыя ў ім файлы будуць недаступны. Для доступу да
-іх, калі ласка, змантуйце гэтую файлавую сістэму ў іншае месца.
+Каталог @WHERE@ указаны як кропка мантавання (другое поле ў /etc/fstab ці
+Where= поле ў файле юніта systemd) і не пусты. Гэта не перашкаджае
+мантаванню, але існуючыя ў ім файлы будуць недаступны. Для доступу да іх,
+калі ласка, змантуйце гэтую файлавую сістэму ў іншае месца.
-- 24d8d4452573402496068381a6312df2
Subject: Віртуальная машына або кантэйнер запусціўся
@@ -258,3 +273,41 @@ Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Віртуальная машына @NAME@ з лідарам № @LEADER@ спынена.
+
+-- 36db2dfa5a9045e1bd4af5f93e1cf057
+Subject: Механізм DNSSEC адключаны, бо сервер не падтымлівае яго
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8) resolved.conf(5)
+
+Сэрвіс вызначэння імён (systemd-resolved.service) вызначыў, што DNS-сервер
+не падтрымлівае механізм DNSSEC. У выніку праверка DNSSEC была адключана.
+
+Гэтая падзея ўзнікае калі наладжаны DNSSEC=allow-downgrade
+у файле resolved.conf і DNS-сервер не падтрымлівае механізм DNSSEC.
+Звярніце ўвагу, што рэжым allow-downgrade дазваляе правесці атаку
+«DNSSEC downgrade», у ходзе якой зламыснік можа адключыць праверку DNSSEC
+шляхам падстаноўкі падробленых DNSSEC-адказаў у камунікацыйны канал.
+
+Гэта падзея можа быць прыкметай таго, што DNS-сервер сапраўды несумяшчальны
+з DNSSEC або што зламысніку паспяхова атрымалася правесці атаку па
+адключэнню DNSSEC.
+
+-- 1675d7f172174098b1108bf8c7dc8f5d
+Subject: Збой пры праверцы DNSSEC
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+DNS-запыт або рэсурсны запіс не прайшоў праверку DNSSEC.
+Як правіла, гэта паказвае на знешняе ўздзеянне на канал сувязі.
+
+-- 4d4408cfd0d144859184d1e65d7c8a65
+Subject: Давераны ключ DNSSEC быў ануляваны
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Давераны ключ DNSSEC быў ануляваны. Неабходна наладзіць новы давераны ключ
+або абнавіць аперацыйную сістэму, каб атрымаць абноўлены давераны ключ
+DNSSEC.
diff --git a/catalog/systemd.be@latin.catalog b/catalog/systemd.be@latin.catalog
index 6ab361aafb..a9dce88377 100644
--- a/catalog/systemd.be@latin.catalog
+++ b/catalog/systemd.be@latin.catalog
@@ -1,7 +1,7 @@
# This file is part of systemd.
#
# Copyright 2012 Lennart Poettering
-# Copyright 2015 Viktar Vaŭčkievič
+# Copyright 2015, 2016 Viktar Vaŭčkievič
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
@@ -19,7 +19,6 @@
# Message catalog for systemd's own messages
# Belarusian Latin translation
-# The catalog format is documented on
# Farmat kataloha apisany na staroncy
# http://www.freedesktop.org/wiki/Software/systemd/catalog
@@ -40,6 +39,23 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Praces sistemnaha žurnaliavannia spyniŭsia i zakryŭ usie fajly.
+-- ec387f577b844b8fa948f33cad9a75e6
+Subject: dyskavaje miesca, zaniataje časopisam
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@JOURNAL_NAME@ (@JOURNAL_PATH@) ciapier zajmaje @CURRENT_USE_PRETTY@.
+Maksimaĺna dazvolieny pamier skladaje @MAX_USE_PRETTY@.
+Pakidajem voĺnymi nie mieńš za @DISK_KEEP_FREE_PRETTY@ (dastupna na dysku
+@DISK_AVAILABLE_PRETTY@).
+Takim čynam, limit skladaje @LIMIT_PRETTY@, z jakich @AVAILABLE_PRETTY@
+dastupna.
+
+Limity na pamier naladžvaiecca z dapamohaj SystemMaxUse=, SystemKeepFree=,
+SystemMaxFileSize=, RuntimeMaxUse=, RuntimeKeepFree=, RuntimeMaxFileSize= u
+fajlie /etc/systemd/journald.conf. Hliadzicie journald.conf(5) dlia
+detaliej.
+
-- a596d6fe7bfa4994828e72309e95d61e
Subject: Paviedamlienni z servisu adkinuty
Defined-By: systemd
@@ -52,17 +68,17 @@ Servis adpraviŭ zanadta štat paviedamlienniaŭ za karotki pramiežak času.
Majcie na ŭvazie, što byli adkinuty paviedamliennia toĺki hetaha servisu.
Paviedamlienni inšych servisaŭ zastalisia.
-Miaža, paslia jakoj paviedamlienni buduć adkinuty, naladžvajecca z
-dapamohaj RateLimitIntervalSec= i RateLimitBurst= u fajlie
-/etc/systemd/journald.conf. Hliadzicie journald.conf(5) dlia detaliej.
+Miaža, paslia jakoj paviedamlienni buduć adkinuty, naladžvajecca z dapamohaj
+RateLimitIntervalSec= i RateLimitBurst= u fajlie /etc/systemd/journald.conf.
+Hliadzicie journald.conf(5) dlia detaliej.
-- e9bf28e6e834481bb6f48f548ad13606
Subject: Paviedamlienni stračany
Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Paviedamlienni jadra byli stračany, tak jak sistema žurnaliavannia nie paspiela
-ich apracavać.
+Paviedamlienni jadra byli stračany, tak jak sistema žurnaliavannia nie
+paspiela ich apracavać.
-- fc2e22bc6ee647b6b90729ab34a250b1
Subject: Praces @COREDUMP_PID@ (@COREDUMP_COMM@) skinuŭ damp pamiaci
@@ -99,7 +115,8 @@ Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
-Novaje pracoŭnaje miesca № @SEAT_ID@ naladžana i dastupna dlia vykarystannia.
+Novaje pracoŭnaje miesca № @SEAT_ID@ naladžana i dastupna dlia
+vykarystannia.
-- e7852bfe46784ed0accde04bc864c2d5
Subject: Pracoŭnaje miesca № @SEAT_ID@ vydaliena
@@ -114,7 +131,8 @@ Subject: Čas zmienieny
Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Sistemny hadzinnik zmienieny na @REALTIME@ mikrasiekund ad 1 studzienia 1970.
+Sistemny hadzinnik zmienieny na @REALTIME@ mikrasiekund ad 1 studzienia
+1970.
-- 45f82f4aef7a4bbf942ce861d1f20990
Subject: Časavy pojas zmienieny na @TIMEZONE@
@@ -258,3 +276,43 @@ Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Virtuaĺnaja mašyna @NAME@ z lidaram № @LEADER@ spyniena.
+
+-- 36db2dfa5a9045e1bd4af5f93e1cf057
+Subject: Miechanizm DNSSEC adkliučany, bo siervier nie padtrymlivaje jaho
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8) resolved.conf(5)
+
+Servis vyznačennia imion (systemd-resolved.service) vyznačyŭ, što
+DNS-siervier nie padtrymlivaje miechanizm DNSSEC. U vyniku pravierka DNSSEC
+byla adkliučana.
+
+Hetaja padzieja ŭznikaje kali naladžany DNSSEC=allow-downgrade
+u fajlie resolved.conf i DNS-siervier nie padtrymlivaje miechanizm DNSSEC.
+Zviarnicie ŭvahu, što režym allow-downgrade dazvaliaje praviesci ataku
+«DNSSEC downgrade», u chodzie jakoj zlamysnik moža adkliučyć pravierku
+DNSSEC šliacham padstanoŭki padroblienych DNSSEC-adkazaŭ u kamunikacyjny
+kanal.
+
+Heta padzieja moža być prykmietaj taho, što DNS-siervier sapraŭdy
+niesumiaščaĺny z DNSSEC abo što zlamysniku paspiachova atrymalasia praviesci
+ataku pa adkliučenniu DNSSEC.
+
+-- 1675d7f172174098b1108bf8c7dc8f5d
+Subject: Zboj pry praviercy DNSSEC
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+DNS-zapyt abo resursny zapis nie prajšoŭ pravierku DNSSEC.
+Jak pravila, heta pakazvaje na zniešniaje ŭzdziejannie na kanal suviazi.
+
+-- 4d4408cfd0d144859184d1e65d7c8a65
+Subject: Davierany kliuč DNSSEC byŭ anuliavany
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Davierany kliuč DNSSEC byŭ anuliavany. Nieabchodna naladzić novy davierany
+kliuč abo abnavić apieracyjnuju sistemu, kab atrymać abnoŭlieny davierany
+kliuč DNSSEC.
diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb
index a5b39dc41e..29aac807d1 100644
--- a/hwdb/70-mouse.hwdb
+++ b/hwdb/70-mouse.hwdb
@@ -316,8 +316,6 @@ mouse:usb:v046dpc046:name:Logitech USB Optical Mouse:
mouse:usb:v046dpc05a:name:Logitech USB Optical Mouse:
# Logitech USB Laser Mouse M-U0011-O rebranded as "terra Laser"
mouse:usb:v046dpc065:name:Logitech USB Laser Mouse:
-# Logitech USB Laser Mouse M-U0007 [M500]
-mouse:usb:v046dpc069:name:Logitech USB Laser Mouse:
# Logitech V500 Cordless Notebook Mouse
mouse:usb:v046dpc510:name:Logitech USB Receiver:
# Logitech M560 Wireless Mouse
@@ -343,6 +341,10 @@ mouse:usb:v046dpc06b:name:Logitech G700 Laser Mouse:
mouse:usb:v046dpc531:name:Logitech USB Receiver:
MOUSE_DPI=*1000@500 3800@500 500@1000 1500@1000 2000@1000
+# Logitech USB Laser Mouse M-U0007 [M500]
+mouse:usb:v046dpc069:name:Logitech USB Laser Mouse:
+ MOUSE_DPI=1100@125
+
# Logitech Wireless Mouse M310
mouse:usb:v046dp1024:name:Logitech M310:
MOUSE_DPI=1100@168
diff --git a/man/machinectl.xml b/man/machinectl.xml
index 4b7f9a0391..d3891332e4 100644
--- a/man/machinectl.xml
+++ b/man/machinectl.xml
@@ -373,8 +373,7 @@
<para>To interactively start a container on the command line
with full access to the container's console, please invoke
<command>systemd-nspawn</command> directly. To stop a running
- container use <command>machinectl poweroff</command>, see
- below.</para></listitem>
+ container use <command>machinectl poweroff</command>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -461,8 +460,8 @@
<listitem><para>Power off one or more containers. This will
trigger a reboot by sending SIGRTMIN+4 to the container's init
process, which causes systemd-compatible init systems to shut
- down cleanly. This operation does not work on containers that
- do not run a
+ down cleanly. Use <command>stop</command> as alias for <command>poweroff</command>.
+ This operation does not work on containers that do not run a
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>-compatible
init system, such as sysvinit. Use
<command>terminate</command> (see below) to immediately
diff --git a/man/os-release.xml b/man/os-release.xml
index 4557abc4a3..99bbb61004 100644
--- a/man/os-release.xml
+++ b/man/os-release.xml
@@ -176,6 +176,22 @@
</varlistentry>
<varlistentry>
+ <term><varname>VERSION_CODENAME=</varname></term>
+
+ <listitem><para>
+ A lower-case string (no spaces or other characters outside of
+ 0–9, a–z, ".", "_" and "-") identifying the operating system
+ release code name, excluding any OS name information or
+ release version, and suitable for processing by scripts or
+ usage in generated filenames. This field is optional and may
+ not be implemented on all systems.
+ Examples:
+ <literal>VERSION_CODENAME=buster</literal>,
+ <literal>VERSION_CODENAME=xenial</literal>
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>VERSION_ID=</varname></term>
<listitem><para>A lower-case string (mostly numeric, no spaces
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index 0c8c699201..08122795f4 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -980,6 +980,19 @@
effect.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>--notify-ready=</varname></term>
+
+ <listitem><para>Configures support for notifications from the container's init process.
+ <varname>--notify-ready=</varname> takes a boolean (<option>no</option> and <option>yes</option>).
+ With option <option>no</option> systemd-nspawn notifies systemd
+ with a <literal>READY=1</literal> message when the init process is created.
+ With option <option>yes</option> systemd-nspawn waits for the
+ <literal>READY=1</literal> message from the init process in the container
+ before sending its own to systemd. For more details about notifications
+ see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml
index 4b66f836a2..b917ac20a2 100644
--- a/man/systemd-resolve.xml
+++ b/man/systemd-resolve.xml
@@ -288,6 +288,12 @@
<listitem><para>Resets the statistics counters shown in <option>--statistics</option> to zero.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--flush-caches</option></term>
+
+ <listitem><para>Flushes all DNS resource record caches the service maintains locally.</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml
index 829729ca09..485f3e9aee 100644
--- a/man/systemd-resolved.service.xml
+++ b/man/systemd-resolved.service.xml
@@ -146,6 +146,28 @@
</refsect1>
<refsect1>
+ <title>Signals</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>SIGUSR1</constant></term>
+
+ <listitem><para>Upon reception of the SIGUSR1 process signal <command>systemd-resolved</command> will dump the
+ contents of all DNS resource record caches it maintains into the system logs.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SIGUSR2</constant></term>
+
+ <listitem><para>Upon reception of the SIGUSR2 process signal <command>systemd-resolved</command> will flush all
+ caches it maintains. Note that it should normally not be necessary to request this explicitly – except for
+ debugging purposes – as <command>systemd-resolved</command> flushes the caches automatically anyway any time
+ the host's network configuration changes.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 4a3dd14c39..1c3256a662 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -146,7 +146,7 @@
<listitem><para>Sets the Unix user or group that the processes
are executed as, respectively. Takes a single user or group
name or ID as argument. If no group is set, the default group
- of the user is chosen.</para></listitem>
+ of the user is chosen. These do not affect commands prefixed with <literal>!</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -161,7 +161,7 @@
this one will have no effect. In any way, this option does not
override, but extends the list of supplementary groups
configured in the system group database for the
- user.</para></listitem>
+ user. This does not affect commands prefixed with <literal>!</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -795,7 +795,8 @@
process are enforced. This option may appear more than once, in which case the bounding sets are merged. If the
empty string is assigned to this option, the bounding set is reset to the empty capability set, and all prior
settings have no effect. If set to <literal>~</literal> (without any further argument), the bounding set is
- reset to the full set of available capabilities, also undoing any previous settings.</para></listitem>
+ reset to the full set of available capabilities, also undoing any previous settings. This does not affect
+ commands prefixed with <literal>!</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -824,7 +825,8 @@
as a non-privileged user but still want to give it some capabilities.
Note that in this case option <constant>keep-caps</constant> is
automatically added to <varname>SecureBits=</varname> to retain the
- capabilities over the user change.</para></listitem>
+ capabilities over the user change. <varname>AmbientCapabilities=</varname> does not affect
+ commands prefixed with <literal>!</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -840,8 +842,8 @@
<option>noroot-locked</option>.
This option may appear more than once, in which case the secure
bits are ORed. If the empty string is assigned to this option,
- the bits are reset to 0. See
- <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ the bits are reset to 0. This does not affect commands prefixed with <literal>!</literal>.
+ See <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
@@ -1097,8 +1099,8 @@
domain transition. However, the policy still needs to
authorize the transition. This directive is ignored if SELinux
is disabled. If prefixed by <literal>-</literal>, all errors
- will be ignored. See
- <citerefentry project='die-net'><refentrytitle>setexeccon</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ will be ignored. This does not affect commands prefixed with <literal>!</literal>.
+ See <citerefentry project='die-net'><refentrytitle>setexeccon</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
@@ -1110,7 +1112,7 @@
Profiles must already be loaded in the kernel, or the unit
will fail. This result in a non operation if AppArmor is not
enabled. If prefixed by <literal>-</literal>, all errors will
- be ignored. </para></listitem>
+ be ignored. This does not affect commands prefixed with <literal>!</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1129,7 +1131,8 @@
<para>The value may be prefixed by <literal>-</literal>, in
which case all errors will be ignored. An empty value may be
- specified to unset previous assignments.</para>
+ specified to unset previous assignments. This does not affect
+ commands prefixed with <literal>!</literal>.</para>
</listitem>
</varlistentry>
@@ -1180,7 +1183,7 @@
listed explicitly. This option may be specified more than once,
in which case the filter masks are merged. If the empty string
is assigned, the filter is reset, all prior assignments will
- have no effect.</para>
+ have no effect. This does not affect commands prefixed with <literal>!</literal>.</para>
<para>If you specify both types of this option (i.e.
whitelisting and blacklisting), the first encountered will
@@ -1343,7 +1346,7 @@
family should be included in the configured whitelist as it is
frequently used for local communication, including for
<citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- logging.</para></listitem>
+ logging. This does not affect commands prefixed with <literal>!</literal>.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 821e22aff8..ea98c821fa 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -240,7 +240,7 @@
By enabling DHCPv6 support explicitly, the DHCPv6 client will
be started regardless of the presence of routers on the link,
or what flags the routers pass. See
- <literal>IPv6AcceptRouterAdvertisements=</literal>.</para>
+ <literal>IPv6AcceptRA=</literal>.</para>
<para>Furthermore, note that by default the domain name
specified through DHCP is not used for name resolution.
@@ -527,24 +527,20 @@
<literal>no</literal>.</para></listitem>
</varlistentry>
<varlistentry>
- <term><varname>IPv6AcceptRouterAdvertisements=</varname></term>
- <listitem><para>Force the setting of the <filename>accept_ra</filename>
- (router advertisements) setting for the interface.
- When unset, the kernel default is used, and router
- advertisements are accepted only when local forwarding
- is disabled for that interface.
- When router advertisements are accepted, they will
- trigger the start of the DHCPv6 client if the relevant
- flags are passed, or if no routers are found on the link.
- Takes a boolean. If true, router advertisements are
- accepted, when false, router advertisements are ignored,
- independently of the local forwarding state.</para>
-
- <para>See
- <ulink url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink>
- in the kernel documentation, but note that systemd's
- setting of <constant>1</constant> corresponds to
- kernel's setting of <constant>2</constant>.</para>
+ <term><varname>IPv6AcceptRA=</varname></term>
+ <listitem><para>Enable or disable IPv6 Router Advertisement (RA) reception support for the interface. Takes
+ a boolean parameter. If true, RAs are accepted; if false, RAs are ignored, independently of the local
+ forwarding state. When not set, the kernel default is used, and RAs are accepted only when local forwarding
+ is disabled for that interface. When RAs are accepted, they may trigger the start of the DHCPv6 client if
+ the relevant flags are set in the RA data, or if no routers are found on the link.</para>
+
+ <para>Further settings for the IPv6 RA support may be configured in the
+ <literal>[IPv6AcceptRA]</literal> section, see below.</para>
+
+ <para>Also see <ulink
+ url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink> in the kernel
+ documentation regarding <literal>accept_ra</literal>, but note that systemd's setting of
+ <constant>1</constant> (i.e. true) corresponds to kernel's setting of <constant>2</constant>.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -799,7 +795,7 @@
false.</para>
<para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
- of all host names, in particular to single-label names. It is generally safer to use the supplied domain
+ of all host names, in particular of single-label names. It is generally safer to use the supplied domain
only as routing domain, rather than as search domain, in order to not have it affect local resolution of
single-label names.</para>
@@ -899,6 +895,47 @@
</refsect1>
<refsect1>
+ <title>[IPv6AcceptRA] Section Options</title>
+ <para>The <literal>[IPv6AcceptRA]</literal> section configures the IPv6 Router Advertisement
+ (RA) client, if it is enabled with the <varname>IPv6AcceptRA=</varname> setting described
+ above:</para>
+
+ <variablelist class='network-directives'>
+ <varlistentry>
+ <term><varname>UseDNS=</varname></term>
+ <listitem>
+ <para>When true (the default), the DNS servers received in the Router Advertisement will be used and take
+ precedence over any statically configured ones.</para>
+
+ <para>This corresponds to the <option>nameserver</option> option in <citerefentry
+ project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>UseDomains=</varname></term>
+ <listitem>
+ <para>Takes a boolean argument, or the special value <literal>route</literal>. When true, the domain name
+ received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link, similar to
+ the effect of the <option>Domains=</option> setting. If set to <literal>route</literal>, the domain name
+ received via IPv6 RA will be used for routing DNS queries only, but not for searching, similar to the
+ effect of the <option>Domains=</option> setting when the argument is prefixed with
+ <literal>~</literal>. Defaults to false.</para>
+
+ <para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
+ of all host names, in particular of single-label names. It is generally safer to use the supplied domain
+ only as routing domain, rather than as search domain, in order to not have it affect local resolution of
+ single-label names.</para>
+
+ <para>When set to true, this setting corresponds to the <option>domain</option> option in <citerefentry
+ project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+
+ <refsect1>
<title>[DHCPServer] Section Options</title>
<para>The <literal>[DHCPServer]</literal> section contains
settings for the DHCP server, if enabled via the
@@ -1093,6 +1130,39 @@
</varlistentry>
</variablelist>
</refsect1>
+ <refsect1>
+ <title>[BridgeVLAN] Section Options</title>
+ <para>The <literal>[BridgeVLAN]</literal> section manages the VLAN ID configuration of a bridge port and accepts
+ the following keys. Specify several <literal>[BridgeVLAN]</literal> sections to configure several VLAN entries.
+ The <varname>VLANFiltering=</varname> option has to be enabled, see <literal>[Bridge]</literal> section in
+ <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+ <variablelist class='network-directives'>
+ <varlistentry>
+ <term><varname>VLAN=</varname></term>
+ <listitem>
+ <para>The VLAN ID allowed on the port. This can be either a single ID or a range M-N. VLAN IDs are valid
+ from 1 to 4094.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>EgressUntagged=</varname></term>
+ <listitem>
+ <para>The VLAN ID specified here will be used to untag frames on egress. Configuring
+ <varname>EgressUntagged=</varname> implicates the use of <varname>VLAN=</varname> above and will enable the
+ VLAN ID for ingress as well. This can be either a single ID or a range M-N.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>PVID=</varname></term>
+ <listitem>
+ <para>The Port VLAN ID specified here is assigned to all untagged frames at ingress.
+ <varname>PVID=</varname> can be used only once. Configuring <varname>PVID=</varname> implicates the use of
+ <varname>VLAN=</varname> above and will enable the VLAN ID for ingress as well.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
<refsect1>
<title>Example</title>
@@ -1139,6 +1209,26 @@ Name=enp2s0
Bridge=bridge0</programlisting>
</example>
<example>
+ <title>/etc/systemd/network/25-bridge-slave-interface-vlan.network</title>
+
+ <programlisting>[Match]
+Name=enp2s0
+
+[Network]
+Bridge=bridge0
+
+[BridgeVLAN]
+VLAN=1-32
+PVID=42
+EgressUntagged=42
+
+[BridgeVLAN]
+VLAN=100-200
+
+[BridgeVLAN]
+EgressUntagged=300-400</programlisting>
+ </example>
+ <example>
<title>/etc/systemd/network/25-ipip.network</title>
<programlisting>[Match]
diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml
index 3683412c14..6df4aeb2a9 100644
--- a/man/systemd.nspawn.xml
+++ b/man/systemd.nspawn.xml
@@ -259,6 +259,15 @@
<option>--private-users=</option> command line switch, and takes the same options. This option is privileged
(see above). </para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>NotifyReady=</varname></term>
+
+ <listitem><para>Configures support for notifications from the container's init process.
+ This is equivalent to use <option>--notify-ready=</option> command line switch,
+ and takes the same options. See <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for details about the specific options supported.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 6641dfed4f..6e969abc25 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -295,9 +295,10 @@
If the absolute filename is prefixed with
<literal>-</literal>, an exit code of the command normally
considered a failure (i.e. non-zero exit status or abnormal
- exit due to signal) is ignored and considered success. If both
- <literal>-</literal> and <literal>@</literal> are used, they
- can appear in either order.</para>
+ exit due to signal) is ignored and considered success.
+ If the absolute path is prefixed with <literal>!</literal> then
+ it is executed with full privileges. <literal>-</literal>, <literal>@</literal>, and <literal>!</literal>
+ may be used together and they can appear in any order.</para>
<para>If more than one command is specified, the commands are
invoked sequentially in the order they appear in the unit
diff --git a/po/be.po b/po/be.po
index d682f32025..2f60eb2eba 100644
--- a/po/be.po
+++ b/po/be.po
@@ -3,13 +3,13 @@
# This file is distributed under the same license as the systemd package.
#
#
-# Viktar Vaŭčkievič <victorenator@gmail.com>, 2015.
+# Viktar Vaŭčkievič <victorenator@gmail.com>, 2015, 2016.
msgid ""
msgstr ""
"Project-Id-Version: systemd master\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-09-12 13:42+0300\n"
-"PO-Revision-Date: 2015-09-12 16:25+0300\n"
+"POT-Creation-Date: 2016-06-09 19:54+0300\n"
+"PO-Revision-Date: 2016-06-09 19:47+0300\n"
"Last-Translator: Viktar Vaŭčkievič <victorenator@gmail.com>\n"
"Language-Team: \n"
"Language: be\n"
@@ -244,46 +244,57 @@ msgstr ""
"апрацоўваць закрыццё крышкі ноўтбука."
#: ../src/login/org.freedesktop.login1.policy.in.h:19
+msgid "Allow non-logged-in user to run programs"
+msgstr ""
+"Дазволіць карыстальніку, якія яшчэ не ўвайшоў у сістэму, выконваць праграмы"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Explicit request is required to run programs as a non-logged-in user."
+msgstr ""
+"Неабходны відавочны запыт для выканання праграм карыстальніка, які яшчэ не "
+"ўвайшоў у сістэму."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
msgid "Allow non-logged-in users to run programs"
msgstr ""
"Дазволіць карыстальнікам, якія яшчэ не ўвайшлі ў сістэму, выконваць праграмы"
-#: ../src/login/org.freedesktop.login1.policy.in.h:20
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
msgid "Authentication is required to run programs as a non-logged-in user."
msgstr ""
"Неабходна аўтэнтыфікацыя для выканання праграм карыстальніка, які яшчэ не "
"ўвайшоў у сістэму."
-#: ../src/login/org.freedesktop.login1.policy.in.h:21
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
msgid "Allow attaching devices to seats"
msgstr "Дазволіць далучаць прылады да працоўных месцаў"
-#: ../src/login/org.freedesktop.login1.policy.in.h:22
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
msgid "Authentication is required for attaching a device to a seat."
msgstr "Неабходна аўтэнтыфікацыя для далучэння прылад да працоўных месцаў."
-#: ../src/login/org.freedesktop.login1.policy.in.h:23
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
msgid "Flush device to seat attachments"
msgstr "Адключаць прылады ад працоўных месцаў"
-#: ../src/login/org.freedesktop.login1.policy.in.h:24
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
msgid ""
"Authentication is required for resetting how devices are attached to seats."
msgstr "Неабходна аўтэнтыфікацыя для адключэння прылад ад працоўных месцаў."
-#: ../src/login/org.freedesktop.login1.policy.in.h:25
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
msgid "Power off the system"
msgstr "Выключыць сістэму"
-#: ../src/login/org.freedesktop.login1.policy.in.h:26
+#: ../src/login/org.freedesktop.login1.policy.in.h:28
msgid "Authentication is required for powering off the system."
msgstr "Неабходна аўтэнтыфікацыя для выключэння сістэмы."
-#: ../src/login/org.freedesktop.login1.policy.in.h:27
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
msgid "Power off the system while other users are logged in"
msgstr "Выключыць сістэму пры прысутнасці іншых карыстальнікаў"
-#: ../src/login/org.freedesktop.login1.policy.in.h:28
+#: ../src/login/org.freedesktop.login1.policy.in.h:30
msgid ""
"Authentication is required for powering off the system while other users are "
"logged in."
@@ -291,11 +302,11 @@ msgstr ""
"Неабходна аўтэнтыфікацыя для выключэння сістэмы пры прысутнасці іншых "
"карыстальнікаў."
-#: ../src/login/org.freedesktop.login1.policy.in.h:29
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
msgid "Power off the system while an application asked to inhibit it"
msgstr "Выключыць сістэму, калі праграмы перашкаджаюць гэтаму"
-#: ../src/login/org.freedesktop.login1.policy.in.h:30
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
msgid ""
"Authentication is required for powering off the system while an application "
"asked to inhibit it."
@@ -303,19 +314,19 @@ msgstr ""
"Неабходна аўтэнтыфікацыя для выключэння сістэмы, калі праграмы перашкаджаюць "
"гэтаму."
-#: ../src/login/org.freedesktop.login1.policy.in.h:31
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
msgid "Reboot the system"
msgstr "Перазагрузіць сістэму"
-#: ../src/login/org.freedesktop.login1.policy.in.h:32
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
msgid "Authentication is required for rebooting the system."
msgstr "Неабходна аўтэнтыфікацыя для перазагрузкі сістэмы."
-#: ../src/login/org.freedesktop.login1.policy.in.h:33
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
msgid "Reboot the system while other users are logged in"
msgstr "Перазагрузіць сістэму пры прысутнасці іншых карыстальнікаў"
-#: ../src/login/org.freedesktop.login1.policy.in.h:34
+#: ../src/login/org.freedesktop.login1.policy.in.h:36
msgid ""
"Authentication is required for rebooting the system while other users are "
"logged in."
@@ -323,11 +334,11 @@ msgstr ""
"Неабходна аўтэнтыфікацыя для перазагрузкі сістэмы пры прысутнасці іншых "
"карыстальнікаў."
-#: ../src/login/org.freedesktop.login1.policy.in.h:35
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
msgid "Reboot the system while an application asked to inhibit it"
msgstr "Перазагрузіць сістэму, калі праграмы перашкаджаюць гэтаму"
-#: ../src/login/org.freedesktop.login1.policy.in.h:36
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
msgid ""
"Authentication is required for rebooting the system while an application "
"asked to inhibit it."
@@ -335,19 +346,19 @@ msgstr ""
"Неабходна аўтэнтыфікацыя для перазагрузкі сістэмы, калі праграмы "
"перашкаджаюць гэтаму."
-#: ../src/login/org.freedesktop.login1.policy.in.h:37
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
msgid "Suspend the system"
msgstr "Прыпыніць сістэму"
-#: ../src/login/org.freedesktop.login1.policy.in.h:38
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
msgid "Authentication is required for suspending the system."
msgstr "Неабходна аўтэнтыфікацыя для прыпынення сістэмы."
-#: ../src/login/org.freedesktop.login1.policy.in.h:39
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
msgid "Suspend the system while other users are logged in"
msgstr "Прыпыніць сістэму пры прысутнасці іншых карыстальнікаў"
-#: ../src/login/org.freedesktop.login1.policy.in.h:40
+#: ../src/login/org.freedesktop.login1.policy.in.h:42
msgid ""
"Authentication is required for suspending the system while other users are "
"logged in."
@@ -355,11 +366,11 @@ msgstr ""
"Неабходна аўтэнтыфікацыя для прыпынення сістэмы пры прысутнасці іншых "
"карыстальнікаў."
-#: ../src/login/org.freedesktop.login1.policy.in.h:41
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
msgid "Suspend the system while an application asked to inhibit it"
msgstr "Прыпыніць сістэму, калі праграмы перашкаджаюць гэтаму"
-#: ../src/login/org.freedesktop.login1.policy.in.h:42
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
msgid ""
"Authentication is required for suspending the system while an application "
"asked to inhibit it."
@@ -367,19 +378,19 @@ msgstr ""
"Неабходна аўтэнтыфікацыя для прыпынення сістэмы, калі праграмы перашкаджаюць "
"гэтаму."
-#: ../src/login/org.freedesktop.login1.policy.in.h:43
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
msgid "Hibernate the system"
msgstr "Гібернаваць сістэму"
-#: ../src/login/org.freedesktop.login1.policy.in.h:44
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
msgid "Authentication is required for hibernating the system."
msgstr "Неабходна аўтэнтыфікацыя для гібернацыі сістэмы."
-#: ../src/login/org.freedesktop.login1.policy.in.h:45
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
msgid "Hibernate the system while other users are logged in"
msgstr "Гібернаваць сістэму пры прысутнасці іншых карыстальнікаў"
-#: ../src/login/org.freedesktop.login1.policy.in.h:46
+#: ../src/login/org.freedesktop.login1.policy.in.h:48
msgid ""
"Authentication is required for hibernating the system while other users are "
"logged in."
@@ -387,11 +398,11 @@ msgstr ""
"Неабходна аўтэнтыфікацыя для гібернацыі сістэмы пры прысутнасці іншых "
"карыстальнікаў."
-#: ../src/login/org.freedesktop.login1.policy.in.h:47
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
msgid "Hibernate the system while an application asked to inhibit it"
msgstr "Гібернаваць сістэму, калі праграмы перашкаджаюць гэтаму"
-#: ../src/login/org.freedesktop.login1.policy.in.h:48
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
msgid ""
"Authentication is required for hibernating the system while an application "
"asked to inhibit it."
@@ -399,44 +410,44 @@ msgstr ""
"Неабходна аўтэнтыфікацыя для гібернацыі сістэмы, калі праграмы перашкаджаюць "
"гэтаму."
-#: ../src/login/org.freedesktop.login1.policy.in.h:49
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
msgid "Manage active sessions, users and seats"
msgstr "Кіраваць актыўнымі сесіямі, карыстальнікамі і працоўнымі месцамі"
-#: ../src/login/org.freedesktop.login1.policy.in.h:50
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
msgid ""
"Authentication is required for managing active sessions, users and seats."
msgstr ""
"Неабходна аўтэнтыфікацыя для кіравання актыўнымі сесіямі, карыстальнікамі і "
"месцамі."
-#: ../src/login/org.freedesktop.login1.policy.in.h:51
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
msgid "Lock or unlock active sessions"
msgstr "Блакаваць або разблакаваць актыўную сесію"
-#: ../src/login/org.freedesktop.login1.policy.in.h:52
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
msgid "Authentication is required to lock or unlock active sessions."
msgstr ""
"Неабходна аўтэнтыфікацыя для блакіроўкі або разблакіроўкі актыўнай сесіі."
-#: ../src/login/org.freedesktop.login1.policy.in.h:53
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
msgid "Allow indication to the firmware to boot to setup interface"
msgstr "Дазволіць указанне прашыўцы на загрузку інтэрфейсу налад"
-#: ../src/login/org.freedesktop.login1.policy.in.h:54
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
msgid ""
"Authentication is required to indicate to the firmware to boot to setup "
"interface."
msgstr ""
"Неабходна аўтэнтыфікацыя для ўказання прашыўцы на загрузку інтэрфейсу налад."
-#: ../src/login/org.freedesktop.login1.policy.in.h:55
+#: ../src/login/org.freedesktop.login1.policy.in.h:57
msgid "Set a wall message"
msgstr "Усталяваць усеагульнае паведамленне"
-#: ../src/login/org.freedesktop.login1.policy.in.h:56
+#: ../src/login/org.freedesktop.login1.policy.in.h:58
msgid "Authentication is required to set a wall message"
-msgstr "Неабходна аўтэнтыфікацыя для ўсталявання усеагульнага паведамлення."
+msgstr "Неабходна аўтэнтыфікацыя для ўсталявання ўсеагульнага паведамлення"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
@@ -552,30 +563,30 @@ msgstr ""
"Неабходна аўтэнтыфікацыя для ўключэння або выключэння сінхранізацыі часу па "
"сетцы."
-#: ../src/core/dbus-unit.c:428
+#: ../src/core/dbus-unit.c:450
msgid "Authentication is required to start '$(unit)'."
msgstr "Неабходна аўтэнтыфікацыя для запуску '$(unit)'."
-#: ../src/core/dbus-unit.c:429
+#: ../src/core/dbus-unit.c:451
msgid "Authentication is required to stop '$(unit)'."
-msgstr "Неабходна аўтэнтыфікацыя для ."
+msgstr "Неабходна аўтэнтыфікацыя для спынення '$(unit)'."
-#: ../src/core/dbus-unit.c:430
+#: ../src/core/dbus-unit.c:452
msgid "Authentication is required to reload '$(unit)'."
msgstr "Неабходна аўтэнтыфікацыя для перачытання стану '$(unit)'."
-#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+#: ../src/core/dbus-unit.c:453 ../src/core/dbus-unit.c:454
msgid "Authentication is required to restart '$(unit)'."
msgstr "Неабходна аўтэнтыфікацыя для перазапуску '$(unit)'."
-#: ../src/core/dbus-unit.c:535
+#: ../src/core/dbus-unit.c:560
msgid "Authentication is required to kill '$(unit)'."
msgstr "Неабходна аўтэнтыфікацыя для забойства '$(unit)'."
-#: ../src/core/dbus-unit.c:565
+#: ../src/core/dbus-unit.c:590
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
msgstr "Неабходна аўтэнтыфікацыя для анулявання памылковага стану '$(unit)'."
-#: ../src/core/dbus-unit.c:597
+#: ../src/core/dbus-unit.c:622
msgid "Authentication is required to set properties on '$(unit)'."
msgstr "Неабходна аўтэнтыфікацыя для ўсталявання ўласцівасцей '$(unit)'."
diff --git a/po/be@latin.po b/po/be@latin.po
index 15488b2c81..121696a316 100644
--- a/po/be@latin.po
+++ b/po/be@latin.po
@@ -3,13 +3,13 @@
# This file is distributed under the same license as the systemd package.
#
#
-# Viktar Vaŭčkievič <victorenator@gmail.com>, 2015.
+# Viktar Vaŭčkievič <victorenator@gmail.com>, 2015, 2016.
msgid ""
msgstr ""
"Project-Id-Version: systemd master\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-09-12 13:42+0300\n"
-"PO-Revision-Date: 2015-09-12 16:25+0300\n"
+"POT-Creation-Date: 2016-06-09 19:54+0300\n"
+"PO-Revision-Date: 2016-06-09 19:50+0300\n"
"Last-Translator: Viktar Vaŭčkievič <victorenator@gmail.com>\n"
"Language-Team: \n"
"Language: be@latin\n"
@@ -246,48 +246,59 @@ msgstr ""
"apracoŭvać zakryccio kryški noŭtbuka."
#: ../src/login/org.freedesktop.login1.policy.in.h:19
+msgid "Allow non-logged-in user to run programs"
+msgstr ""
+"Dazvolić karystaĺniku, jakija jašče nie ŭvajšoŭ u sistemu, vykonvać prahramy"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Explicit request is required to run programs as a non-logged-in user."
+msgstr ""
+"Nieabchodny vidavočny zapyt dlia vykanannia prahram karystaĺnika, jaki jašče "
+"nie ŭvajšoŭ u sistemu."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
msgid "Allow non-logged-in users to run programs"
msgstr ""
"Dazvolić karystaĺnikam, jakija jašče nie ŭvajšli ŭ sistemu, vykonvać prahramy"
-#: ../src/login/org.freedesktop.login1.policy.in.h:20
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
msgid "Authentication is required to run programs as a non-logged-in user."
msgstr ""
"Nieabchodna aŭtentyfikacyja dlia vykanannia prahram karystaĺnika, jaki jašče "
"nie ŭvajšoŭ u sistemu."
-#: ../src/login/org.freedesktop.login1.policy.in.h:21
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
msgid "Allow attaching devices to seats"
msgstr "Dazvolić dalučać prylady da pracoŭnych miescaŭ"
-#: ../src/login/org.freedesktop.login1.policy.in.h:22
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
msgid "Authentication is required for attaching a device to a seat."
msgstr ""
"Nieabchodna aŭtentyfikacyja dlia dalučennia prylad da pracoŭnych miescaŭ."
-#: ../src/login/org.freedesktop.login1.policy.in.h:23
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
msgid "Flush device to seat attachments"
msgstr "Adkliučać prylady ad pracoŭnych miescaŭ"
-#: ../src/login/org.freedesktop.login1.policy.in.h:24
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
msgid ""
"Authentication is required for resetting how devices are attached to seats."
msgstr ""
"Nieabchodna aŭtentyfikacyja dlia adkliučennia prylad ad pracoŭnych miescaŭ."
-#: ../src/login/org.freedesktop.login1.policy.in.h:25
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
msgid "Power off the system"
msgstr "Vykliučyć sistemu"
-#: ../src/login/org.freedesktop.login1.policy.in.h:26
+#: ../src/login/org.freedesktop.login1.policy.in.h:28
msgid "Authentication is required for powering off the system."
msgstr "Nieabchodna aŭtentyfikacyja dlia vykliučennia sistemy."
-#: ../src/login/org.freedesktop.login1.policy.in.h:27
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
msgid "Power off the system while other users are logged in"
msgstr "Vykliučyć sistemu pry prysutnasci inšych karystaĺnikaŭ"
-#: ../src/login/org.freedesktop.login1.policy.in.h:28
+#: ../src/login/org.freedesktop.login1.policy.in.h:30
msgid ""
"Authentication is required for powering off the system while other users are "
"logged in."
@@ -295,11 +306,11 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia vykliučennia sistemy pry prysutnasci inšych "
"karystaĺnikaŭ."
-#: ../src/login/org.freedesktop.login1.policy.in.h:29
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
msgid "Power off the system while an application asked to inhibit it"
msgstr "Vykliučyć sistemu, kali prahramy pieraškadžajuć hetamu"
-#: ../src/login/org.freedesktop.login1.policy.in.h:30
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
msgid ""
"Authentication is required for powering off the system while an application "
"asked to inhibit it."
@@ -307,19 +318,19 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia vykliučennia sistemy, kali prahramy "
"pieraškadžajuć hetamu."
-#: ../src/login/org.freedesktop.login1.policy.in.h:31
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
msgid "Reboot the system"
msgstr "Pierazahruzić sistemu"
-#: ../src/login/org.freedesktop.login1.policy.in.h:32
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
msgid "Authentication is required for rebooting the system."
msgstr "Nieabchodna aŭtentyfikacyja dlia pierazahruzki sistemy."
-#: ../src/login/org.freedesktop.login1.policy.in.h:33
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
msgid "Reboot the system while other users are logged in"
msgstr "Pierazahruzić sistemu pry prysutnasci inšych karystaĺnikaŭ"
-#: ../src/login/org.freedesktop.login1.policy.in.h:34
+#: ../src/login/org.freedesktop.login1.policy.in.h:36
msgid ""
"Authentication is required for rebooting the system while other users are "
"logged in."
@@ -327,11 +338,11 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia pierazahruzki sistemy pry prysutnasci "
"inšych karystaĺnikaŭ."
-#: ../src/login/org.freedesktop.login1.policy.in.h:35
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
msgid "Reboot the system while an application asked to inhibit it"
msgstr "Pierazahruzić sistemu, kali prahramy pieraškadžajuć hetamu"
-#: ../src/login/org.freedesktop.login1.policy.in.h:36
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
msgid ""
"Authentication is required for rebooting the system while an application "
"asked to inhibit it."
@@ -339,19 +350,19 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia pierazahruzki sistemy, kali prahramy "
"pieraškadžajuć hetamu."
-#: ../src/login/org.freedesktop.login1.policy.in.h:37
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
msgid "Suspend the system"
msgstr "Prypynić sistemu"
-#: ../src/login/org.freedesktop.login1.policy.in.h:38
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
msgid "Authentication is required for suspending the system."
msgstr "Nieabchodna aŭtentyfikacyja dlia prypyniennia sistemy."
-#: ../src/login/org.freedesktop.login1.policy.in.h:39
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
msgid "Suspend the system while other users are logged in"
msgstr "Prypynić sistemu pry prysutnasci inšych karystaĺnikaŭ"
-#: ../src/login/org.freedesktop.login1.policy.in.h:40
+#: ../src/login/org.freedesktop.login1.policy.in.h:42
msgid ""
"Authentication is required for suspending the system while other users are "
"logged in."
@@ -359,11 +370,11 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia prypyniennia sistemy pry prysutnasci inšych "
"karystaĺnikaŭ."
-#: ../src/login/org.freedesktop.login1.policy.in.h:41
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
msgid "Suspend the system while an application asked to inhibit it"
msgstr "Prypynić sistemu, kali prahramy pieraškadžajuć hetamu"
-#: ../src/login/org.freedesktop.login1.policy.in.h:42
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
msgid ""
"Authentication is required for suspending the system while an application "
"asked to inhibit it."
@@ -371,19 +382,19 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia prypyniennia sistemy, kali prahramy "
"pieraškadžajuć hetamu."
-#: ../src/login/org.freedesktop.login1.policy.in.h:43
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
msgid "Hibernate the system"
msgstr "Hibiernavać sistemu"
-#: ../src/login/org.freedesktop.login1.policy.in.h:44
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
msgid "Authentication is required for hibernating the system."
msgstr "Nieabchodna aŭtentyfikacyja dlia hibiernacyi sistemy."
-#: ../src/login/org.freedesktop.login1.policy.in.h:45
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
msgid "Hibernate the system while other users are logged in"
msgstr "Hibiernavać sistemu pry prysutnasci inšych karystaĺnikaŭ"
-#: ../src/login/org.freedesktop.login1.policy.in.h:46
+#: ../src/login/org.freedesktop.login1.policy.in.h:48
msgid ""
"Authentication is required for hibernating the system while other users are "
"logged in."
@@ -391,11 +402,11 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia hibiernacyi sistemy pry prysutnasci inšych "
"karystaĺnikaŭ."
-#: ../src/login/org.freedesktop.login1.policy.in.h:47
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
msgid "Hibernate the system while an application asked to inhibit it"
msgstr "Hibiernavać sistemu, kali prahramy pieraškadžajuć hetamu"
-#: ../src/login/org.freedesktop.login1.policy.in.h:48
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
msgid ""
"Authentication is required for hibernating the system while an application "
"asked to inhibit it."
@@ -403,32 +414,32 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia hibiernacyi sistemy, kali prahramy "
"pieraškadžajuć hetamu."
-#: ../src/login/org.freedesktop.login1.policy.in.h:49
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
msgid "Manage active sessions, users and seats"
msgstr "Kiravać aktyŭnymi siesijami, karystaĺnikami i pracoŭnymi miescami"
-#: ../src/login/org.freedesktop.login1.policy.in.h:50
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
msgid ""
"Authentication is required for managing active sessions, users and seats."
msgstr ""
"Nieabchodna aŭtentyfikacyja dlia kiravannia aktyŭnymi siesijami, "
"karystaĺnikami i miescami."
-#: ../src/login/org.freedesktop.login1.policy.in.h:51
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
msgid "Lock or unlock active sessions"
msgstr "Blakavać abo razblakavać aktyŭnuju siesiju"
-#: ../src/login/org.freedesktop.login1.policy.in.h:52
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
msgid "Authentication is required to lock or unlock active sessions."
msgstr ""
"Nieabchodna aŭtentyfikacyja dlia blakiroŭki abo razblakiroŭki aktyŭnaj "
"siesii."
-#: ../src/login/org.freedesktop.login1.policy.in.h:53
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
msgid "Allow indication to the firmware to boot to setup interface"
msgstr "Dazvolić ukazannie prašyŭcy na zahruzku interfiejsu nalad"
-#: ../src/login/org.freedesktop.login1.policy.in.h:54
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
msgid ""
"Authentication is required to indicate to the firmware to boot to setup "
"interface."
@@ -436,14 +447,14 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia ŭkazannia prašyŭcy na zahruzku interfiejsu "
"nalad."
-#: ../src/login/org.freedesktop.login1.policy.in.h:55
+#: ../src/login/org.freedesktop.login1.policy.in.h:57
msgid "Set a wall message"
msgstr "Ustaliavać usieahuĺnaje paviedamliennie"
-#: ../src/login/org.freedesktop.login1.policy.in.h:56
+#: ../src/login/org.freedesktop.login1.policy.in.h:58
msgid "Authentication is required to set a wall message"
msgstr ""
-"Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia usieahuĺnaha paviedamliennia."
+"Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia ŭsieahuĺnaha paviedamliennia"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
@@ -563,32 +574,32 @@ msgstr ""
"Nieabchodna aŭtentyfikacyja dlia ŭkliučennia abo vykliučennia sinchranizacyi "
"času pa sietcy."
-#: ../src/core/dbus-unit.c:428
+#: ../src/core/dbus-unit.c:450
msgid "Authentication is required to start '$(unit)'."
msgstr "Nieabchodna aŭtentyfikacyja dlia zapusku '$(unit)'."
-#: ../src/core/dbus-unit.c:429
+#: ../src/core/dbus-unit.c:451
msgid "Authentication is required to stop '$(unit)'."
-msgstr "Nieabchodna aŭtentyfikacyja dlia ."
+msgstr "Nieabchodna aŭtentyfikacyja dlia spyniennia '$(unit)'."
-#: ../src/core/dbus-unit.c:430
+#: ../src/core/dbus-unit.c:452
msgid "Authentication is required to reload '$(unit)'."
msgstr "Nieabchodna aŭtentyfikacyja dlia pieračytannia stanu '$(unit)'."
-#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+#: ../src/core/dbus-unit.c:453 ../src/core/dbus-unit.c:454
msgid "Authentication is required to restart '$(unit)'."
msgstr "Nieabchodna aŭtentyfikacyja dlia pierazapusku '$(unit)'."
-#: ../src/core/dbus-unit.c:535
+#: ../src/core/dbus-unit.c:560
msgid "Authentication is required to kill '$(unit)'."
msgstr "Nieabchodna aŭtentyfikacyja dlia zabojstva '$(unit)'."
-#: ../src/core/dbus-unit.c:565
+#: ../src/core/dbus-unit.c:590
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
msgstr ""
"Nieabchodna aŭtentyfikacyja dlia anuliavannia pamylkovaha stanu '$(unit)'."
-#: ../src/core/dbus-unit.c:597
+#: ../src/core/dbus-unit.c:622
msgid "Authentication is required to set properties on '$(unit)'."
msgstr ""
"Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia ŭlascivasciej '$(unit)'."
diff --git a/po/es.po b/po/es.po
index 681b30d5b2..6642351f68 100644
--- a/po/es.po
+++ b/po/es.po
@@ -10,15 +10,15 @@ msgstr ""
"Project-Id-Version: systemd master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-22 16:37+0100\n"
-"PO-Revision-Date: 2015-04-24 13:26+0200\n"
-"Last-Translator: Álex Puchades <alex94puchades@gmail.com>\n"
+"PO-Revision-Date: 2016-06-07 15:41-0400\n"
+"Last-Translator: Pablo Lezaeta Reyes <prflr88@gmail.com>\n"
"Language-Team: Español; Castellano <gnome-es-list@gnome.org>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Gtranslator 2.91.7\n"
+"X-Generator: Poedit 1.8.7.1\n"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
msgid "Send passphrase back to system"
@@ -72,11 +72,11 @@ msgstr "Se requiere autenticación para recargar el estado de systemd."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
msgid "Set host name"
-msgstr "Establecer nombre del equipo"
+msgstr "Establecer el nombre del equipo"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
msgid "Authentication is required to set the local host name."
-msgstr "Se requiere autenticación para establecer el nombre de equipo local."
+msgstr "Se requiere autenticación para establecer el nombre del equipo local."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
msgid "Set static host name"
@@ -135,7 +135,7 @@ msgstr "Establecer región del sistema"
#: ../src/locale/org.freedesktop.locale1.policy.in.h:2
msgid "Authentication is required to set the system locale."
-msgstr "Se requiere autenticación para establecer la región del sistema"
+msgstr "Se requiere autenticación para establecer la región del sistema."
#: ../src/locale/org.freedesktop.locale1.policy.in.h:3
msgid "Set system keyboard settings"
@@ -412,7 +412,7 @@ msgid ""
"asked to inhibit it."
msgstr ""
"Se requiere autenticación para hibernar el sistema a pesar de que una "
-"aplicación lo impide"
+"aplicación lo impide."
#: ../src/login/org.freedesktop.login1.policy.in.h:49
msgid "Manage active sessions, users and seats"
@@ -448,12 +448,11 @@ msgstr ""
#: ../src/login/org.freedesktop.login1.policy.in.h:55
msgid "Set a wall message"
-msgstr ""
+msgstr "Establecer muro de texto"
#: ../src/login/org.freedesktop.login1.policy.in.h:56
-#, fuzzy
msgid "Authentication is required to set a wall message"
-msgstr "Se requiere autenticación para establecer el nombre de equipo local."
+msgstr "Se requiere autenticación para establecer un muro de texto"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
@@ -464,53 +463,51 @@ msgid "Authentication is required to log into a local container."
msgstr "Se requiere autenticación para conectarse a un contenedor local."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
-#, fuzzy
msgid "Log into the local host"
-msgstr "Conectarse a un contenedor local"
+msgstr "Conectarse al equipo local"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
-#, fuzzy
msgid "Authentication is required to log into the local host."
-msgstr "Se requiere autenticación para conectarse a un contenedor local."
+msgstr "Se requiere autenticación para conectarse al equipo local."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
-#, fuzzy
msgid "Acquire a shell in a local container"
-msgstr "Conectarse a un contenedor local"
+msgstr "Se adquiere un intérprete de órdenes en un contenedor local"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
-#, fuzzy
msgid "Authentication is required to acquire a shell in a local container."
-msgstr "Se requiere autenticación para conectarse a un contenedor local."
+msgstr ""
+"Se requiere autenticación para adquirir un intérprete de órdenes en un "
+"contenedor local."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:7
msgid "Acquire a shell on the local host"
-msgstr ""
+msgstr "Se adquiere un intérprete de órdenes en el equipo local"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:8
-#, fuzzy
msgid "Authentication is required to acquire a shell on the local host."
-msgstr "Se requiere autenticación para establecer el nombre de equipo local."
+msgstr ""
+"Se requiere autenticación para adquirir un intérprete de órdenes del equipo "
+"local."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:9
-#, fuzzy
msgid "Acquire a pseudo TTY in a local container"
-msgstr "Conectarse a un contenedor local"
+msgstr "Se adquiere un seudo-TTY en el contenedor local"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:10
-#, fuzzy
msgid ""
"Authentication is required to acquire a pseudo TTY in a local container."
-msgstr "Se requiere autenticación para conectarse a un contenedor local."
+msgstr ""
+"Se requiere autenticación para adquirir un seudo-TTY en el contenedor local."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:11
msgid "Acquire a pseudo TTY on the local host"
-msgstr ""
+msgstr "Se adquiere un seudo-TTY en el equipo local"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:12
-#, fuzzy
msgid "Authentication is required to acquire a pseudo TTY on the local host."
-msgstr "Se requiere autenticación para establecer el nombre de equipo local."
+msgstr ""
+"Se requiere autenticación para adquirir un seudo-TTY en el equipo local."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:13
msgid "Manage local virtual machines and containers"
@@ -525,7 +522,7 @@ msgstr ""
#: ../src/machine/org.freedesktop.machine1.policy.in.h:15
msgid "Manage local virtual machine and container images"
-msgstr "Administrar imágenes de máquina virtual y de contenedor locales"
+msgstr "Administrar imágenes de máquina virtual y de contenedores locales"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:16
msgid ""
@@ -533,7 +530,7 @@ msgid ""
"images."
msgstr ""
"Se requiere autenticación para administrar las imágenes de máquina virtual y "
-"de contenedor locales."
+"de contenedores locales."
#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
msgid "Set system time"
@@ -561,7 +558,7 @@ msgid ""
"UTC time."
msgstr ""
"Se requiere autenticación para establecer el reloj del sistema en formato de "
-"hora local / tiempo UTC."
+"hora local o tiempo UTC."
#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7
msgid "Turn network time synchronization on or off"
@@ -576,39 +573,33 @@ msgstr ""
"por red."
#: ../src/core/dbus-unit.c:428
-#, fuzzy
msgid "Authentication is required to start '$(unit)'."
-msgstr "Se requiere autenticación para establecer la fecha y hora del sistema."
+msgstr "Se requiere autenticación para iniciar '$(unit)'."
#: ../src/core/dbus-unit.c:429
-#, fuzzy
msgid "Authentication is required to stop '$(unit)'."
-msgstr "Se requiere autenticación para establecer la fecha y hora del sistema."
+msgstr "Se requiere autenticación para detener '$(unit)'."
#: ../src/core/dbus-unit.c:430
-#, fuzzy
msgid "Authentication is required to reload '$(unit)'."
-msgstr "Se requiere autenticación para recargar el estado de systemd."
+msgstr "Se requiere autenticación para recargar '$(unit)'."
#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
-#, fuzzy
msgid "Authentication is required to restart '$(unit)'."
-msgstr "Se requiere autenticación para establecer la fecha y hora del sistema."
+msgstr "Se requiere autenticación para reiniciar '$(unit)'."
#: ../src/core/dbus-unit.c:535
-#, fuzzy
msgid "Authentication is required to kill '$(unit)'."
-msgstr "Se requiere autenticación para conectarse a un contenedor local."
+msgstr "Se requiere autenticación para matar a '$(unit)'."
#: ../src/core/dbus-unit.c:565
-#, fuzzy
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
-msgstr "Se requiere autenticación para establecer el nombre de equipo local."
+msgstr "Se requiere autenticación para reiniciar el estado de «fallido» de '$(unit)'."
#: ../src/core/dbus-unit.c:597
-#, fuzzy
msgid "Authentication is required to set properties on '$(unit)'."
-msgstr "Se requiere autenticación para establecer la fecha y hora del sistema."
+msgstr ""
+"Se requiere autenticación para establecer las propiedades de '$(unit)'."
#~ msgid "Press Ctrl+C to cancel all filesystem checks in progress"
#~ msgstr ""
diff --git a/po/tr.po b/po/tr.po
index 076627e428..b71f30b835 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -3,20 +3,20 @@
# This file is distributed under the same license as the systemd package.
# Necdet Yücel <necdetyucel@gmail.com>, 2014.
# Gökhan Gurbetoğlu <ggurbet@gmail.com>, 2015.
-# Muhammet Kara <muhammetk@gmail.com>, 2015.
+# Muhammet Kara <muhammetk@gmail.com>, 2015, 2016.
#
msgid ""
msgstr ""
"Project-Id-Version: systemd master\n"
"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2015-09-18 00:07+0000\n"
-"PO-Revision-Date: 2015-09-19 08:31+0300\n"
+"POT-Creation-Date: 2016-04-24 12:53+0000\n"
+"PO-Revision-Date: 2016-06-09 16:05+0300\n"
"Last-Translator: Muhammet Kara <muhammetk@gmail.com>\n"
-"Language-Team: Türkçe <gnome-turk@gnome.org>\n"
+"Language-Team: Turkish <gnome-turk@gnome.org>\n"
+"Language: tr_TR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: tr_TR\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Gtranslator 2.91.7\n"
@@ -249,48 +249,60 @@ msgstr ""
"kimlik doğrulaması gereklidir."
#: ../src/login/org.freedesktop.login1.policy.in.h:19
+#| msgid "Allow non-logged-in users to run programs"
+msgid "Allow non-logged-in user to run programs"
+msgstr "Oturum açmamış kullanıcının program çalıştırmasına izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+#| msgid "Authentication is required to run programs as a non-logged-in user."
+msgid "Explicit request is required to run programs as a non-logged-in user."
+msgstr ""
+"Oturum açmamış bir kullanıcı olarak program çalıştırmak için açıkça istekte "
+"bulunulması gerekir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
msgid "Allow non-logged-in users to run programs"
msgstr "Oturum açmamış kullanıcıların program çalıştırmasına izin ver"
-#: ../src/login/org.freedesktop.login1.policy.in.h:20
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
msgid "Authentication is required to run programs as a non-logged-in user."
msgstr ""
"Oturum açmamış bir kullanıcı olarak program çalıştırmak için kimlik "
"doğrulaması gereklidir."
-#: ../src/login/org.freedesktop.login1.policy.in.h:21
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
msgid "Allow attaching devices to seats"
msgstr "Aygıtların yuvaya takılmasına izin ver"
-#: ../src/login/org.freedesktop.login1.policy.in.h:22
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
msgid "Authentication is required for attaching a device to a seat."
msgstr ""
"Bir aygıtın yuvaya takılmasına izin vermek kimlik doğrulaması gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:23
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
msgid "Flush device to seat attachments"
msgstr "Aygıtın yuvaya eklenmesini sıfırla"
-#: ../src/login/org.freedesktop.login1.policy.in.h:24
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
msgid ""
"Authentication is required for resetting how devices are attached to seats."
msgstr ""
"Aygıtların yuvalara nasıl takıldığını sıfırlamak kimlik doğrulama "
"gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:25
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
msgid "Power off the system"
msgstr "Sistemi kapat"
-#: ../src/login/org.freedesktop.login1.policy.in.h:26
+#: ../src/login/org.freedesktop.login1.policy.in.h:28
msgid "Authentication is required for powering off the system."
msgstr "Sistemi kapatmak için kimlik doğrulaması gerekiyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:27
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
msgid "Power off the system while other users are logged in"
msgstr "Diğer kullanıcılar oturum açmışken sistemi kapat"
-#: ../src/login/org.freedesktop.login1.policy.in.h:28
+#: ../src/login/org.freedesktop.login1.policy.in.h:30
msgid ""
"Authentication is required for powering off the system while other users are "
"logged in."
@@ -298,11 +310,11 @@ msgstr ""
"Diğer kullanıcılar oturum açmışken sistemi kapatmak kimlik doğrulaması "
"gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:29
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
msgid "Power off the system while an application asked to inhibit it"
msgstr "Bir uygulama engellenmesini isterken sistemi kapat"
-#: ../src/login/org.freedesktop.login1.policy.in.h:30
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
msgid ""
"Authentication is required for powering off the system while an application "
"asked to inhibit it."
@@ -310,19 +322,19 @@ msgstr ""
"Bir uygulama engellenmesini isterken sistemi kapatmak kimlik doğrulaması "
"gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:31
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
msgid "Reboot the system"
msgstr "Sistemi yeniden başlat"
-#: ../src/login/org.freedesktop.login1.policy.in.h:32
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
msgid "Authentication is required for rebooting the system."
msgstr "Sistemi yeniden başlatmak kimlik doğrulaması gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:33
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
msgid "Reboot the system while other users are logged in"
msgstr "Diğer kullanıcılar oturum açmışken sistemi yeniden başlat"
-#: ../src/login/org.freedesktop.login1.policy.in.h:34
+#: ../src/login/org.freedesktop.login1.policy.in.h:36
msgid ""
"Authentication is required for rebooting the system while other users are "
"logged in."
@@ -330,11 +342,11 @@ msgstr ""
"Diğer kullanıcılar oturum açmışken sistemi yeniden başlatmak kimlik "
"doğrulaması gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:35
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
msgid "Reboot the system while an application asked to inhibit it"
msgstr "Bir uygulama engellenmesini isterken sistemi yeniden başlat"
-#: ../src/login/org.freedesktop.login1.policy.in.h:36
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
msgid ""
"Authentication is required for rebooting the system while an application "
"asked to inhibit it."
@@ -342,19 +354,19 @@ msgstr ""
"Bir uygulama engellenmesini isterken sistemi yeniden başlatmak kimlik "
"doğrulaması gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:37
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
msgid "Suspend the system"
msgstr "Sistemi askıya al"
-#: ../src/login/org.freedesktop.login1.policy.in.h:38
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
msgid "Authentication is required for suspending the system."
msgstr "Sistemi askıya almak kimlik doğrulaması gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:39
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
msgid "Suspend the system while other users are logged in"
msgstr "Diğer kullanıcılar oturum açmışken sistemi askıya al"
-#: ../src/login/org.freedesktop.login1.policy.in.h:40
+#: ../src/login/org.freedesktop.login1.policy.in.h:42
msgid ""
"Authentication is required for suspending the system while other users are "
"logged in."
@@ -362,11 +374,11 @@ msgstr ""
"Diğer kullanıcılar oturum açmışken sistemi askıya almak kimlik doğrulaması "
"gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:41
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
msgid "Suspend the system while an application asked to inhibit it"
msgstr "Bir uygulama engellenmesini isterken sistemi askıya al"
-#: ../src/login/org.freedesktop.login1.policy.in.h:42
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
msgid ""
"Authentication is required for suspending the system while an application "
"asked to inhibit it."
@@ -374,19 +386,19 @@ msgstr ""
"Bir uygulama engellenmesini isterken sistemi askıya almak kimlik doğrulaması "
"gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:43
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
msgid "Hibernate the system"
msgstr "Sistemi hazırda beklet"
-#: ../src/login/org.freedesktop.login1.policy.in.h:44
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
msgid "Authentication is required for hibernating the system."
msgstr "Sistemi hazırda bekletmek kimlik doğrulaması gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:45
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
msgid "Hibernate the system while other users are logged in"
msgstr "Diğer kullanıcılar oturum açmışken sistemi hazırda beklet"
-#: ../src/login/org.freedesktop.login1.policy.in.h:46
+#: ../src/login/org.freedesktop.login1.policy.in.h:48
msgid ""
"Authentication is required for hibernating the system while other users are "
"logged in."
@@ -394,11 +406,11 @@ msgstr ""
"Diğer kullanıcılar oturum açmışken sistemi hazırda bekletmek kimlik "
"doğrulaması gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:47
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
msgid "Hibernate the system while an application asked to inhibit it"
msgstr "Bir uygulama engellenmesini isterken sistemi hazırda beklet"
-#: ../src/login/org.freedesktop.login1.policy.in.h:48
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
msgid ""
"Authentication is required for hibernating the system while an application "
"asked to inhibit it."
@@ -406,33 +418,33 @@ msgstr ""
"Bir uygulama engellenmesini isterken sistemi hazırda bekletmek kimlik "
"doğrulaması gerektiriyor."
-#: ../src/login/org.freedesktop.login1.policy.in.h:49
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
msgid "Manage active sessions, users and seats"
msgstr "Aktif oturumları, kullanıcıları ve yuvaları yönet"
-#: ../src/login/org.freedesktop.login1.policy.in.h:50
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
msgid ""
"Authentication is required for managing active sessions, users and seats."
msgstr ""
"Aktif oturumları, kullanıcıları ve yuvaları yönetmek için kimlik doğrulaması "
"gereklidir."
-#: ../src/login/org.freedesktop.login1.policy.in.h:51
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
msgid "Lock or unlock active sessions"
msgstr "Aktif oturumları kilitle ya da kilidini aç"
-#: ../src/login/org.freedesktop.login1.policy.in.h:52
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
msgid "Authentication is required to lock or unlock active sessions."
msgstr ""
"Aktif oturumları kilitlemek ve bunların kilidini açmak için kimlik "
"doğrulaması gereklidir."
-#: ../src/login/org.freedesktop.login1.policy.in.h:53
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
msgid "Allow indication to the firmware to boot to setup interface"
msgstr ""
"Kurulum arayüzünü önyüklemek için ürün yazılımının belirtilmesine izin ver"
-#: ../src/login/org.freedesktop.login1.policy.in.h:54
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
msgid ""
"Authentication is required to indicate to the firmware to boot to setup "
"interface."
@@ -440,11 +452,11 @@ msgstr ""
"Kurulum arayüzünü önyüklemek için ürün yazılımının belirtilmesi için kimlik "
"doğrulaması gereklidir."
-#: ../src/login/org.freedesktop.login1.policy.in.h:55
+#: ../src/login/org.freedesktop.login1.policy.in.h:57
msgid "Set a wall message"
msgstr "Bir duvar mesajı ayarla"
-#: ../src/login/org.freedesktop.login1.policy.in.h:56
+#: ../src/login/org.freedesktop.login1.policy.in.h:58
msgid "Authentication is required to set a wall message"
msgstr "Duvar mesajı ayarlamak için kimlik doğrulaması gereklidir"
@@ -565,33 +577,33 @@ msgid ""
msgstr ""
"Ağ zaman eş zamanlamasını kontrol etmek kimlik doğrulaması gerektiriyor."
-#: ../src/core/dbus-unit.c:428
+#: ../src/core/dbus-unit.c:450
msgid "Authentication is required to start '$(unit)'."
msgstr "'$(unit)' başlatmak için kimlik doğrulaması gereklidir."
-#: ../src/core/dbus-unit.c:429
+#: ../src/core/dbus-unit.c:451
msgid "Authentication is required to stop '$(unit)'."
msgstr "'$(unit)' durdurmak için kimlik doğrulaması gereklidir."
-#: ../src/core/dbus-unit.c:430
+#: ../src/core/dbus-unit.c:452
msgid "Authentication is required to reload '$(unit)'."
msgstr "'$(unit)' yeniden yüklemek için kimlik doğrulaması gereklidir."
-#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+#: ../src/core/dbus-unit.c:453 ../src/core/dbus-unit.c:454
msgid "Authentication is required to restart '$(unit)'."
msgstr "'$(unit)' yeniden başlatmak için kimlik doğrulaması gereklidir."
-#: ../src/core/dbus-unit.c:535
+#: ../src/core/dbus-unit.c:560
msgid "Authentication is required to kill '$(unit)'."
msgstr "'$(unit)' sonlandırmak için kimlik doğrulaması gereklidir."
-#: ../src/core/dbus-unit.c:565
+#: ../src/core/dbus-unit.c:590
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
msgstr ""
"'$(unit)'in \"failed\" (başarısız) durumunu sıfırlamak için kimlik "
"doğrulaması gereklidir."
-#: ../src/core/dbus-unit.c:597
+#: ../src/core/dbus-unit.c:622
msgid "Authentication is required to set properties on '$(unit)'."
msgstr ""
"'$(unit)' üzerindeki özellikleri ayarlamak için kimlik doğrulaması "
diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules
index 408733915c..cbd44cb242 100644
--- a/rules/60-persistent-storage.rules
+++ b/rules/60-persistent-storage.rules
@@ -6,7 +6,7 @@
ACTION=="remove", GOTO="persistent_storage_end"
SUBSYSTEM!="block", GOTO="persistent_storage_end"
-KERNEL!="loop*|mmcblk*[0-9]|msblk*[0-9]|mspblk*[0-9]|nvme*|sd*|sr*|vd*|xvd*|bcache*|cciss*|dasd*|ubd*", GOTO="persistent_storage_end"
+KERNEL!="loop*|mmcblk*[0-9]|msblk*[0-9]|mspblk*[0-9]|nvme*|sd*|sr*|vd*|xvd*|bcache*|cciss*|dasd*|ubd*|scm*", GOTO="persistent_storage_end"
# ignore partitions that span the entire disk
TEST=="whole_disk", GOTO="persistent_storage_end"
diff --git a/shell-completion/bash/machinectl b/shell-completion/bash/machinectl
index e7829ca968..aebe48304d 100644
--- a/shell-completion/bash/machinectl
+++ b/shell-completion/bash/machinectl
@@ -41,7 +41,7 @@ _machinectl() {
local -A VERBS=(
[STANDALONE]='list list-images pull-tar pull-raw import-tar import-raw export-tar export-raw list-transfers cancel-transfer'
- [MACHINES]='status show start login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit'
+ [MACHINES]='status show start stop login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit'
)
_init_completion || return
diff --git a/shell-completion/zsh/_machinectl b/shell-completion/zsh/_machinectl
index 198fa28f7b..92d77109a5 100644
--- a/shell-completion/zsh/_machinectl
+++ b/shell-completion/zsh/_machinectl
@@ -23,6 +23,7 @@ _available_machines() {
"status:Show VM/container status"
"show:Show properties of one or more VMs/containers"
"start:Start container as a service"
+ "stop:Stop container (equal to poweroff)"
"login:Get a login prompt on a VM/container"
"enable:Enable automatic container start at boot"
"disable:Disable automatic container start at boot"
diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c
index 92fa5ace61..d488cfc59f 100644
--- a/src/basic/exit-status.c
+++ b/src/basic/exit-status.c
@@ -38,8 +38,7 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
return "FAILURE";
}
-
- if (level == EXIT_STATUS_SYSTEMD || level == EXIT_STATUS_LSB) {
+ if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB)) {
switch ((int) status) {
case EXIT_CHDIR:
@@ -189,13 +188,9 @@ bool is_clean_exit(int code, int status, ExitStatusSet *success_status) {
/* If a daemon does not implement handlers for some of the
* signals that's not considered an unclean shutdown */
if (code == CLD_KILLED)
- return
- status == SIGHUP ||
- status == SIGINT ||
- status == SIGTERM ||
- status == SIGPIPE ||
+ return IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE) ||
(success_status &&
- set_contains(success_status->signal, INT_TO_PTR(status)));
+ set_contains(success_status->signal, INT_TO_PTR(status)));
return false;
}
@@ -207,15 +202,14 @@ bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status) {
return
code == CLD_EXITED &&
- (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED);
+ IN_SET(status, EXIT_NOTINSTALLED, EXIT_NOTCONFIGURED);
}
void exit_status_set_free(ExitStatusSet *x) {
assert(x);
- set_free(x->status);
- set_free(x->signal);
- x->status = x->signal = NULL;
+ x->status = set_free(x->status);
+ x->signal = set_free(x->signal);
}
bool exit_status_set_is_empty(ExitStatusSet *x) {
diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h
index 1208c8feed..2309f68815 100644
--- a/src/basic/exit-status.h
+++ b/src/basic/exit-status.h
@@ -25,6 +25,12 @@
#include "macro.h"
#include "set.h"
+/* This defines pretty names for the LSB 'start' verb exit codes. Note that they shouldn't be confused with the LSB
+ * 'status' verb exit codes which are defined very differently. For details see:
+ *
+ * https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
+ */
+
typedef enum ExitStatus {
/* EXIT_SUCCESS defined by libc */
/* EXIT_FAILURE defined by libc */
@@ -37,9 +43,7 @@ typedef enum ExitStatus {
/* The LSB suggests that error codes >= 200 are "reserved". We
* use them here under the assumption that they hence are
- * unused by init scripts.
- *
- * http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */
+ * unused by init scripts. */
EXIT_CHDIR = 200,
EXIT_NICE,
@@ -81,9 +85,9 @@ typedef enum ExitStatus {
} ExitStatus;
typedef enum ExitStatusLevel {
- EXIT_STATUS_MINIMAL,
- EXIT_STATUS_SYSTEMD,
- EXIT_STATUS_LSB,
+ EXIT_STATUS_MINIMAL, /* only cover libc EXIT_STATUS/EXIT_FAILURE */
+ EXIT_STATUS_SYSTEMD, /* cover libc and systemd's own exit codes */
+ EXIT_STATUS_LSB, /* cover libc, systemd's own and LSB exit codes */
EXIT_STATUS_FULL = EXIT_STATUS_LSB
} ExitStatusLevel;
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index 245107ebb8..aa7ccd1afd 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -20,26 +20,36 @@
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
+#include <net/if.h>
#include <stdint.h>
#include <stdlib.h>
#include "alloc-util.h"
#include "in-addr-util.h"
#include "macro.h"
+#include "parse-util.h"
#include "util.h"
+bool in4_addr_is_null(const struct in_addr *a) {
+ return a->s_addr == 0;
+}
+
+bool in6_addr_is_null(const struct in6_addr *a) {
+ return
+ a->s6_addr32[0] == 0 &&
+ a->s6_addr32[1] == 0 &&
+ a->s6_addr32[2] == 0 &&
+ a->s6_addr32[3] == 0;
+}
+
int in_addr_is_null(int family, const union in_addr_union *u) {
assert(u);
if (family == AF_INET)
- return u->in.s_addr == 0;
+ return in4_addr_is_null(&u->in);
if (family == AF_INET6)
- return
- u->in6.s6_addr32[0] == 0 &&
- u->in6.s6_addr32[1] == 0 &&
- u->in6.s6_addr32[2] == 0 &&
- u->in6.s6_addr32[3] == 0;
+ return in6_addr_is_null(&u->in6);
return -EAFNOSUPPORT;
}
@@ -224,6 +234,48 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
return 0;
}
+int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
+ size_t l;
+ char *x;
+ int r;
+
+ assert(u);
+ assert(ret);
+
+ /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
+ * handle IPv6 link-local addresses. */
+
+ if (family != AF_INET6)
+ goto fallback;
+ if (ifindex <= 0)
+ goto fallback;
+
+ r = in_addr_is_link_local(family, u);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ goto fallback;
+
+ l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1;
+ x = new(char, l);
+ if (!x)
+ return -ENOMEM;
+
+ errno = 0;
+ if (!inet_ntop(family, u, x, l)) {
+ free(x);
+ return errno > 0 ? -errno : -EINVAL;
+ }
+
+ sprintf(strchr(x, 0), "%%%i", ifindex);
+ *ret = x;
+
+ return 0;
+
+fallback:
+ return in_addr_to_string(family, u, ret);
+}
+
int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
assert(s);
@@ -261,6 +313,47 @@ int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *re
return -EINVAL;
}
+int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
+ const char *suffix;
+ int r, ifi = 0;
+
+ assert(s);
+ assert(family);
+ assert(ret);
+
+ /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
+ * if one is found. */
+
+ suffix = strchr(s, '%');
+ if (suffix) {
+
+ if (ifindex) {
+ /* If we shall return the interface index, try to parse it */
+ r = parse_ifindex(suffix + 1, &ifi);
+ if (r < 0) {
+ unsigned u;
+
+ u = if_nametoindex(suffix + 1);
+ if (u <= 0)
+ return -errno;
+
+ ifi = (int) u;
+ }
+ }
+
+ s = strndupa(s, suffix - s);
+ }
+
+ r = in_addr_from_string_auto(s, family, ret);
+ if (r < 0)
+ return r;
+
+ if (ifindex)
+ *ifindex = ifi;
+
+ return r;
+}
+
unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
assert(addr);
diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h
index 17798ce816..d60064aef8 100644
--- a/src/basic/in-addr-util.h
+++ b/src/basic/in-addr-util.h
@@ -36,6 +36,9 @@ struct in_addr_data {
union in_addr_union address;
};
+bool in4_addr_is_null(const struct in_addr *a);
+bool in6_addr_is_null(const struct in6_addr *a);
+
int in_addr_is_null(int family, const union in_addr_union *u);
int in_addr_is_link_local(int family, const union in_addr_union *u);
int in_addr_is_localhost(int family, const union in_addr_union *u);
@@ -43,8 +46,10 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_
int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
+int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret);
+int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr);
struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
diff --git a/src/basic/macro.h b/src/basic/macro.h
index e41aa4260f..6b2aeb933f 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -89,6 +89,15 @@
#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
#define UNIQ __COUNTER__
+/* builtins */
+#if __SIZEOF_INT__ == 4
+#define BUILTIN_FFS_U32(x) __builtin_ffs(x);
+#elif __SIZEOF_LONG__ == 4
+#define BUILTIN_FFS_U32(x) __builtin_ffsl(x);
+#else
+#error "neither int nor long are four bytes long?!?"
+#endif
+
/* Rounds up */
#define ALIGN4(l) (((l) + 3) & ~3)
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 51dafcaca9..8b977871e9 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -759,6 +759,14 @@ struct btrfs_ioctl_quota_ctl_args {
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
#endif
+#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN
+#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
+#endif
+
+#ifndef BRIDGE_VLAN_INFO_RANGE_END
+#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
+#endif
+
#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID
#define IFLA_BR_UNSPEC 0
#define IFLA_BR_FORWARD_DELAY 1
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index b991e7c6ba..08fa98bb9e 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -102,6 +102,7 @@ int get_process_comm(pid_t pid, char **name) {
int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
_cleanup_fclose_ FILE *f = NULL;
+ bool space = false;
char *r = NULL, *k;
const char *p;
int c;
@@ -128,14 +129,21 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
return -ENOMEM;
}
- r[len++] = isprint(c) ? c : ' ';
- }
+ if (isprint(c)) {
+ if (space) {
+ r[len++] = ' ';
+ space = false;
+ }
+
+ r[len++] = c;
+ } else
+ space = true;
+ }
if (len > 0)
- r[len-1] = 0;
+ r[len] = 0;
} else {
- bool space = false;
size_t left;
r = new(char, max_length);
@@ -317,9 +325,6 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
assert(field);
assert(uid);
- if (pid == 0)
- return getuid();
-
p = procfs_file_alloca(pid, "status");
f = fopen(p, "re");
if (!f) {
diff --git a/src/basic/random-util.c b/src/basic/random-util.c
index 2f468db770..ad7b3eedf2 100644
--- a/src/basic/random-util.c
+++ b/src/basic/random-util.c
@@ -46,7 +46,7 @@ int dev_urandom(void *p, size_t n) {
* never block, and will always return some data from the
* kernel, regardless if the random pool is fully initialized
* or not. It thus makes no guarantee for the quality of the
- * returned entropy, but is good enough for or usual usecases
+ * returned entropy, but is good enough for our usual usecases
* of seeding the hash functions for hashtable */
/* Use the getrandom() syscall unless we know we don't have
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index edd9179cb8..24e681bf85 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -87,6 +87,16 @@ dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
return ts;
}
+triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
+ assert(ts);
+
+ ts->realtime = now(CLOCK_REALTIME);
+ ts->monotonic = now(CLOCK_MONOTONIC);
+ ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY;
+
+ return ts;
+}
+
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
int64_t delta;
assert(ts);
@@ -104,6 +114,24 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
return ts;
}
+triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) {
+ int64_t delta;
+
+ assert(ts);
+
+ if (u == USEC_INFINITY || u <= 0) {
+ ts->realtime = ts->monotonic = ts->boottime = u;
+ return ts;
+ }
+
+ ts->realtime = u;
+ delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
+ ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta);
+ ts->boottime = clock_boottime_supported() ? usec_sub(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
+
+ return ts;
+}
+
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
int64_t delta;
assert(ts);
@@ -136,6 +164,26 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
return ts;
}
+usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) {
+
+ switch (clock) {
+
+ case CLOCK_REALTIME:
+ case CLOCK_REALTIME_ALARM:
+ return ts->realtime;
+
+ case CLOCK_MONOTONIC:
+ return ts->monotonic;
+
+ case CLOCK_BOOTTIME:
+ case CLOCK_BOOTTIME_ALARM:
+ return ts->boottime;
+
+ default:
+ return USEC_INFINITY;
+ }
+}
+
usec_t timespec_load(const struct timespec *ts) {
assert(ts);
@@ -1107,6 +1155,30 @@ clockid_t clock_boottime_or_monotonic(void) {
return CLOCK_MONOTONIC;
}
+bool clock_supported(clockid_t clock) {
+ struct timespec ts;
+
+ switch (clock) {
+
+ case CLOCK_MONOTONIC:
+ case CLOCK_REALTIME:
+ return true;
+
+ case CLOCK_BOOTTIME:
+ return clock_boottime_supported();
+
+ case CLOCK_BOOTTIME_ALARM:
+ if (!clock_boottime_supported())
+ return false;
+
+ /* fall through, after checking the cached value for CLOCK_BOOTTIME. */
+
+ default:
+ /* For everything else, check properly */
+ return clock_gettime(clock, &ts) >= 0;
+ }
+}
+
int get_timezone(char **tz) {
_cleanup_free_ char *t = NULL;
const char *e;
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index a5e3f567ec..1b058f0e49 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -39,6 +39,12 @@ typedef struct dual_timestamp {
usec_t monotonic;
} dual_timestamp;
+typedef struct triple_timestamp {
+ usec_t realtime;
+ usec_t monotonic;
+ usec_t boottime;
+} triple_timestamp;
+
#define USEC_INFINITY ((usec_t) -1)
#define NSEC_INFINITY ((nsec_t) -1)
@@ -69,7 +75,8 @@ typedef struct dual_timestamp {
#define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
-#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL })
+#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) {})
+#define TRIPLE_TIMESTAMP_NULL ((struct triple_timestamp) {})
usec_t now(clockid_t clock);
nsec_t now_nsec(clockid_t clock);
@@ -79,11 +86,28 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u);
dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u);
+triple_timestamp* triple_timestamp_get(triple_timestamp *ts);
+triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u);
+
+#define DUAL_TIMESTAMP_HAS_CLOCK(clock) \
+ IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC)
+
+#define TRIPLE_TIMESTAMP_HAS_CLOCK(clock) \
+ IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM)
+
static inline bool dual_timestamp_is_set(dual_timestamp *ts) {
return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) ||
(ts->monotonic > 0 && ts->monotonic != USEC_INFINITY));
}
+static inline bool triple_timestamp_is_set(triple_timestamp *ts) {
+ return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) ||
+ (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY) ||
+ (ts->boottime > 0 && ts->boottime != USEC_INFINITY));
+}
+
+usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock);
+
usec_t timespec_load(const struct timespec *ts) _pure_;
struct timespec *timespec_store(struct timespec *ts, usec_t u);
@@ -113,6 +137,7 @@ int get_timezones(char ***l);
bool timezone_is_valid(const char *name);
bool clock_boottime_supported(void);
+bool clock_supported(clockid_t clock);
clockid_t clock_boottime_or_monotonic(void);
#define xstrftime(buf, fmt, tm) \
diff --git a/src/basic/unaligned.h b/src/basic/unaligned.h
index 79be645bed..7c847a3ccb 100644
--- a/src/basic/unaligned.h
+++ b/src/basic/unaligned.h
@@ -109,3 +109,21 @@ static inline void unaligned_write_le64(void *_u, uint64_t a) {
unaligned_write_le32(u, (uint32_t) a);
unaligned_write_le32(u + 4, (uint32_t) (a >> 32));
}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define unaligned_read_ne16 unaligned_read_be16
+#define unaligned_read_ne32 unaligned_read_be32
+#define unaligned_read_ne64 unaligned_read_be64
+
+#define unaligned_write_ne16 unaligned_write_be16
+#define unaligned_write_ne32 unaligned_write_be32
+#define unaligned_write_ne64 unaligned_write_be64
+#else
+#define unaligned_read_ne16 unaligned_read_le16
+#define unaligned_read_ne32 unaligned_read_le32
+#define unaligned_read_ne64 unaligned_read_le64
+
+#define unaligned_write_ne16 unaligned_write_le16
+#define unaligned_write_ne32 unaligned_write_le32
+#define unaligned_write_ne64 unaligned_write_le64
+#endif
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index 6bd2288897..c67b328b38 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -868,14 +868,16 @@ static int get_cgroup_root(char **ret) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_free_ char *unit = NULL, *path = NULL;
- char *aux;
const char *m;
int r;
if (arg_root) {
+ char *aux;
+
aux = strdup(arg_root);
if (!aux)
return log_oom();
+
*ret = aux;
return 0;
}
diff --git a/src/core/execute.c b/src/core/execute.c
index 2cef70e668..c20650626c 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -552,6 +552,10 @@ static int chown_terminal(int fd, uid_t uid) {
assert(fd >= 0);
+ /* Before we chown/chmod the TTY, let's ensure this is actually a tty */
+ if (isatty(fd) < 1)
+ return 0;
+
/* This might fail. What matters are the results. */
(void) fchown(fd, uid, -1);
(void) fchmod(fd, TTY_MODE);
@@ -795,7 +799,7 @@ static int setup_pam(
const char *user,
uid_t uid,
const char *tty,
- char ***pam_env,
+ char ***env,
int fds[], unsigned n_fds) {
static const struct pam_conv conv = {
@@ -814,7 +818,7 @@ static int setup_pam(
assert(name);
assert(user);
- assert(pam_env);
+ assert(env);
/* We set up PAM in the parent process, then fork. The child
* will then stay around until killed via PR_GET_PDEATHSIG or
@@ -842,6 +846,12 @@ static int setup_pam(
goto fail;
}
+ STRV_FOREACH(e, *env) {
+ pam_code = pam_putenv(handle, *e);
+ if (pam_code != PAM_SUCCESS)
+ goto fail;
+ }
+
pam_code = pam_acct_mgmt(handle, flags);
if (pam_code != PAM_SUCCESS)
goto fail;
@@ -962,8 +972,8 @@ static int setup_pam(
if (!barrier_place_and_sync(&barrier))
log_error("PAM initialization failed");
- *pam_env = e;
- e = NULL;
+ strv_free(*env);
+ *env = e;
return 0;
@@ -1460,7 +1470,7 @@ static int exec_child(
char **files_env,
int *exit_status) {
- _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
+ _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL;
_cleanup_free_ char *mac_selinux_context_net = NULL;
const char *username = NULL, *home = NULL, *shell = NULL, *wd;
uid_t uid = UID_INVALID;
@@ -1711,9 +1721,33 @@ static int exec_child(
}
}
+ r = build_environment(context, params, n_fds, home, username, shell, &our_env);
+ if (r < 0) {
+ *exit_status = EXIT_MEMORY;
+ return r;
+ }
+
+ r = build_pass_environment(context, &pass_env);
+ if (r < 0) {
+ *exit_status = EXIT_MEMORY;
+ return r;
+ }
+
+ accum_env = strv_env_merge(5,
+ params->environment,
+ our_env,
+ pass_env,
+ context->environment,
+ files_env,
+ NULL);
+ if (!accum_env) {
+ *exit_status = EXIT_MEMORY;
+ return -ENOMEM;
+ }
+
umask(context->umask);
- if (params->apply_permissions) {
+ if (params->apply_permissions && !command->privileged) {
r = enforce_groups(context, username, gid);
if (r < 0) {
*exit_status = EXIT_GROUP;
@@ -1747,7 +1781,7 @@ static int exec_child(
#endif
#ifdef HAVE_PAM
if (context->pam_name && username) {
- r = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
+ r = setup_pam(context->pam_name, username, uid, context->tty_path, &accum_env, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_PAM;
return r;
@@ -1838,7 +1872,7 @@ static int exec_child(
}
#ifdef HAVE_SELINUX
- if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) {
+ if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0 && !command->privileged) {
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
if (r < 0) {
*exit_status = EXIT_SELINUX_CONTEXT;
@@ -1863,7 +1897,7 @@ static int exec_child(
return r;
}
- if (params->apply_permissions) {
+ if (params->apply_permissions && !command->privileged) {
bool use_address_families = context->address_families_whitelist ||
!set_isempty(context->address_families);
@@ -1993,38 +2027,13 @@ static int exec_child(
#endif
}
- r = build_environment(context, params, n_fds, home, username, shell, &our_env);
- if (r < 0) {
- *exit_status = EXIT_MEMORY;
- return r;
- }
-
- r = build_pass_environment(context, &pass_env);
- if (r < 0) {
- *exit_status = EXIT_MEMORY;
- return r;
- }
-
- final_env = strv_env_merge(6,
- params->environment,
- our_env,
- pass_env,
- context->environment,
- files_env,
- pam_env,
- NULL);
- if (!final_env) {
- *exit_status = EXIT_MEMORY;
- return -ENOMEM;
- }
-
- final_argv = replace_env_argv(argv, final_env);
+ final_argv = replace_env_argv(argv, accum_env);
if (!final_argv) {
*exit_status = EXIT_MEMORY;
return -ENOMEM;
}
- final_env = strv_env_clean(final_env);
+ accum_env = strv_env_clean(accum_env);
if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
_cleanup_free_ char *line;
@@ -2041,7 +2050,7 @@ static int exec_child(
}
}
- execve(command->path, final_argv, final_env);
+ execve(command->path, final_argv, accum_env);
*exit_status = EXIT_EXEC;
return -errno;
}
diff --git a/src/core/execute.h b/src/core/execute.h
index 464869d226..cd1f7b36f6 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -81,7 +81,8 @@ struct ExecCommand {
char **argv;
ExecStatus exec_status;
LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */
- bool ignore;
+ bool ignore:1;
+ bool privileged:1;
};
struct ExecRuntime {
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index b53301a147..17c72aed88 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -596,7 +596,7 @@ int config_parse_exec(
p = rvalue;
do {
_cleanup_free_ char *path = NULL, *firstword = NULL;
- bool separate_argv0 = false, ignore = false;
+ bool separate_argv0 = false, ignore = false, privileged = false;
_cleanup_free_ ExecCommand *nce = NULL;
_cleanup_strv_free_ char **n = NULL;
size_t nlen = 0, nbufsize = 0;
@@ -610,14 +610,18 @@ int config_parse_exec(
return 0;
f = firstword;
- for (i = 0; i < 2; i++) {
- /* We accept an absolute path as first argument, or
- * alternatively an absolute prefixed with @ to allow
- * overriding of argv[0]. */
+ for (i = 0; i < 3; i++) {
+ /* We accept an absolute path as first argument.
+ * If it's prefixed with - and the path doesn't exist,
+ * we ignore it instead of erroring out;
+ * if it's prefixed with @, we allow overriding of argv[0];
+ * and if it's prefixed with !, it will be run with full privileges */
if (*f == '-' && !ignore)
ignore = true;
else if (*f == '@' && !separate_argv0)
separate_argv0 = true;
+ else if (*f == '!' && !privileged)
+ privileged = true;
else
break;
f++;
@@ -715,6 +719,7 @@ int config_parse_exec(
nce->argv = n;
nce->path = path;
nce->ignore = ignore;
+ nce->privileged = privileged;
exec_command_append_list(e, nce);
@@ -3743,7 +3748,7 @@ static int merge_by_names(Unit **u, Set *names, const char *id) {
/* If the symlink name we are looking at is unit template, then
we must search for instance of this template */
- if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE)) {
+ if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
_cleanup_free_ char *instance = NULL;
r = unit_name_replace_instance(k, (*u)->instance, &instance);
diff --git a/src/core/manager.c b/src/core/manager.c
index 14d97a87d0..ec8acdff5b 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -136,23 +136,28 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po
if (pos > 1) {
if (pos > 2)
p = mempset(p, ' ', pos-2);
- p = stpcpy(p, ANSI_RED);
+ if (log_get_show_color())
+ p = stpcpy(p, ANSI_RED);
*p++ = '*';
}
if (pos > 0 && pos <= width) {
- p = stpcpy(p, ANSI_HIGHLIGHT_RED);
+ if (log_get_show_color())
+ p = stpcpy(p, ANSI_HIGHLIGHT_RED);
*p++ = '*';
}
- p = stpcpy(p, ANSI_NORMAL);
+ if (log_get_show_color())
+ p = stpcpy(p, ANSI_NORMAL);
if (pos < width) {
- p = stpcpy(p, ANSI_RED);
+ if (log_get_show_color())
+ p = stpcpy(p, ANSI_RED);
*p++ = '*';
if (pos < width-1)
p = mempset(p, ' ', width-1-pos);
- strcpy(p, ANSI_NORMAL);
+ if (log_get_show_color())
+ strcpy(p, ANSI_NORMAL);
}
}
diff --git a/src/core/mount.c b/src/core/mount.c
index 665a60bb55..fda4d65d6f 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1706,6 +1706,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
/* This has just been unmounted by
* somebody else, follow the state
* change. */
+ mount->result = MOUNT_SUCCESS; /* make sure we forget any earlier umount failures */
mount_enter_dead(mount, MOUNT_SUCCESS);
break;
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 108522873e..fc7cf39847 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -496,6 +496,12 @@ static int add_sysroot_mount(void) {
return 0;
}
+ if (streq(arg_root_what, "gpt-auto")) {
+ /* This is handled by the gpt-auto generator */
+ log_debug("Skipping root directory handling, as gpt-auto was requested.");
+ return 0;
+ }
+
what = fstab_node_to_udev_node(arg_root_what);
if (!what)
return log_oom();
diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c
index 1160dacdf1..e12cd93d1c 100644
--- a/src/hwdb/hwdb.c
+++ b/src/hwdb/hwdb.c
@@ -29,7 +29,9 @@
#include "fs-util.h"
#include "hwdb-internal.h"
#include "hwdb-util.h"
+#include "label.h"
#include "mkdir.h"
+#include "selinux-util.h"
#include "strbuf.h"
#include "string-util.h"
#include "strv.h"
@@ -643,12 +645,12 @@ static int hwdb_update(int argc, char *argv[], void *userdata) {
if (!hwdb_bin)
return -ENOMEM;
- mkdir_parents(hwdb_bin, 0755);
+ mkdir_parents_label(hwdb_bin, 0755);
r = trie_store(trie, hwdb_bin);
if (r < 0)
return log_error_errno(r, "Failure writing database %s: %m", hwdb_bin);
- return 0;
+ return label_fix(hwdb_bin, false, false);
}
static void help(void) {
@@ -732,6 +734,8 @@ int main (int argc, char *argv[]) {
if (r <= 0)
goto finish;
+ mac_selinux_init();
+
r = hwdb_main(argc, argv);
finish:
diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c
index d81e9ebd88..c2e4b0e9e3 100644
--- a/src/libsystemd-network/icmp6-util.c
+++ b/src/libsystemd-network/icmp6-util.c
@@ -49,7 +49,8 @@ int icmp6_bind_router_solicitation(int index) {
};
_cleanup_close_ int s = -1;
char ifname[IF_NAMESIZE] = "";
- int r, zero = 0, one = 1, hops = 255;
+ static const int zero = 0, one = 1, hops = 255;
+ int r;
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
if (s < 0)
@@ -85,6 +86,10 @@ int icmp6_bind_router_solicitation(int index) {
if (r < 0)
return -errno;
+ r = setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
+ if (r < 0)
+ return -errno;
+
if (if_indextoname(index, ifname) == 0)
return -errno;
diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h
index 7592bc4305..becc162fab 100644
--- a/src/libsystemd-network/lldp-internal.h
+++ b/src/libsystemd-network/lldp-internal.h
@@ -28,6 +28,8 @@
#include "prioq.h"
struct sd_lldp {
+ unsigned n_ref;
+
int ifindex;
int fd;
diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c
index 6a716430e3..88f7e329b0 100644
--- a/src/libsystemd-network/lldp-neighbor.c
+++ b/src/libsystemd-network/lldp-neighbor.c
@@ -360,9 +360,16 @@ end_marker:
void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) {
assert(n);
- if (n->ttl > 0)
- n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC);
- else
+ if (n->ttl > 0) {
+ usec_t base;
+
+ /* Use the packet's timestamp if there is one known */
+ base = triple_timestamp_by_clock(&n->timestamp, clock_boottime_or_monotonic());
+ if (base <= 0 || base == USEC_INFINITY)
+ base = now(clock_boottime_or_monotonic()); /* Otherwise, take the current time */
+
+ n->until = usec_add(base, n->ttl * USEC_PER_SEC);
+ } else
n->until = 0;
if (n->lldp)
@@ -588,11 +595,11 @@ done:
return 0;
}
-_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret) {
+_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
assert_return(n, -EINVAL);
- assert_return(ret, -EINVAL);
+ assert_return(ret_sec, -EINVAL);
- *ret = n->ttl;
+ *ret_sec = n->ttl;
return 0;
}
@@ -651,7 +658,7 @@ _public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint
return 0;
}
-int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
+_public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
int r;
@@ -668,7 +675,7 @@ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t ra
return r;
*ret = n;
- n = 0;
+ n = NULL;
return r;
}
@@ -679,7 +686,7 @@ _public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
assert(n->raw_size >= sizeof(struct ether_header));
n->rindex = sizeof(struct ether_header);
- return 0;
+ return n->rindex < n->raw_size;
}
_public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
@@ -693,7 +700,7 @@ _public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
if (n->rindex + 2 > n->raw_size) /* Truncated message */
return -EBADMSG;
- length = LLDP_NEIGHBOR_LENGTH(n);
+ length = LLDP_NEIGHBOR_TLV_LENGTH(n);
if (n->rindex + 2 + length > n->raw_size)
return -EBADMSG;
@@ -711,7 +718,7 @@ _public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
if (n->rindex + 2 > n->raw_size)
return -EBADMSG;
- *type = LLDP_NEIGHBOR_TYPE(n);
+ *type = LLDP_NEIGHBOR_TLV_TYPE(n);
return 0;
}
@@ -743,14 +750,14 @@ _public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], u
if (r == 0)
return -ENXIO;
- length = LLDP_NEIGHBOR_LENGTH(n);
+ length = LLDP_NEIGHBOR_TLV_LENGTH(n);
if (length < 4)
return -EBADMSG;
if (n->rindex + 2 + length > n->raw_size)
return -EBADMSG;
- d = LLDP_NEIGHBOR_DATA(n);
+ d = LLDP_NEIGHBOR_TLV_DATA(n);
memcpy(oui, d, 3);
*subtype = d[3];
@@ -782,8 +789,7 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret,
if (n->rindex + 2 > n->raw_size)
return -EBADMSG;
- length = LLDP_NEIGHBOR_LENGTH(n);
-
+ length = LLDP_NEIGHBOR_TLV_LENGTH(n);
if (n->rindex + 2 + length > n->raw_size)
return -EBADMSG;
@@ -792,3 +798,16 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret,
return 0;
}
+
+_public_ int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) {
+ assert_return(n, -EINVAL);
+ assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
+ assert_return(clock_supported(clock), -EOPNOTSUPP);
+ assert_return(ret, -EINVAL);
+
+ if (!triple_timestamp_is_set(&n->timestamp))
+ return -ENODATA;
+
+ *ret = triple_timestamp_by_clock(&n->timestamp, clock);
+ return 0;
+}
diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h
index f203bfa604..c1a7606d06 100644
--- a/src/libsystemd-network/lldp-neighbor.h
+++ b/src/libsystemd-network/lldp-neighbor.h
@@ -43,6 +43,8 @@ struct sd_lldp_neighbor {
sd_lldp *lldp;
unsigned n_ref;
+ triple_timestamp timestamp;
+
usec_t until;
unsigned prioq_idx;
@@ -81,18 +83,18 @@ static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) {
return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor));
}
-static inline uint8_t LLDP_NEIGHBOR_TYPE(const sd_lldp_neighbor *n) {
+static inline uint8_t LLDP_NEIGHBOR_TLV_TYPE(const sd_lldp_neighbor *n) {
return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1;
}
-static inline size_t LLDP_NEIGHBOR_LENGTH(const sd_lldp_neighbor *n) {
+static inline size_t LLDP_NEIGHBOR_TLV_LENGTH(const sd_lldp_neighbor *n) {
uint8_t *p;
p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
return p[1] + (((size_t) (p[0] & 1)) << 8);
}
-static inline void* LLDP_NEIGHBOR_DATA(const sd_lldp_neighbor *n) {
+static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) {
return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2;
}
diff --git a/src/libsystemd-network/ndisc-internal.h b/src/libsystemd-network/ndisc-internal.h
new file mode 100644
index 0000000000..60e183ff8c
--- /dev/null
+++ b/src/libsystemd-network/ndisc-internal.h
@@ -0,0 +1,49 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "log.h"
+
+#include "sd-ndisc.h"
+
+struct sd_ndisc {
+ unsigned n_ref;
+
+ int ifindex;
+ int fd;
+
+ sd_event *event;
+ int event_priority;
+
+ struct ether_addr mac_addr;
+ uint8_t hop_limit;
+ uint32_t mtu;
+
+ sd_event_source *recv_event_source;
+ sd_event_source *timeout_event_source;
+
+ unsigned nd_sent;
+
+ sd_ndisc_callback_t callback;
+ void *userdata;
+};
+
+#define log_ndisc_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDISC: " fmt, ##__VA_ARGS__)
+#define log_ndisc(fmt, ...) log_ndisc_errno(0, fmt, ##__VA_ARGS__)
diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/ndisc-router.c
new file mode 100644
index 0000000000..d9950b638c
--- /dev/null
+++ b/src/libsystemd-network/ndisc-router.c
@@ -0,0 +1,779 @@
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/icmp6.h>
+
+#include "sd-ndisc.h"
+
+#include "alloc-util.h"
+#include "dns-domain.h"
+#include "hostname-util.h"
+#include "missing.h"
+#include "ndisc-internal.h"
+#include "ndisc-router.h"
+#include "strv.h"
+
+_public_ sd_ndisc_router* sd_ndisc_router_ref(sd_ndisc_router *rt) {
+ if (!rt)
+ return NULL;
+
+ assert(rt->n_ref > 0);
+ rt->n_ref++;
+
+ return rt;
+}
+
+_public_ sd_ndisc_router* sd_ndisc_router_unref(sd_ndisc_router *rt) {
+ if (!rt)
+ return NULL;
+
+ assert(rt->n_ref > 0);
+ rt->n_ref--;
+
+ if (rt->n_ref > 0)
+ return NULL;
+
+ free(rt);
+ return NULL;
+}
+
+sd_ndisc_router *ndisc_router_new(size_t raw_size) {
+ sd_ndisc_router *rt;
+
+ rt = malloc0(ALIGN(sizeof(sd_ndisc_router)) + raw_size);
+ if (!rt)
+ return NULL;
+
+ rt->raw_size = raw_size;
+ rt->n_ref = 1;
+
+ return rt;
+}
+
+_public_ int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size) {
+ _cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = NULL;
+ int r;
+
+ assert_return(ret, -EINVAL);
+ assert_return(raw || raw_size <= 0, -EINVAL);
+
+ rt = ndisc_router_new(raw_size);
+ if (!rt)
+ return -ENOMEM;
+
+ memcpy(NDISC_ROUTER_RAW(rt), raw, raw_size);
+ r = ndisc_router_parse(rt);
+ if (r < 0)
+ return r;
+
+ *ret = rt;
+ rt = NULL;
+
+ return r;
+}
+
+_public_ int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret_addr, -EINVAL);
+
+ if (in6_addr_is_null(&rt->address))
+ return -ENODATA;
+
+ *ret_addr = rt->address;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) {
+ assert_return(rt, -EINVAL);
+ assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
+ assert_return(clock_supported(clock), -EOPNOTSUPP);
+ assert_return(ret, -EINVAL);
+
+ if (!triple_timestamp_is_set(&rt->timestamp))
+ return -ENODATA;
+
+ *ret = triple_timestamp_by_clock(&rt->timestamp, clock);
+ return 0;
+}
+
+_public_ int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+ assert_return(size, -EINVAL);
+
+ *ret = NDISC_ROUTER_RAW(rt);
+ *size = rt->raw_size;
+
+ return 0;
+}
+
+int ndisc_router_parse(sd_ndisc_router *rt) {
+ struct nd_router_advert *a;
+ const uint8_t *p;
+ bool has_mtu = false, has_flag_extension = false;
+ size_t left;
+
+ assert(rt);
+
+ if (rt->raw_size < sizeof(struct nd_router_advert)) {
+ log_ndisc("Too small to be a router advertisement, ignoring.");
+ return -EBADMSG;
+ }
+
+ /* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */
+ a = NDISC_ROUTER_RAW(rt);
+
+ if (a->nd_ra_type != ND_ROUTER_ADVERT) {
+ log_ndisc("Received ND packet that is not a router advertisement, ignoring.");
+ return -EBADMSG;
+ }
+
+ if (a->nd_ra_code != 0) {
+ log_ndisc("Received ND packet with wrong RA code, ignoring.");
+ return -EBADMSG;
+ }
+
+ rt->hop_limit = a->nd_ra_curhoplimit;
+ rt->flags = a->nd_ra_flags_reserved; /* the first 8bit */
+ rt->lifetime = be16toh(a->nd_ra_router_lifetime);
+
+ rt->preference = (rt->flags >> 3) & 3;
+ if (!IN_SET(rt->preference, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
+ rt->preference = SD_NDISC_PREFERENCE_MEDIUM;
+
+ p = (const uint8_t*) NDISC_ROUTER_RAW(rt) + sizeof(struct nd_router_advert);
+ left = rt->raw_size - sizeof(struct nd_router_advert);
+
+ for (;;) {
+ uint8_t type;
+ size_t length;
+
+ if (left == 0)
+ break;
+
+ if (left < 2) {
+ log_ndisc("Option lacks header, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ type = p[0];
+ length = p[1] * 8;
+
+ if (length == 0) {
+ log_ndisc("Zero-length option, ignoring datagram.");
+ return -EBADMSG;
+ }
+ if (left < length) {
+ log_ndisc("Option truncated, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ switch (type) {
+
+ case SD_NDISC_OPTION_PREFIX_INFORMATION:
+
+ if (length != 4*8) {
+ log_ndisc("Prefix option of invalid size, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ if (p[2] > 128) {
+ log_ndisc("Bad prefix length, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ break;
+
+ case SD_NDISC_OPTION_MTU: {
+ uint32_t m;
+
+ if (has_mtu) {
+ log_ndisc("MTU option specified twice, ignoring.");
+ continue;
+ }
+
+ if (length != 8) {
+ log_ndisc("MTU option of invalid size, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ m = be32toh(*(uint32_t*) (p + 4));
+ if (m >= IPV6_MIN_MTU) /* ignore invalidly small MTUs */
+ rt->mtu = m;
+
+ has_mtu = true;
+ break;
+ }
+
+ case SD_NDISC_OPTION_ROUTE_INFORMATION:
+ if (length < 1*8 || length > 3*8) {
+ log_ndisc("Route information option of invalid size, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ if (p[2] > 128) {
+ log_ndisc("Bad route prefix length, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ break;
+
+ case SD_NDISC_OPTION_RDNSS:
+ if (length < 3*8 || (length % (2*8)) != 1*8) {
+ log_ndisc("RDNSS option has invalid size.");
+ return -EBADMSG;
+ }
+
+ break;
+
+ case SD_NDISC_OPTION_FLAGS_EXTENSION:
+
+ if (has_flag_extension) {
+ log_ndisc("Flags extension option specified twice, ignoring.");
+ continue;
+ }
+
+ if (length < 1*8) {
+ log_ndisc("Flags extension option has invalid size.");
+ return -EBADMSG;
+ }
+
+ /* Add in the additional flags bits */
+ rt->flags |=
+ ((uint64_t) p[2] << 8) |
+ ((uint64_t) p[3] << 16) |
+ ((uint64_t) p[4] << 24) |
+ ((uint64_t) p[5] << 32) |
+ ((uint64_t) p[6] << 40) |
+ ((uint64_t) p[7] << 48);
+
+ has_flag_extension = true;
+ break;
+
+ case SD_NDISC_OPTION_DNSSL:
+ if (length < 2*8) {
+ log_ndisc("DNSSL option has invalid size.");
+ return -EBADMSG;
+ }
+
+ break;
+ }
+
+ p += length, left -= length;
+ }
+
+ rt->rindex = sizeof(struct nd_router_advert);
+ return 0;
+}
+
+_public_ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ *ret = rt->hop_limit;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret_flags, -EINVAL);
+
+ *ret_flags = rt->flags;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret_lifetime, -EINVAL);
+
+ *ret_lifetime = rt->lifetime;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ *ret = rt->preference;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (rt->mtu <= 0)
+ return -ENODATA;
+
+ *ret = rt->mtu;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
+ assert_return(rt, -EINVAL);
+
+ assert(rt->raw_size >= sizeof(struct nd_router_advert));
+ rt->rindex = sizeof(struct nd_router_advert);
+
+ return rt->rindex < rt->raw_size;
+}
+
+_public_ int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
+ size_t length;
+
+ assert_return(rt, -EINVAL);
+
+ if (rt->rindex == rt->raw_size) /* EOF */
+ return -ESPIPE;
+
+ if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
+ return -EBADMSG;
+
+ length = NDISC_ROUTER_OPTION_LENGTH(rt);
+ if (rt->rindex + length > rt->raw_size)
+ return -EBADMSG;
+
+ rt->rindex += length;
+ return rt->rindex < rt->raw_size;
+}
+
+_public_ int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (rt->rindex == rt->raw_size) /* EOF */
+ return -ESPIPE;
+
+ if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
+ return -EBADMSG;
+
+ *ret = NDISC_ROUTER_OPTION_TYPE(rt);
+ return 0;
+}
+
+_public_ int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
+ uint8_t k;
+ int r;
+
+ assert_return(rt, -EINVAL);
+
+ r = sd_ndisc_router_option_get_type(rt, &k);
+ if (r < 0)
+ return r;
+
+ return type == k;
+}
+
+_public_ int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
+ size_t length;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+ assert_return(size, -EINVAL);
+
+ /* Note that this returns the full option, including the option header */
+
+ if (rt->rindex + 2 > rt->raw_size)
+ return -EBADMSG;
+
+ length = NDISC_ROUTER_OPTION_LENGTH(rt);
+ if (rt->rindex + length > rt->raw_size)
+ return -EBADMSG;
+
+ *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
+ *size = length;
+
+ return 0;
+}
+
+static int get_prefix_info(sd_ndisc_router *rt, struct nd_opt_prefix_info **ret) {
+ struct nd_opt_prefix_info *ri;
+ size_t length;
+ int r;
+
+ assert(rt);
+ assert(ret);
+
+ r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_PREFIX_INFORMATION);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EMEDIUMTYPE;
+
+ length = NDISC_ROUTER_OPTION_LENGTH(rt);
+ if (length != sizeof(struct nd_opt_prefix_info))
+ return -EBADMSG;
+
+ ri = (struct nd_opt_prefix_info*) ((uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex);
+ if (ri->nd_opt_pi_prefix_len > 128)
+ return -EBADMSG;
+
+ *ret = ri;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
+ struct nd_opt_prefix_info *ri;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_prefix_info(rt, &ri);
+ if (r < 0)
+ return r;
+
+ *ret = be32toh(ri->nd_opt_pi_valid_time);
+ return 0;
+}
+
+_public_ int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
+ struct nd_opt_prefix_info *pi;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_prefix_info(rt, &pi);
+ if (r < 0)
+ return r;
+
+ *ret = be32toh(pi->nd_opt_pi_preferred_time);
+ return 0;
+}
+
+_public_ int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret) {
+ struct nd_opt_prefix_info *pi;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_prefix_info(rt, &pi);
+ if (r < 0)
+ return r;
+
+ *ret = pi->nd_opt_pi_flags_reserved;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
+ struct nd_opt_prefix_info *pi;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret_addr, -EINVAL);
+
+ r = get_prefix_info(rt, &pi);
+ if (r < 0)
+ return r;
+
+ *ret_addr = pi->nd_opt_pi_prefix;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
+ struct nd_opt_prefix_info *pi;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_prefix_info(rt, &pi);
+ if (r < 0)
+ return r;
+
+ if (pi->nd_opt_pi_prefix_len > 128)
+ return -EBADMSG;
+
+ *ret = pi->nd_opt_pi_prefix_len;
+ return 0;
+}
+
+static int get_route_info(sd_ndisc_router *rt, uint8_t **ret) {
+ uint8_t *ri;
+ size_t length;
+ int r;
+
+ assert(rt);
+ assert(ret);
+
+ r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_ROUTE_INFORMATION);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EMEDIUMTYPE;
+
+ length = NDISC_ROUTER_OPTION_LENGTH(rt);
+ if (length < 1*8 || length > 3*8)
+ return -EBADMSG;
+
+ ri = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
+
+ if (ri[2] > 128)
+ return -EBADMSG;
+
+ *ret = ri;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
+ uint8_t *ri;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_route_info(rt, &ri);
+ if (r < 0)
+ return r;
+
+ *ret = be32toh(*(uint32_t*) (ri + 4));
+ return 0;
+}
+
+_public_ int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
+ uint8_t *ri;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret_addr, -EINVAL);
+
+ r = get_route_info(rt, &ri);
+ if (r < 0)
+ return r;
+
+ zero(*ret_addr);
+ memcpy(ret_addr, ri + 8, NDISC_ROUTER_OPTION_LENGTH(rt) - 8);
+
+ return 0;
+}
+
+_public_ int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
+ uint8_t *ri;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_route_info(rt, &ri);
+ if (r < 0)
+ return r;
+
+ *ret = ri[2];
+ return 0;
+}
+
+_public_ int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret) {
+ uint8_t *ri;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_route_info(rt, &ri);
+ if (r < 0)
+ return r;
+
+ *ret = (ri[3] >> 3) & 3;
+ if (!IN_SET(*ret, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
+ *ret = SD_NDISC_PREFERENCE_MEDIUM;
+
+ return 0;
+}
+
+static int get_rdnss_info(sd_ndisc_router *rt, uint8_t **ret) {
+ size_t length;
+ int r;
+
+ assert(rt);
+ assert(ret);
+
+ r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EMEDIUMTYPE;
+
+ length = NDISC_ROUTER_OPTION_LENGTH(rt);
+ if (length < 3*8 || (length % (2*8)) != 1*8)
+ return -EBADMSG;
+
+ *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) {
+ uint8_t *ri;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_rdnss_info(rt, &ri);
+ if (r < 0)
+ return r;
+
+ *ret = (const struct in6_addr*) (ri + 8);
+ return (NDISC_ROUTER_OPTION_LENGTH(rt) - 8) / 16;
+}
+
+_public_ int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
+ uint8_t *ri;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_rdnss_info(rt, &ri);
+ if (r < 0)
+ return r;
+
+ *ret = be32toh(*(uint32_t*) (ri + 4));
+ return 0;
+}
+
+static int get_dnssl_info(sd_ndisc_router *rt, uint8_t **ret) {
+ size_t length;
+ int r;
+
+ assert(rt);
+ assert(ret);
+
+ r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_DNSSL);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EMEDIUMTYPE;
+
+ length = NDISC_ROUTER_OPTION_LENGTH(rt);
+ if (length < 2*8)
+ return -EBADMSG;
+
+ *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
+ return 0;
+}
+
+_public_ int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret) {
+ _cleanup_strv_free_ char **l = NULL;
+ _cleanup_free_ char *e = NULL;
+ size_t allocated = 0, n = 0, left;
+ uint8_t *ri, *p;
+ bool first = true;
+ int r;
+ unsigned k = 0;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = get_dnssl_info(rt, &ri);
+ if (r < 0)
+ return r;
+
+ p = ri + 8;
+ left = NDISC_ROUTER_OPTION_LENGTH(rt) - 8;
+
+ for (;;) {
+ if (left == 0) {
+
+ if (n > 0) /* Not properly NUL terminated */
+ return -EBADMSG;
+
+ break;
+ }
+
+ if (*p == 0) {
+ /* Found NUL termination */
+
+ if (n > 0) {
+ _cleanup_free_ char *normalized = NULL;
+
+ e[n] = 0;
+ r = dns_name_normalize(e, &normalized);
+ if (r < 0)
+ return r;
+
+ /* Ignore the root domain name or "localhost" and friends */
+ if (!is_localhost(normalized) &&
+ !dns_name_is_root(normalized)) {
+
+ if (strv_push(&l, normalized) < 0)
+ return -ENOMEM;
+
+ normalized = NULL;
+ k++;
+ }
+ }
+
+ n = 0;
+ first = true;
+ p++, left--;
+ continue;
+ }
+
+ /* Check for compression (which is not allowed) */
+ if (*p > 63)
+ return -EBADMSG;
+
+ if (1U + *p + 1U > left)
+ return -EBADMSG;
+
+ if (!GREEDY_REALLOC(e, allocated, n + !first + DNS_LABEL_ESCAPED_MAX + 1U))
+ return -ENOMEM;
+
+ if (first)
+ first = false;
+ else
+ e[n++] = '.';
+
+ r = dns_label_escape((char*) p+1, *p, e + n, DNS_LABEL_ESCAPED_MAX);
+ if (r < 0)
+ return r;
+
+ n += r;
+
+ left -= 1 + *p;
+ p += 1 + *p;
+ }
+
+ if (strv_isempty(l)) {
+ *ret = NULL;
+ return 0;
+ }
+
+ *ret = l;
+ l = NULL;
+
+ return k;
+}
+
+_public_ int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret_sec) {
+ uint8_t *ri;
+ int r;
+
+ assert_return(rt, -EINVAL);
+ assert_return(ret_sec, -EINVAL);
+
+ r = get_dnssl_info(rt, &ri);
+ if (r < 0)
+ return r;
+
+ *ret_sec = be32toh(*(uint32_t*) (ri + 4));
+ return 0;
+}
diff --git a/src/libsystemd-network/ndisc-router.h b/src/libsystemd-network/ndisc-router.h
new file mode 100644
index 0000000000..1fe703da63
--- /dev/null
+++ b/src/libsystemd-network/ndisc-router.h
@@ -0,0 +1,62 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-ndisc.h"
+
+#include "time-util.h"
+
+struct sd_ndisc_router {
+ unsigned n_ref;
+
+ triple_timestamp timestamp;
+ struct in6_addr address;
+
+ /* The raw packet size. The data is appended to the object, accessible via NDIS_ROUTER_RAW() */
+ size_t raw_size;
+
+ /* The current read index for the iterative option interface */
+ size_t rindex;
+
+ uint64_t flags;
+ unsigned preference;
+ uint16_t lifetime;
+
+ uint8_t hop_limit;
+ uint32_t mtu;
+};
+
+static inline void* NDISC_ROUTER_RAW(const sd_ndisc_router *rt) {
+ return (uint8_t*) rt + ALIGN(sizeof(sd_ndisc_router));
+}
+
+static inline void *NDISC_ROUTER_OPTION_DATA(const sd_ndisc_router *rt) {
+ return ((uint8_t*) NDISC_ROUTER_RAW(rt)) + rt->rindex;
+}
+
+static inline uint8_t NDISC_ROUTER_OPTION_TYPE(const sd_ndisc_router *rt) {
+ return ((uint8_t*) NDISC_ROUTER_OPTION_DATA(rt))[0];
+}
+static inline size_t NDISC_ROUTER_OPTION_LENGTH(const sd_ndisc_router *rt) {
+ return ((uint8_t*) NDISC_ROUTER_OPTION_DATA(rt))[1] * 8;
+}
+
+sd_ndisc_router *ndisc_router_new(size_t raw_size);
+int ndisc_router_parse(sd_ndisc_router *rt);
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index bfaa75880b..ce30b7fc25 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -380,18 +380,21 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) {
return size;
}
-void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
- size_t size) {
+void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size) {
unsigned i;
assert(f);
assert(addresses);
assert(size);
- for (i = 0; i < size; i++)
- fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s",
- SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]),
- (i < (size - 1)) ? " ": "");
+ for (i = 0; i < size; i++) {
+ char buffer[INET6_ADDRSTRLEN];
+
+ fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
+
+ if (i < size - 1)
+ fputc(' ', f);
+ }
}
int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index 9d4587c80e..0bd1e66aa0 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -43,7 +43,6 @@ static void lldp_flush_neighbors(sd_lldp *lldp) {
static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
assert(lldp);
- assert(n);
log_lldp("Invoking callback for '%c'.", event);
@@ -138,6 +137,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) {
if (lldp_neighbor_equal(n, old)) {
/* Is this equal, then restart the TTL counter, but don't do anyting else. */
+ old->timestamp = n->timestamp;
lldp_start_timer(lldp, old);
lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old);
return 0;
@@ -171,7 +171,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) {
finish:
if (old)
- lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n);
+ lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old);
return r;
}
@@ -202,6 +202,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
ssize_t space, length;
sd_lldp *lldp = userdata;
+ struct timespec ts;
assert(fd >= 0);
assert(lldp);
@@ -215,21 +216,41 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
return -ENOMEM;
length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
- if (length < 0)
+ if (length < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
return log_lldp_errno(errno, "Failed to read LLDP datagram: %m");
+ }
if ((size_t) length != n->raw_size) {
log_lldp("Packet size mismatch.");
return -EINVAL;
}
+ /* Try to get the timestamp of this packet if it is known */
+ if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0)
+ triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts));
+ else
+ triple_timestamp_get(&n->timestamp);
+
return lldp_handle_datagram(lldp, n);
}
+static void lldp_reset(sd_lldp *lldp) {
+ assert(lldp);
+
+ lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source);
+ lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
+ lldp->fd = safe_close(lldp->fd);
+}
+
_public_ int sd_lldp_start(sd_lldp *lldp) {
int r;
assert_return(lldp, -EINVAL);
+ assert_return(lldp->event, -EINVAL);
+ assert_return(lldp->ifindex > 0, -EINVAL);
if (lldp->fd >= 0)
return 0;
@@ -240,24 +261,21 @@ _public_ int sd_lldp_start(sd_lldp *lldp) {
if (lldp->fd < 0)
return lldp->fd;
- if (lldp->event) {
- r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp);
- if (r < 0)
- goto fail;
+ r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp);
+ if (r < 0)
+ goto fail;
- r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority);
- if (r < 0)
- goto fail;
+ r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority);
+ if (r < 0)
+ goto fail;
- (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io");
- }
+ (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io");
+ log_lldp("Started LLDP client");
return 1;
fail:
- lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
- lldp->fd = safe_close(lldp->fd);
-
+ lldp_reset(lldp);
return r;
}
@@ -267,10 +285,9 @@ _public_ int sd_lldp_stop(sd_lldp *lldp) {
if (lldp->fd < 0)
return 0;
- lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source);
- lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
- lldp->fd = safe_close(lldp->fd);
+ log_lldp("Stopping LLDP client");
+ lldp_reset(lldp);
lldp_flush_neighbors(lldp);
return 1;
@@ -305,6 +322,12 @@ _public_ int sd_lldp_detach_event(sd_lldp *lldp) {
return 0;
}
+_public_ sd_event* sd_lldp_get_event(sd_lldp *lldp) {
+ assert_return(lldp, NULL);
+
+ return lldp->event;
+}
+
_public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) {
assert_return(lldp, -EINVAL);
@@ -314,39 +337,60 @@ _public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *us
return 0;
}
+_public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) {
+ assert_return(lldp, -EINVAL);
+ assert_return(ifindex > 0, -EINVAL);
+ assert_return(lldp->fd < 0, -EBUSY);
+
+ lldp->ifindex = ifindex;
+ return 0;
+}
+
+_public_ sd_lldp* sd_lldp_ref(sd_lldp *lldp) {
+
+ if (!lldp)
+ return NULL;
+
+ assert(lldp->n_ref > 0);
+ lldp->n_ref++;
+
+ return lldp;
+}
+
_public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) {
if (!lldp)
return NULL;
+ assert(lldp->n_ref > 0);
+ lldp->n_ref --;
+
+ if (lldp->n_ref > 0)
+ return NULL;
+
+ lldp_reset(lldp);
+ sd_lldp_detach_event(lldp);
lldp_flush_neighbors(lldp);
hashmap_free(lldp->neighbor_by_id);
prioq_free(lldp->neighbor_by_expiry);
-
- sd_event_source_unref(lldp->io_event_source);
- sd_event_source_unref(lldp->timer_event_source);
- sd_event_unref(lldp->event);
- safe_close(lldp->fd);
-
free(lldp);
return NULL;
}
-_public_ int sd_lldp_new(sd_lldp **ret, int ifindex) {
+_public_ int sd_lldp_new(sd_lldp **ret) {
_cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL;
int r;
assert_return(ret, -EINVAL);
- assert_return(ifindex > 0, -EINVAL);
lldp = new0(sd_lldp, 1);
if (!lldp)
return -ENOMEM;
+ lldp->n_ref = 1;
lldp->fd = -1;
- lldp->ifindex = ifindex;
lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX;
lldp->capability_mask = (uint16_t) -1;
@@ -486,11 +530,10 @@ _public_ int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *
/* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so
* that our own can be filtered out here. */
- if (!addr) {
+ if (addr)
+ lldp->filter_address = *addr;
+ else
zero(lldp->filter_address);
- return 0;
- }
- lldp->filter_address = *addr;
return 0;
}
diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c
index ccb8002173..ea3fe369ce 100644
--- a/src/libsystemd-network/sd-ndisc.c
+++ b/src/libsystemd-network/sd-ndisc.c
@@ -19,165 +19,71 @@
#include <netinet/icmp6.h>
#include <netinet/in.h>
-#include <netinet/ip6.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/ioctl.h>
#include "sd-ndisc.h"
#include "alloc-util.h"
-#include "async.h"
+#include "fd-util.h"
#include "icmp6-util.h"
#include "in-addr-util.h"
-#include "list.h"
+#include "ndisc-internal.h"
+#include "ndisc-router.h"
#include "socket-util.h"
#include "string-util.h"
+#include "util.h"
#define NDISC_ROUTER_SOLICITATION_INTERVAL (4U * USEC_PER_SEC)
-#define NDISC_MAX_ROUTER_SOLICITATIONS 3U
+#define NDISC_MAX_ROUTER_SOLICITATIONS 3U
-enum NDiscState {
- NDISC_STATE_IDLE,
- NDISC_STATE_SOLICITATION_SENT,
- NDISC_STATE_ADVERTISEMENT_LISTEN,
- _NDISC_STATE_MAX,
- _NDISC_STATE_INVALID = -1,
-};
+static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event event, sd_ndisc_router *rt) {
+ assert(ndisc);
-#define IP6_MIN_MTU 1280U
-#define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr))
-#define NDISC_OPT_LEN_UNITS 8U
+ log_ndisc("Invoking callback for '%c'.", event);
-#define ND_RA_FLAG_PREF 0x18
-#define ND_RA_FLAG_PREF_LOW 0x03
-#define ND_RA_FLAG_PREF_MEDIUM 0x0
-#define ND_RA_FLAG_PREF_HIGH 0x1
-#define ND_RA_FLAG_PREF_INVALID 0x2
+ if (!ndisc->callback)
+ return;
-typedef struct NDiscPrefix NDiscPrefix;
-
-struct NDiscPrefix {
- unsigned n_ref;
-
- sd_ndisc *nd;
-
- LIST_FIELDS(NDiscPrefix, prefixes);
-
- uint8_t len;
- usec_t valid_until;
- struct in6_addr addr;
-};
-
-struct sd_ndisc {
- unsigned n_ref;
-
- enum NDiscState state;
- int ifindex;
- int fd;
-
- sd_event *event;
- int event_priority;
-
- struct ether_addr mac_addr;
- uint32_t mtu;
-
- LIST_HEAD(NDiscPrefix, prefixes);
-
- sd_event_source *recv_event_source;
- sd_event_source *timeout_event_source;
-
- unsigned nd_sent;
-
- sd_ndisc_router_callback_t router_callback;
- sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback;
- sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback;
- sd_ndisc_callback_t callback;
- void *userdata;
-};
-
-#define log_ndisc_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__)
-#define log_ndisc(p, fmt, ...) log_ndisc_errno(p, 0, fmt, ##__VA_ARGS__)
-
-static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) {
-
- if (!prefix)
- return NULL;
-
- assert(prefix->n_ref > 0);
- prefix->n_ref--;
-
- if (prefix->n_ref > 0)
- return NULL;
-
- if (prefix->nd)
- LIST_REMOVE(prefixes, prefix->nd->prefixes, prefix);
-
- free(prefix);
-
- return NULL;
-}
-
-static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) {
- NDiscPrefix *prefix;
-
- assert(ret);
-
- prefix = new0(NDiscPrefix, 1);
- if (!prefix)
- return -ENOMEM;
-
- prefix->n_ref = 1;
- LIST_INIT(prefixes, prefix);
- prefix->nd = nd;
-
- *ret = prefix;
- return 0;
+ ndisc->callback(ndisc, event, rt, ndisc->userdata);
}
-int sd_ndisc_set_callback(
+_public_ int sd_ndisc_set_callback(
sd_ndisc *nd,
- sd_ndisc_router_callback_t router_callback,
- sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback,
- sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback,
sd_ndisc_callback_t callback,
void *userdata) {
assert_return(nd, -EINVAL);
- nd->router_callback = router_callback;
- nd->prefix_onlink_callback = prefix_onlink_callback;
- nd->prefix_autonomous_callback = prefix_autonomous_callback;
nd->callback = callback;
nd->userdata = userdata;
return 0;
}
-int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) {
+_public_ int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) {
assert_return(nd, -EINVAL);
assert_return(ifindex > 0, -EINVAL);
+ assert_return(nd->fd < 0, -EBUSY);
nd->ifindex = ifindex;
return 0;
}
-int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) {
+_public_ int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) {
assert_return(nd, -EINVAL);
if (mac_addr)
- memcpy(&nd->mac_addr, mac_addr, sizeof(nd->mac_addr));
+ nd->mac_addr = *mac_addr;
else
zero(nd->mac_addr);
return 0;
-
}
-int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) {
+_public_ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) {
int r;
assert_return(nd, -EINVAL);
+ assert_return(nd->fd < 0, -EBUSY);
assert_return(!nd->event, -EBUSY);
if (event)
@@ -193,21 +99,22 @@ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) {
return 0;
}
-int sd_ndisc_detach_event(sd_ndisc *nd) {
+_public_ int sd_ndisc_detach_event(sd_ndisc *nd) {
+
assert_return(nd, -EINVAL);
+ assert_return(nd->fd < 0, -EBUSY);
nd->event = sd_event_unref(nd->event);
-
return 0;
}
-sd_event *sd_ndisc_get_event(sd_ndisc *nd) {
+_public_ sd_event *sd_ndisc_get_event(sd_ndisc *nd) {
assert_return(nd, NULL);
return nd->event;
}
-sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) {
+_public_ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) {
if (!nd)
return NULL;
@@ -221,15 +128,14 @@ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) {
static int ndisc_reset(sd_ndisc *nd) {
assert(nd);
- nd->recv_event_source = sd_event_source_unref(nd->recv_event_source);
- nd->fd = asynchronous_close(nd->fd);
nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source);
+ nd->recv_event_source = sd_event_source_unref(nd->recv_event_source);
+ nd->fd = safe_close(nd->fd);
return 0;
}
-sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) {
- NDiscPrefix *prefix, *p;
+_public_ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) {
if (!nd)
return NULL;
@@ -242,16 +148,12 @@ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) {
ndisc_reset(nd);
sd_ndisc_detach_event(nd);
-
- LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes)
- prefix = ndisc_prefix_unref(prefix);
-
free(nd);
return NULL;
}
-int sd_ndisc_new(sd_ndisc **ret) {
+_public_ int sd_ndisc_new(sd_ndisc **ret) {
_cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
assert_return(ret, -EINVAL);
@@ -261,223 +163,70 @@ int sd_ndisc_new(sd_ndisc **ret) {
return -ENOMEM;
nd->n_ref = 1;
- nd->ifindex = -1;
nd->fd = -1;
- LIST_HEAD_INIT(nd->prefixes);
-
*ret = nd;
nd = NULL;
return 0;
}
-int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) {
+_public_ int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) {
assert_return(nd, -EINVAL);
assert_return(mtu, -EINVAL);
if (nd->mtu == 0)
- return -ENOMSG;
+ return -ENODATA;
*mtu = nd->mtu;
return 0;
}
-static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
- const struct in6_addr *addr,
- uint8_t addr_prefixlen) {
- uint8_t bytes, mask, len;
-
- assert(prefix);
- assert(addr);
-
- len = MIN(prefixlen, addr_prefixlen);
-
- bytes = len / 8;
- mask = 0xff << (8 - len % 8);
+_public_ int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret) {
+ assert_return(nd, -EINVAL);
+ assert_return(ret, -EINVAL);
- if (memcmp(prefix, addr, bytes) != 0 ||
- (prefix->s6_addr[bytes] & mask) != (addr->s6_addr[bytes] & mask))
- return -EADDRNOTAVAIL;
+ if (nd->hop_limit == 0)
+ return -ENODATA;
+ *ret = nd->hop_limit;
return 0;
}
-static int ndisc_prefix_match(sd_ndisc *nd, const struct in6_addr *addr,
- uint8_t addr_len, NDiscPrefix **result) {
- NDiscPrefix *prefix, *p;
- usec_t time_now;
- int r;
-
- assert(nd);
-
- r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
- if (r < 0)
- return r;
-
- LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
- if (prefix->valid_until < time_now) {
- prefix = ndisc_prefix_unref(prefix);
- continue;
- }
-
- if (prefix_match(&prefix->addr, prefix->len, addr, addr_len) >= 0) {
- *result = prefix;
- return 0;
- }
- }
-
- return -EADDRNOTAVAIL;
-}
-
-static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
- const struct nd_opt_prefix_info *prefix_opt) {
- NDiscPrefix *prefix;
- uint32_t lifetime_valid, lifetime_preferred;
- usec_t time_now;
- char time_string[FORMAT_TIMESPAN_MAX];
+static int ndisc_handle_datagram(sd_ndisc *nd, sd_ndisc_router *rt) {
int r;
assert(nd);
- assert(prefix_opt);
+ assert(rt);
- if (len < prefix_opt->nd_opt_pi_len)
- return -EBADMSG;
-
- if (!(prefix_opt->nd_opt_pi_flags_reserved & (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO)))
+ r = ndisc_router_parse(rt);
+ if (r == -EBADMSG) /* Bad packet */
return 0;
-
- if (in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &prefix_opt->nd_opt_pi_prefix) > 0)
- return 0;
-
- lifetime_valid = be32toh(prefix_opt->nd_opt_pi_valid_time);
- lifetime_preferred = be32toh(prefix_opt->nd_opt_pi_preferred_time);
-
- if (lifetime_valid < lifetime_preferred)
- return 0;
-
- r = ndisc_prefix_match(nd, &prefix_opt->nd_opt_pi_prefix,
- prefix_opt->nd_opt_pi_prefix_len, &prefix);
- if (r < 0) {
- if (r != -EADDRNOTAVAIL)
- return r;
-
- /* if router advertisement prefix valid timeout is zero, the timeout
- callback will be called immediately to clean up the prefix */
-
- r = ndisc_prefix_new(nd, &prefix);
- if (r < 0)
- return r;
-
- prefix->len = prefix_opt->nd_opt_pi_prefix_len;
-
- memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix,
- sizeof(prefix->addr));
-
- log_ndisc(nd, "New prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
- SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr),
- prefix->len, lifetime_valid,
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC));
-
- LIST_PREPEND(prefixes, nd->prefixes, prefix);
-
- } else {
- if (prefix->len != prefix_opt->nd_opt_pi_prefix_len) {
- uint8_t prefixlen;
-
- prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len);
-
- log_ndisc(nd, "Prefix length mismatch %d/%d using %d",
- prefix->len,
- prefix_opt->nd_opt_pi_prefix_len,
- prefixlen);
-
- prefix->len = prefixlen;
- }
-
- log_ndisc(nd, "Update prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
- SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr),
- prefix->len, lifetime_valid,
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC));
- }
-
- r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
- return r;
-
- prefix->valid_until = time_now + lifetime_valid * USEC_PER_SEC;
-
- if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && nd->prefix_onlink_callback)
- nd->prefix_onlink_callback(nd, &prefix->addr, prefix->len, prefix->valid_until, nd->userdata);
-
- if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && nd->prefix_autonomous_callback)
- nd->prefix_autonomous_callback(nd, &prefix->addr, prefix->len, lifetime_preferred, lifetime_valid,
- nd->userdata);
-
- return 0;
-}
-
-static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, size_t len) {
- struct nd_opt_hdr *opt_hdr;
- void *opt;
-
- assert(nd);
- assert(ra);
-
- if (len < sizeof(struct nd_router_advert) + NDISC_OPT_LEN_UNITS) {
- log_ndisc(nd, "Router Advertisement below minimum length");
- return -EBADMSG;
- }
-
- len -= sizeof(struct nd_router_advert);
- opt = ra + 1;
- opt_hdr = opt;
-
- while (len != 0 && len >= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS) {
- struct nd_opt_mtu *opt_mtu;
- struct nd_opt_prefix_info *opt_prefix;
- uint32_t mtu;
-
- if (opt_hdr->nd_opt_len == 0)
- return -EBADMSG;
-
- switch (opt_hdr->nd_opt_type) {
-
- case ND_OPT_MTU:
- opt_mtu = opt;
-
- mtu = be32toh(opt_mtu->nd_opt_mtu_mtu);
-
- if (mtu != nd->mtu) {
- nd->mtu = MAX(mtu, IP6_MIN_MTU);
- log_ndisc(nd, "Router Advertisement link MTU %d using %d", mtu, nd->mtu);
- }
-
- break;
-
- case ND_OPT_PREFIX_INFORMATION:
- opt_prefix = opt;
- ndisc_prefix_update(nd, len, opt_prefix);
- break;
- }
+ return 0;
- len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS;
- opt = (void*) ((uint8_t*) opt + opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS);
- opt_hdr = opt;
- }
+ /* Update global variables we keep */
+ if (rt->mtu > 0)
+ nd->mtu = rt->mtu;
+ if (rt->hop_limit > 0)
+ nd->hop_limit = rt->hop_limit;
- if (len > 0)
- log_ndisc(nd, "Router Advertisement contains %zd bytes of trailing garbage", len);
+ log_ndisc("Received Router Advertisement: flags %s preference %s lifetime %" PRIu16 " sec",
+ rt->flags & ND_RA_FLAG_MANAGED ? "MANAGED" : rt->flags & ND_RA_FLAG_OTHER ? "OTHER" : "none",
+ rt->preference == SD_NDISC_PREFERENCE_HIGH ? "high" : rt->preference == SD_NDISC_PREFERENCE_LOW ? "low" : "medium",
+ rt->lifetime);
+ ndisc_callback(nd, SD_NDISC_EVENT_ROUTER, rt);
return 0;
}
-static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- _cleanup_free_ struct nd_router_advert *ra = NULL;
+static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ _cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = NULL;
sd_ndisc *nd = userdata;
union {
struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_LEN(sizeof(int))];
+ uint8_t buf[CMSG_SPACE(sizeof(int)) + /* ttl */
+ CMSG_SPACE(sizeof(struct timeval))];
} control = {};
struct iovec iov = {};
union sockaddr_union sa = {};
@@ -490,10 +239,7 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t
.msg_controllen = sizeof(control),
};
struct cmsghdr *cmsg;
- struct in6_addr *gw;
- unsigned lifetime;
ssize_t len, buflen;
- int r, pref, stateful;
assert(s);
assert(nd);
@@ -501,35 +247,47 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t
buflen = next_datagram_size_fd(fd);
if (buflen < 0)
- return buflen;
-
- iov.iov_len = buflen;
+ return log_ndisc_errno(buflen, "Failed to determine datagram size to read: %m");
- ra = malloc(iov.iov_len);
- if (!ra)
+ rt = ndisc_router_new(buflen);
+ if (!rt)
return -ENOMEM;
- iov.iov_base = ra;
+ iov.iov_base = NDISC_ROUTER_RAW(rt);
+ iov.iov_len = rt->raw_size;
- len = recvmsg(fd, &msg, 0);
+ len = recvmsg(fd, &msg, MSG_DONTWAIT);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
- return log_ndisc_errno(nd, errno, "Could not receive message from ICMPv6 socket: %m");
+ return log_ndisc_errno(errno, "Could not receive message from ICMPv6 socket: %m");
}
- if ((size_t) len < sizeof(struct nd_router_advert)) {
- log_ndisc(nd, "Too small to be a router advertisement: ignoring");
- return 0;
+
+ if ((size_t) len != rt->raw_size) {
+ log_ndisc("Packet size mismatch.");
+ return -EINVAL;
}
- if (msg.msg_namelen == 0)
- gw = NULL; /* only happens when running the test-suite over a socketpair */
- else if (msg.msg_namelen != sizeof(sa.in6)) {
- log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)msg.msg_namelen);
- return 0;
- } else
- gw = &sa.in6.sin6_addr;
+ if (msg.msg_namelen == sizeof(struct sockaddr_in6) &&
+ sa.in6.sin6_family == AF_INET6) {
+
+ if (in_addr_is_link_local(AF_INET6, (union in_addr_union*) &sa.in6.sin6_addr) <= 0) {
+ _cleanup_free_ char *addr = NULL;
+
+ (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &sa.in6.sin6_addr, &addr);
+ log_ndisc("Received RA from non-link-local address %s. Ignoring.", strna(addr));
+ return 0;
+ }
+
+ rt->address = sa.in6.sin6_addr;
+
+ } else if (msg.msg_namelen > 0) {
+ log_ndisc("Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t) msg.msg_namelen);
+ return -EINVAL;
+ }
+
+ /* namelen == 0 only happens when running the test-suite over a socketpair */
assert(!(msg.msg_flags & MSG_CTRUNC));
assert(!(msg.msg_flags & MSG_TRUNC));
@@ -538,61 +296,29 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t
if (cmsg->cmsg_level == SOL_IPV6 &&
cmsg->cmsg_type == IPV6_HOPLIMIT &&
cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
- int hops = *(int*)CMSG_DATA(cmsg);
+ int hops = *(int*) CMSG_DATA(cmsg);
if (hops != 255) {
- log_ndisc(nd, "Received RA with invalid hop limit %d. Ignoring.", hops);
+ log_ndisc("Received RA with invalid hop limit %d. Ignoring.", hops);
return 0;
}
-
- break;
}
- }
- if (gw && !in_addr_is_link_local(AF_INET6, (const union in_addr_union*) gw)) {
- _cleanup_free_ char *addr = NULL;
-
- (void)in_addr_to_string(AF_INET6, (const union in_addr_union*) gw, &addr);
-
- log_ndisc(nd, "Received RA from non-link-local address %s. Ignoring.", strna(addr));
- return 0;
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SO_TIMESTAMP &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
+ triple_timestamp_from_realtime(&rt->timestamp, timeval_load(CMSG_DATA(cmsg)));
}
- if (ra->nd_ra_type != ND_ROUTER_ADVERT)
- return 0;
-
- if (ra->nd_ra_code != 0)
- return 0;
+ if (!triple_timestamp_is_set(&rt->timestamp))
+ triple_timestamp_get(&rt->timestamp);
nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source);
- nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN;
-
- stateful = ra->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER);
- pref = (ra->nd_ra_flags_reserved & ND_RA_FLAG_PREF) >> 3;
-
- if (!IN_SET(pref, ND_RA_FLAG_PREF_LOW, ND_RA_FLAG_PREF_HIGH))
- pref = ND_RA_FLAG_PREF_MEDIUM;
-
- lifetime = be16toh(ra->nd_ra_router_lifetime);
-
- log_ndisc(nd, "Received Router Advertisement: flags %s preference %s lifetime %u sec",
- stateful & ND_RA_FLAG_MANAGED ? "MANAGED" : stateful & ND_RA_FLAG_OTHER ? "OTHER" : "none",
- pref == ND_RA_FLAG_PREF_HIGH ? "high" : pref == ND_RA_FLAG_PREF_LOW ? "low" : "medium",
- lifetime);
- r = ndisc_ra_parse(nd, ra, (size_t) len);
- if (r < 0) {
- log_ndisc_errno(nd, r, "Could not parse Router Advertisement: %m");
- return 0;
- }
-
- if (nd->router_callback)
- nd->router_callback(nd, stateful, gw, lifetime, pref, nd->userdata);
-
- return 0;
+ return ndisc_handle_datagram(nd, rt);
}
-static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+static int ndisc_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
sd_ndisc *nd = userdata;
usec_t time_now, next_timeout;
int r;
@@ -601,43 +327,34 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
assert(nd);
assert(nd->event);
- nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source);
-
if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) {
- if (nd->callback)
- nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata);
- nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN;
- } else {
- r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr);
- if (r < 0) {
- log_ndisc_errno(nd, r, "Error sending Router Solicitation: %m");
- goto fail;
- } else {
- nd->state = NDISC_STATE_SOLICITATION_SENT;
- log_ndisc(nd, "Sent Router Solicitation");
- }
-
- nd->nd_sent++;
+ nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source);
+ ndisc_callback(nd, SD_NDISC_EVENT_TIMEOUT, NULL);
+ return 0;
+ }
- assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+ r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr);
+ if (r < 0) {
+ log_ndisc_errno(r, "Error sending Router Solicitation: %m");
+ goto fail;
+ }
- next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL;
+ log_ndisc("Sent Router Solicitation");
+ nd->nd_sent++;
- r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(),
- next_timeout, 0,
- ndisc_router_solicitation_timeout, nd);
- if (r < 0) {
- log_ndisc_errno(nd, r, "Failed to allocate timer event: %m");
- goto fail;
- }
+ assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+ next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL;
- r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority);
- if (r < 0) {
- log_ndisc_errno(nd, r, "Cannot set timer priority: %m");
- goto fail;
- }
+ r = sd_event_source_set_time(nd->timeout_event_source, next_timeout);
+ if (r < 0) {
+ log_ndisc_errno(r, "Error updating timer: %m");
+ goto fail;
+ }
- (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout");
+ r = sd_event_source_set_enabled(nd->timeout_event_source, SD_EVENT_ONESHOT);
+ if (r < 0) {
+ log_ndisc_errno(r, "Error reenabling timer: %m");
+ goto fail;
}
return 0;
@@ -647,38 +364,36 @@ fail:
return 0;
}
-int sd_ndisc_stop(sd_ndisc *nd) {
+_public_ int sd_ndisc_stop(sd_ndisc *nd) {
assert_return(nd, -EINVAL);
- if (nd->state == NDISC_STATE_IDLE)
+ if (nd->fd < 0)
return 0;
- log_ndisc(nd, "Stopping IPv6 Router Solicitation client");
+ log_ndisc("Stopping IPv6 Router Solicitation client");
ndisc_reset(nd);
- nd->state = NDISC_STATE_IDLE;
-
- if (nd->callback)
- nd->callback(nd, SD_NDISC_EVENT_STOP, nd->userdata);
-
- return 0;
+ return 1;
}
-int sd_ndisc_router_discovery_start(sd_ndisc *nd) {
+_public_ int sd_ndisc_start(sd_ndisc *nd) {
int r;
assert_return(nd, -EINVAL);
assert_return(nd->event, -EINVAL);
assert_return(nd->ifindex > 0, -EINVAL);
- assert_return(nd->state == NDISC_STATE_IDLE, -EBUSY);
- r = icmp6_bind_router_solicitation(nd->ifindex);
- if (r < 0)
- return r;
+ if (nd->fd >= 0)
+ return 0;
- nd->fd = r;
+ assert(!nd->recv_event_source);
+ assert(!nd->timeout_event_source);
- r = sd_event_add_io(nd->event, &nd->recv_event_source, nd->fd, EPOLLIN, ndisc_router_advertisement_recv, nd);
+ nd->fd = icmp6_bind_router_solicitation(nd->ifindex);
+ if (nd->fd < 0)
+ return nd->fd;
+
+ r = sd_event_add_io(nd->event, &nd->recv_event_source, nd->fd, EPOLLIN, ndisc_recv, nd);
if (r < 0)
goto fail;
@@ -688,7 +403,7 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) {
(void) sd_event_source_set_description(nd->recv_event_source, "ndisc-receive-message");
- r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), 0, 0, ndisc_router_solicitation_timeout, nd);
+ r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), 0, 0, ndisc_timeout, nd);
if (r < 0)
goto fail;
@@ -698,8 +413,8 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) {
(void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout");
- log_ndisc(ns, "Started IPv6 Router Solicitation client");
- return 0;
+ log_ndisc("Started IPv6 Router Solicitation client");
+ return 1;
fail:
ndisc_reset(nd);
diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c
index 1aae2253c0..6bcd65de0a 100644
--- a/src/libsystemd-network/test-lldp.c
+++ b/src/libsystemd-network/test-lldp.c
@@ -54,11 +54,11 @@ static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n
static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) {
int r;
- r = sd_lldp_new(lldp, 42);
+ r = sd_lldp_new(lldp);
if (r < 0)
return r;
- r = sd_lldp_attach_event(*lldp, e, 0);
+ r = sd_lldp_set_ifindex(*lldp, 42);
if (r < 0)
return r;
@@ -66,6 +66,10 @@ static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *
if (r < 0)
return r;
+ r = sd_lldp_attach_event(*lldp, e, 0);
+ if (r < 0)
+ return r;
+
r = sd_lldp_start(*lldp);
if (r < 0)
return r;
diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c
index 4817c968ac..d9669488be 100644
--- a/src/libsystemd-network/test-ndisc-rs.c
+++ b/src/libsystemd-network/test-ndisc-rs.c
@@ -18,11 +18,15 @@
***/
#include <netinet/icmp6.h>
+#include <arpa/inet.h>
#include "sd-ndisc.h"
+#include "alloc-util.h"
+#include "hexdecoct.h"
#include "icmp6-util.h"
#include "socket-util.h"
+#include "strv.h"
static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
@@ -35,6 +39,144 @@ static int test_fd[2];
typedef int (*send_ra_t)(uint8_t flags);
static send_ra_t send_ra_function;
+static void router_dump(sd_ndisc_router *rt) {
+ struct in6_addr addr;
+ char buf[FORMAT_TIMESTAMP_MAX];
+ uint8_t hop_limit;
+ uint64_t t, flags;
+ uint32_t mtu;
+ uint16_t lifetime;
+ unsigned preference;
+ int r;
+
+ assert_se(rt);
+
+ log_info("--");
+ assert_se(sd_ndisc_router_get_address(rt, &addr) == -ENODATA);
+
+ assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
+ log_info("Timestamp: %s", format_timestamp(buf, sizeof(buf), t));
+
+ assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
+ log_info("Monotonic: %" PRIu64, t);
+
+ if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0)
+ log_info("No hop limit set");
+ else
+ log_info("Hop limit: %u", hop_limit);
+
+ assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
+ log_info("Flags: <%s|%s>",
+ flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
+ flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
+
+ assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0);
+ log_info("Preference: %s",
+ preference == SD_NDISC_PREFERENCE_LOW ? "low" :
+ preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium");
+
+ assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0);
+ log_info("Lifetime: %" PRIu16, lifetime);
+
+ if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
+ log_info("No MTU set");
+ else
+ log_info("MTU: %" PRIu32, mtu);
+
+ r = sd_ndisc_router_option_rewind(rt);
+ for (;;) {
+ uint8_t type;
+
+ assert_se(r >= 0);
+
+ if (r == 0)
+ break;
+
+ assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
+
+ log_info(">> Option %u", type);
+
+ switch (type) {
+
+ case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
+ case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
+ _cleanup_free_ char *c = NULL;
+ const void *p;
+ size_t n;
+
+ assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
+ assert_se(n > 2);
+ assert_se(c = hexmem((uint8_t*) p + 2, n - 2));
+
+ log_info("Address: %s", c);
+ break;
+ }
+
+ case SD_NDISC_OPTION_PREFIX_INFORMATION: {
+ uint32_t lifetime_valid, lifetime_preferred;
+ unsigned prefix_len;
+ uint8_t pfl;
+ struct in6_addr a;
+ char buff[INET6_ADDRSTRLEN];
+
+ assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid) >= 0);
+ log_info("Valid Lifetime: %" PRIu32, lifetime_valid);
+
+ assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred) >= 0);
+ log_info("Preferred Lifetime: %" PRIu32, lifetime_preferred);
+
+ assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
+ log_info("Flags: <%s|%s>",
+ pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
+ pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
+
+ assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
+ log_info("Prefix Length: %u", prefix_len);
+
+ assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
+ log_info("Prefix: %s", inet_ntop(AF_INET6, &a, buff, sizeof(buff)));
+
+ break;
+ }
+
+ case SD_NDISC_OPTION_RDNSS: {
+ const struct in6_addr *a;
+ uint32_t lt;
+ int n, i;
+
+ n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
+ assert_se(n > 0);
+
+ for (i = 0; i < n; i++) {
+ char buff[INET6_ADDRSTRLEN];
+ log_info("DNS: %s", inet_ntop(AF_INET6, a + i, buff, sizeof(buff)));
+ }
+
+ assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lt) >= 0);
+ log_info("Lifetime: %" PRIu32, lt);
+ break;
+ }
+
+ case SD_NDISC_OPTION_DNSSL: {
+ _cleanup_strv_free_ char **l = NULL;
+ uint32_t lt;
+ int n, i;
+
+ n = sd_ndisc_router_dnssl_get_domains(rt, &l);
+ assert_se(n > 0);
+
+ for (i = 0; i < n; i++)
+ log_info("Domain: %s", l[i]);
+
+ assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lt) >= 0);
+ log_info("Lifetime: %" PRIu32, lt);
+ break;
+ }}
+
+ r = sd_ndisc_router_option_next(rt);
+ }
+}
+
static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
void *userdata) {
assert_se(false);
@@ -83,32 +225,39 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
return send_ra_function(0);
}
-static void test_rs_done(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) {
+static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
sd_event *e = userdata;
static unsigned idx = 0;
- uint8_t flags_array[] = {
+ uint64_t flags_array[] = {
0,
0,
0,
ND_RA_FLAG_OTHER,
ND_RA_FLAG_MANAGED
};
+ uint64_t flags;
uint32_t mtu;
assert_se(nd);
+ if (event != SD_NDISC_EVENT_ROUTER)
+ return;
+
+ router_dump(rt);
+
+ assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
assert_se(flags == flags_array[idx]);
idx++;
if (verbose)
- printf(" got event 0x%02x\n", flags);
+ printf(" got event 0x%02" PRIx64 "\n", flags);
if (idx < ELEMENTSOF(flags_array)) {
send_ra(flags_array[idx]);
return;
}
- assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENOMSG);
+ assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENODATA);
sd_event_exit(e, 0);
}
@@ -132,17 +281,17 @@ static void test_rs(void) {
assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
- assert_se(sd_ndisc_set_callback(nd, test_rs_done, NULL, NULL, NULL, e) >= 0);
+ assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
time_now + 2 *USEC_PER_SEC, 0,
test_rs_hangcheck, NULL) >= 0);
assert_se(sd_ndisc_stop(nd) >= 0);
- assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
+ assert_se(sd_ndisc_start(nd) >= 0);
assert_se(sd_ndisc_stop(nd) >= 0);
- assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
+ assert_se(sd_ndisc_start(nd) >= 0);
sd_event_loop(e);
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 7ba6527f63..f364b54b50 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -216,8 +216,7 @@ struct sd_event {
pid_t original_pid;
unsigned iteration;
- dual_timestamp timestamp;
- usec_t timestamp_boottime;
+ triple_timestamp timestamp;
int state;
bool exit_requested:1;
@@ -1072,16 +1071,16 @@ _public_ int sd_event_add_time(
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
- if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) &&
- !clock_boottime_supported())
+ if (!clock_supported(clock)) /* Checks whether the kernel supports the clock */
+ return -EOPNOTSUPP;
+
+ type = clock_to_event_source_type(clock); /* checks whether sd-event supports this clock */
+ if (type < 0)
return -EOPNOTSUPP;
if (!callback)
callback = time_exit_callback;
- type = clock_to_event_source_type(clock);
- assert_return(type >= 0, -EOPNOTSUPP);
-
d = event_get_clock_data(e, type);
assert(d);
@@ -2530,9 +2529,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
goto finish;
}
- dual_timestamp_get(&e->timestamp);
- if (clock_boottime_supported())
- e->timestamp_boottime = now(CLOCK_BOOTTIME);
+ triple_timestamp_get(&e->timestamp);
for (i = 0; i < m; i++) {
@@ -2573,7 +2570,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
if (r < 0)
goto finish;
- r = process_timer(e, e->timestamp_boottime, &e->boottime);
+ r = process_timer(e, e->timestamp.boottime, &e->boottime);
if (r < 0)
goto finish;
@@ -2585,7 +2582,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
if (r < 0)
goto finish;
- r = process_timer(e, e->timestamp_boottime, &e->boottime_alarm);
+ r = process_timer(e, e->timestamp.boottime, &e->boottime_alarm);
if (r < 0)
goto finish;
@@ -2759,43 +2756,24 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) {
assert_return(e, -EINVAL);
assert_return(usec, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
- assert_return(IN_SET(clock,
- CLOCK_REALTIME,
- CLOCK_REALTIME_ALARM,
- CLOCK_MONOTONIC,
- CLOCK_BOOTTIME,
- CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP);
+ if (!TRIPLE_TIMESTAMP_HAS_CLOCK(clock))
+ return -EOPNOTSUPP;
+
+ /* Generate a clean error in case CLOCK_BOOTTIME is not available. Note that don't use clock_supported() here,
+ * for a reason: there are systems where CLOCK_BOOTTIME is supported, but CLOCK_BOOTTIME_ALARM is not, but for
+ * the purpose of getting the time this doesn't matter. */
if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported())
return -EOPNOTSUPP;
- if (!dual_timestamp_is_set(&e->timestamp)) {
+ if (!triple_timestamp_is_set(&e->timestamp)) {
/* Implicitly fall back to now() if we never ran
* before and thus have no cached time. */
*usec = now(clock);
return 1;
}
- switch (clock) {
-
- case CLOCK_REALTIME:
- case CLOCK_REALTIME_ALARM:
- *usec = e->timestamp.realtime;
- break;
-
- case CLOCK_MONOTONIC:
- *usec = e->timestamp.monotonic;
- break;
-
- case CLOCK_BOOTTIME:
- case CLOCK_BOOTTIME_ALARM:
- *usec = e->timestamp_boottime;
- break;
-
- default:
- assert_not_reached("Unknown clock?");
- }
-
+ *usec = triple_timestamp_by_clock(&e->timestamp, clock);
return 0;
}
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 86d8dee867..df3b3c922e 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -120,7 +120,9 @@ sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m) {
}
sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
- if (m && REFCNT_DEC(m->n_ref) == 0) {
+ sd_netlink_message *t;
+
+ while (m && REFCNT_DEC(m->n_ref) == 0) {
unsigned i;
free(m->hdr);
@@ -128,9 +130,9 @@ sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
for (i = 0; i <= m->n_containers; i++)
free(m->containers[i].attributes);
- sd_netlink_message_unref(m->next);
-
- free(m);
+ t = m;
+ m = m->next;
+ free(t);
}
return NULL;
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index 91701405a5..43114eb825 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -144,7 +144,10 @@ int sd_netlink_open(sd_netlink **ret) {
return 0;
}
-int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size) {
+int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
+ assert_return(rtnl, -EINVAL);
+ assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
+
return fd_inc_rcvbuf(rtnl->fd, size);
}
diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index 9a8089f97c..8ef48dbaa1 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -85,7 +85,7 @@ int manager_handle_action(
}
/* If the key handling is inhibited, don't do anything */
- if (inhibit_key > 0) {
+ if (!ignore_inhibited && inhibit_key > 0) {
if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0, NULL)) {
log_debug("Refusing operation, %s is inhibited.", inhibit_what_to_string(inhibit_key));
return 0;
@@ -124,7 +124,7 @@ int manager_handle_action(
return -EALREADY;
}
- inhibit_operation = handle == HANDLE_SUSPEND || handle == HANDLE_HIBERNATE || handle == HANDLE_HYBRID_SLEEP ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN;
+ inhibit_operation = IN_SET(handle, HANDLE_SUSPEND, HANDLE_HIBERNATE, HANDLE_HYBRID_SLEEP) ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN;
/* If the actual operation is inhibited, warn and fail */
if (!ignore_inhibited &&
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 8e4ffa9a39..afe5026373 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -2720,6 +2720,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "terminate", 2, VERB_ANY, 0, terminate_machine },
{ "reboot", 2, VERB_ANY, 0, reboot_machine },
{ "poweroff", 2, VERB_ANY, 0, poweroff_machine },
+ { "stop", 2, VERB_ANY, 0, poweroff_machine }, /* Convenience alias */
{ "kill", 2, VERB_ANY, 0, kill_machine },
{ "login", VERB_ANY, 2, 0, login_machine },
{ "shell", VERB_ANY, VERB_ANY, 0, shell_machine },
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 367c340e08..5498e352d8 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -32,6 +32,9 @@
#include "utf8.h"
#include "util.h"
+#define ADDRESSES_PER_LINK_MAX 2048U
+#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
+
int address_new(Address **ret) {
_cleanup_address_free_ Address *address = NULL;
@@ -54,6 +57,9 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
_cleanup_address_free_ Address *address = NULL;
int r;
+ assert(network);
+ assert(ret);
+
if (section) {
address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
if (address) {
@@ -64,18 +70,21 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
}
}
+ if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX)
+ return -E2BIG;
+
r = address_new(&address);
if (r < 0)
return r;
if (section) {
address->section = section;
- hashmap_put(network->addresses_by_section,
- UINT_TO_PTR(address->section), address);
+ hashmap_put(network->addresses_by_section, UINT_TO_PTR(address->section), address);
}
address->network = network;
LIST_APPEND(addresses, network->static_addresses, address);
+ network->n_static_addresses++;
*ret = address;
address = NULL;
@@ -89,10 +98,11 @@ void address_free(Address *address) {
if (address->network) {
LIST_REMOVE(addresses, address->network->static_addresses, address);
+ assert(address->network->n_static_addresses > 0);
+ address->network->n_static_addresses--;
if (address->section)
- hashmap_remove(address->network->addresses_by_section,
- UINT_TO_PTR(address->section));
+ hashmap_remove(address->network->addresses_by_section, UINT_TO_PTR(address->section));
}
if (address->link) {
@@ -328,7 +338,12 @@ static int address_release(Address *address) {
return 0;
}
-int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) {
+int address_update(
+ Address *address,
+ unsigned char flags,
+ unsigned char scope,
+ const struct ifa_cacheinfo *cinfo) {
+
bool ready;
int r;
@@ -383,31 +398,38 @@ int address_drop(Address *address) {
return 0;
}
-int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
- Address address = {}, *existing;
+int address_get(Link *link,
+ int family,
+ const union in_addr_union *in_addr,
+ unsigned char prefixlen,
+ Address **ret) {
+
+ Address address, *existing;
assert(link);
assert(in_addr);
- assert(ret);
- address.family = family;
- address.in_addr = *in_addr;
- address.prefixlen = prefixlen;
+ address = (Address) {
+ .family = family,
+ .in_addr = *in_addr,
+ .prefixlen = prefixlen,
+ };
existing = set_get(link->addresses, &address);
if (existing) {
- *ret = existing;
-
+ if (ret)
+ *ret = existing;
return 1;
- } else {
- existing = set_get(link->addresses_foreign, &address);
- if (!existing)
- return -ENOENT;
}
- *ret = existing;
+ existing = set_get(link->addresses_foreign, &address);
+ if (existing) {
+ if (ret)
+ *ret = existing;
+ return 0;
+ }
- return 0;
+ return -ENOENT;
}
int address_remove(
@@ -509,7 +531,12 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
return 0;
}
-int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) {
+int address_configure(
+ Address *address,
+ Link *link,
+ sd_netlink_message_handler_t callback,
+ bool update) {
+
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@@ -520,6 +547,11 @@ int address_configure(Address *address, Link *link, sd_netlink_message_handler_t
assert(link->manager);
assert(link->manager->rtnl);
+ /* If this is a new address, then refuse adding more than the limit */
+ if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
+ set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
+ return -E2BIG;
+
r = address_acquire(link, address, &address);
if (r < 0)
return r;
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 784ab18b27..03c4bea7c6 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -63,7 +63,7 @@ void address_free(Address *address);
int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
-int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo);
+int address_update(Address *address, unsigned char flags, unsigned char scope, const struct ifa_cacheinfo *cinfo);
int address_drop(Address *address);
int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update);
int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback);
diff --git a/src/network/networkd-brvlan.c b/src/network/networkd-brvlan.c
new file mode 100644
index 0000000000..f621b8011b
--- /dev/null
+++ b/src/network/networkd-brvlan.c
@@ -0,0 +1,329 @@
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2016 BISDN GmbH. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/in.h>
+#include <linux/if_bridge.h>
+#include <stdbool.h>
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "netlink-util.h"
+#include "networkd-brvlan.h"
+#include "networkd.h"
+#include "parse-util.h"
+#include "vlan-util.h"
+
+static bool is_bit_set(unsigned bit, uint32_t scope) {
+ assert(bit < sizeof(scope)*8);
+ return scope & (1 << bit);
+}
+
+static inline void set_bit(unsigned nr, uint32_t *addr) {
+ if (nr < BRIDGE_VLAN_BITMAP_MAX)
+ addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
+}
+
+static int find_next_bit(int i, uint32_t x) {
+ int j;
+
+ if (i >= 32)
+ return -1;
+
+ /* find first bit */
+ if (i < 0)
+ return BUILTIN_FFS_U32(x);
+
+ /* mask off prior finds to get next */
+ j = __builtin_ffs(x >> i);
+ return j ? j + i : 0;
+}
+
+static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint16_t pvid, const uint32_t *br_vid_bitmap, const uint32_t *br_untagged_bitmap) {
+ struct bridge_vlan_info br_vlan;
+ int i, j, k, r, done, cnt;
+ uint16_t begin, end;
+ bool untagged;
+
+ assert(link);
+ assert(req);
+ assert(br_vid_bitmap);
+ assert(br_untagged_bitmap);
+
+ i = cnt = -1;
+
+ begin = end = UINT16_MAX;
+ for (k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) {
+ unsigned base_bit;
+ uint32_t vid_map = br_vid_bitmap[k];
+ uint32_t untagged_map = br_untagged_bitmap[k];
+
+ base_bit = k * 32;
+ i = -1;
+ done = 0;
+ do {
+ j = find_next_bit(i, vid_map);
+ if (j > 0) {
+ /* first hit of any bit */
+ if (begin == UINT16_MAX && end == UINT16_MAX) {
+ begin = end = j - 1 + base_bit;
+ untagged = is_bit_set(j - 1, untagged_map);
+ goto next;
+ }
+
+ /* this bit is a continuation of prior bits */
+ if (j - 2 + base_bit == end && untagged == is_bit_set(j - 1, untagged_map) && (uint16_t)j - 1 + base_bit != pvid && (uint16_t)begin != pvid) {
+ end++;
+ goto next;
+ }
+ } else
+ done = 1;
+
+ if (begin != UINT16_MAX) {
+ cnt++;
+ if (done && k < BRIDGE_VLAN_BITMAP_LEN - 1)
+ break;
+
+ br_vlan.flags = 0;
+ if (untagged)
+ br_vlan.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+
+ if (begin == end) {
+ br_vlan.vid = begin;
+
+ if (begin == pvid)
+ br_vlan.flags |= BRIDGE_VLAN_INFO_PVID;
+
+ r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
+ } else {
+ br_vlan.vid = begin;
+ br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
+
+ r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
+
+ br_vlan.vid = end;
+ br_vlan.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_END;
+
+ r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
+ }
+
+ if (done)
+ break;
+ }
+ if (j > 0) {
+ begin = end = j - 1 + base_bit;
+ untagged = is_bit_set(j - 1, untagged_map);
+ }
+
+ next:
+ i = j;
+ } while(!done);
+ }
+ if (!cnt)
+ return -EINVAL;
+
+ return cnt;
+}
+
+static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ Link *link = userdata;
+ int r;
+
+ assert(link);
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0 && r != -EEXIST)
+ log_link_error_errno(link, r, "Could not add VLAN to bridge port: %m");
+
+ return 1;
+}
+
+int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+ int r;
+ uint16_t flags;
+ sd_netlink *rtnl;
+
+ assert(link);
+ assert(link->manager);
+ assert(br_vid_bitmap);
+ assert(br_untagged_bitmap);
+ assert(link->network);
+
+ /* pvid might not be in br_vid_bitmap yet */
+ if (pvid)
+ set_bit(pvid, br_vid_bitmap);
+
+ rtnl = link->manager->rtnl;
+
+ /* create new RTM message */
+ r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, link->ifindex);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
+
+ r = sd_rtnl_message_link_set_family(req, PF_BRIDGE);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set message family: %m");
+
+ r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
+
+ /* master needs flag self */
+ if (!link->network->bridge) {
+ flags = BRIDGE_FLAGS_SELF;
+ sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t));
+ }
+
+ /* add vlan info */
+ r = append_vlan_info_data(link, req, pvid, br_vid_bitmap, br_untagged_bitmap);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append VLANs: %m");
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
+
+ /* send message to the kernel */
+ r = sd_netlink_call_async(rtnl, req, set_brvlan_handler, link, 0, NULL);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+ return 0;
+}
+
+static int parse_vid_range(const char *rvalue, uint16_t *vid, uint16_t *vid_end) {
+ int r;
+ char *p;
+ char *_rvalue = NULL;
+ uint16_t _vid = UINT16_MAX;
+ uint16_t _vid_end = UINT16_MAX;
+
+ assert(rvalue);
+ assert(vid);
+ assert(vid_end);
+
+ _rvalue = strdupa(rvalue);
+ p = strchr(_rvalue, '-');
+ if (p) {
+ *p = '\0';
+ p++;
+ r = parse_vlanid(_rvalue, &_vid);
+ if (r < 0)
+ return r;
+
+ if (_vid == 0)
+ return -ERANGE;
+
+ r = parse_vlanid(p, &_vid_end);
+ if (r < 0)
+ return r;
+
+ if (_vid_end == 0)
+ return -ERANGE;
+ } else {
+ r = parse_vlanid(_rvalue, &_vid);
+ if (r < 0)
+ return r;
+
+ if (_vid == 0)
+ return -ERANGE;
+ }
+
+ *vid = _vid;
+ *vid_end = _vid_end;
+ return r;
+}
+
+int config_parse_brvlan_vlan(const char *unit, const char *filename,
+ unsigned line, const char *section,
+ unsigned section_line, const char *lvalue,
+ int ltype, const char *rvalue, void *data,
+ void *userdata) {
+ Network *network = userdata;
+ int r;
+ uint16_t vid, vid_end;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = parse_vid_range(rvalue, &vid, &vid_end);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VLAN, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (UINT16_MAX == vid_end)
+ set_bit(vid++, network->br_vid_bitmap);
+ else {
+ if (vid >= vid_end) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid VLAN range, ignoring %s", rvalue);
+ return 0;
+ }
+ for (; vid <= vid_end; vid++)
+ set_bit(vid, network->br_vid_bitmap);
+ }
+ return 0;
+}
+
+int config_parse_brvlan_untagged(const char *unit, const char *filename,
+ unsigned line, const char *section,
+ unsigned section_line, const char *lvalue,
+ int ltype, const char *rvalue, void *data,
+ void *userdata) {
+ Network *network = userdata;
+ int r;
+ uint16_t vid, vid_end;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = parse_vid_range(rvalue, &vid, &vid_end);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse VLAN: %s", rvalue);
+ return 0;
+ }
+
+ if (UINT16_MAX == vid_end) {
+ set_bit(vid, network->br_vid_bitmap);
+ set_bit(vid, network->br_untagged_bitmap);
+ } else {
+ if (vid >= vid_end) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid VLAN range, ignoring %s", rvalue);
+ return 0;
+ }
+ for (; vid <= vid_end; vid++) {
+ set_bit(vid, network->br_vid_bitmap);
+ set_bit(vid, network->br_untagged_bitmap);
+ }
+ }
+ return 0;
+}
diff --git a/src/network/networkd-brvlan.h b/src/network/networkd-brvlan.h
new file mode 100644
index 0000000000..6aa6883bfc
--- /dev/null
+++ b/src/network/networkd-brvlan.h
@@ -0,0 +1,29 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2016 BISDN GmbH. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdint.h>
+
+typedef struct Link Link;
+
+int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap);
+
+int config_parse_brvlan_vlan(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_brvlan_untagged(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 50721b1c74..15acf56a5f 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -60,10 +60,15 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
return 1;
}
-static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr,
- uint32_t lifetime_preferred, uint32_t lifetime_valid) {
- int r;
+static int dhcp6_address_change(
+ Link *link,
+ struct in6_addr *ip6_addr,
+ uint32_t lifetime_preferred,
+ uint32_t lifetime_valid) {
+
_cleanup_address_free_ Address *addr = NULL;
+ char buffer[INET6_ADDRSTRLEN];
+ int r;
r = address_new(&addr);
if (r < 0)
@@ -79,8 +84,8 @@ static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr,
addr->cinfo.ifa_valid = lifetime_valid;
log_link_info(link,
- "DHCPv6 address "SD_NDISC_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
- SD_NDISC_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
+ "DHCPv6 address %s/%d timeout preferred %d valid %d",
+ inet_ntop(AF_INET6, &addr->in_addr.in6, buffer, sizeof(buffer)),
addr->prefixlen, lifetime_preferred, lifetime_valid);
r = address_configure(addr, link, dhcp6_address_handler, true);
diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c
index 241f486211..be8aebee2d 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -26,15 +26,21 @@
#include "networkd-fdb.h"
#include "networkd.h"
#include "util.h"
+#include "vlan-util.h"
+
+#define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U
/* create a new FDB entry or get an existing one. */
-int fdb_entry_new_static(Network *const network,
- const unsigned section,
- FdbEntry **ret) {
+int fdb_entry_new_static(
+ Network *network,
+ unsigned section,
+ FdbEntry **ret) {
+
_cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
struct ether_addr *mac_addr = NULL;
assert(network);
+ assert(ret);
/* search entry in hashmap first. */
if (section) {
@@ -47,6 +53,9 @@ int fdb_entry_new_static(Network *const network,
}
}
+ if (network->n_static_fdb_entries >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX)
+ return -E2BIG;
+
/* allocate space for MAC address. */
mac_addr = new0(struct ether_addr, 1);
if (!mac_addr)
@@ -54,7 +63,6 @@ int fdb_entry_new_static(Network *const network,
/* allocate space for and FDB entry. */
fdb_entry = new0(FdbEntry, 1);
-
if (!fdb_entry) {
/* free previously allocated space for mac_addr. */
free(mac_addr);
@@ -66,6 +74,7 @@ int fdb_entry_new_static(Network *const network,
fdb_entry->mac_addr = mac_addr;
LIST_PREPEND(static_fdb_entries, network->static_fdb_entries, fdb_entry);
+ network->n_static_fdb_entries++;
if (section) {
fdb_entry->section = section;
@@ -94,7 +103,7 @@ static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
}
/* send a request to the kernel to add a FDB entry in its static MAC table. */
-int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) {
+int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
sd_netlink *rtnl;
int r;
@@ -145,12 +154,13 @@ void fdb_entry_free(FdbEntry *fdb_entry) {
return;
if (fdb_entry->network) {
- LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries,
- fdb_entry);
+ LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries, fdb_entry);
+
+ assert(fdb_entry->network->n_static_fdb_entries > 0);
+ fdb_entry->network->n_static_fdb_entries--;
if (fdb_entry->section)
- hashmap_remove(fdb_entry->network->fdb_entries_by_section,
- UINT_TO_PTR(fdb_entry->section));
+ hashmap_remove(fdb_entry->network->fdb_entries_by_section, UINT_TO_PTR(fdb_entry->section));
}
free(fdb_entry->mac_addr);
@@ -231,9 +241,9 @@ int config_parse_fdb_vlan_id(
if (r < 0)
return log_oom();
- r = config_parse_unsigned(unit, filename, line, section,
- section_line, lvalue, ltype,
- rvalue, &fdb_entry->vlan_id, userdata);
+ r = config_parse_vlanid(unit, filename, line, section,
+ section_line, lvalue, ltype,
+ rvalue, &fdb_entry->vlan_id, userdata);
if (r < 0)
return r;
diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h
index 84410714f5..2d7d28735c 100644
--- a/src/network/networkd-fdb.h
+++ b/src/network/networkd-fdb.h
@@ -36,9 +36,9 @@ struct FdbEntry {
LIST_FIELDS(FdbEntry, static_fdb_entries);
};
-int fdb_entry_new_static(Network *const network, const unsigned section, FdbEntry **ret);
+int fdb_entry_new_static(Network *network, unsigned section, FdbEntry **ret);
void fdb_entry_free(FdbEntry *fdb_entry);
-int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry);
+int fdb_entry_configure(Link *link, FdbEntry *fdb_entry);
DEFINE_TRIVIAL_CLEANUP_FUNC(FdbEntry*, fdb_entry_free);
#define _cleanup_fdbentry_free_ _cleanup_(fdb_entry_freep)
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index ee52b1ce1e..044f934e5f 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -28,8 +28,9 @@
#include "fileio.h"
#include "netlink-util.h"
#include "network-internal.h"
-#include "networkd.h"
#include "networkd-lldp-tx.h"
+#include "networkd-ndisc.h"
+#include "networkd.h"
#include "set.h"
#include "socket-util.h"
#include "stdio-util.h"
@@ -395,7 +396,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) {
static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
_cleanup_link_unref_ Link *link = NULL;
uint16_t type;
- const char *ifname;
+ const char *ifname, *kind = NULL;
int r, ifindex;
unsigned short iftype;
@@ -403,6 +404,15 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
assert(message);
assert(ret);
+ /* check for link kind */
+ r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
+ if (r == 0) {
+ (void)sd_netlink_message_read_string(message, IFLA_INFO_KIND, &kind);
+ r = sd_netlink_message_exit_container(message);
+ if (r < 0)
+ return r;
+ }
+
r = sd_netlink_message_get_type(message, &type);
if (r < 0)
return r;
@@ -437,6 +447,12 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
if (!link->ifname)
return -ENOMEM;
+ if (kind) {
+ link->kind = strdup(kind);
+ if (!link->kind)
+ return -ENOMEM;
+ }
+
r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
if (r < 0)
log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
@@ -504,13 +520,18 @@ static void link_free(Link *link) {
sd_ipv4ll_unref(link->ipv4ll);
sd_dhcp6_client_unref(link->dhcp6_client);
- sd_ndisc_unref(link->ndisc_router_discovery);
+ sd_ndisc_unref(link->ndisc);
+
+ set_free_free(link->ndisc_rdnss);
+ set_free_free(link->ndisc_dnssl);
if (link->manager)
hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
free(link->ifname);
+ free(link->kind);
+
(void)unlink(link->state_file);
free(link->state_file);
@@ -616,8 +637,8 @@ static int link_stop_clients(Link *link) {
r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
}
- if (link->ndisc_router_discovery) {
- k = sd_ndisc_stop(link->ndisc_router_discovery);
+ if (link->ndisc) {
+ k = sd_ndisc_stop(link->ndisc);
if (k < 0)
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
}
@@ -1092,7 +1113,17 @@ int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u
return 1;
}
-static int link_set_bridge_fdb(Link *const link) {
+static int link_set_bridge_vlan(Link *link) {
+ int r = 0;
+
+ r = br_vlan_configure(link, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
+ if (r < 0)
+ log_link_error_errno(link, r, "Failed to assign VLANs to bridge port: %m");
+
+ return r;
+}
+
+static int link_set_bridge_fdb(Link *link) {
FdbEntry *fdb_entry;
int r = 0;
@@ -1107,7 +1138,7 @@ static int link_set_bridge_fdb(Link *const link) {
return r;
}
-static int link_set_proxy_arp(Link *const link) {
+static int link_set_proxy_arp(Link *link) {
const char *p = NULL;
int r;
@@ -1453,11 +1484,11 @@ static int link_acquire_ipv6_conf(Link *link) {
}
if (link_ipv6_accept_ra_enabled(link)) {
- assert(link->ndisc_router_discovery);
+ assert(link->ndisc);
log_link_debug(link, "Discovering IPv6 routers");
- r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
+ r = sd_ndisc_start(link->ndisc);
if (r < 0 && r != -EBUSY)
return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
}
@@ -1974,6 +2005,12 @@ static int link_joined(Link *link) {
log_link_error_errno(link, r, "Could not set bridge message: %m");
}
+ if (link->network->bridge || streq_ptr("bridge", link->kind)) {
+ r = link_set_bridge_vlan(link);
+ if (r < 0)
+ log_link_error_errno(link, r, "Could not set bridge vlan: %m");
+ }
+
return link_enter_set_addresses(link);
}
@@ -2364,7 +2401,11 @@ static int link_configure(Link *link) {
}
if (link_lldp_rx_enabled(link)) {
- r = sd_lldp_new(&link->lldp, link->ifindex);
+ r = sd_lldp_new(&link->lldp);
+ if (r < 0)
+ return r;
+
+ r = sd_lldp_set_ifindex(link->lldp, link->ifindex);
if (r < 0)
return r;
@@ -3083,6 +3124,22 @@ int link_save(Link *link) {
if (space)
fputc(' ', f);
serialize_in6_addrs(f, in6_addrs, r);
+ space = true;
+ }
+ }
+
+ /* Make sure to flush out old entries before we use the NDISC data */
+ ndisc_vacuum(link);
+
+ if (link->network->dhcp_use_dns && link->ndisc_rdnss) {
+ NDiscRDNSS *dd;
+
+ SET_FOREACH(dd, link->ndisc_rdnss, i) {
+ if (space)
+ fputc(' ', f);
+
+ serialize_in6_addrs(f, &dd->address, 1);
+ space = true;
}
}
@@ -3128,7 +3185,6 @@ int link_save(Link *link) {
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
if (link->dhcp_lease)
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
-
if (dhcp6_lease)
(void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
}
@@ -3136,22 +3192,34 @@ int link_save(Link *link) {
fputs("DOMAINS=", f);
fputstrv(f, link->network->search_domains, NULL, &space);
- if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp_domainname)
- fputs_with_space(f, dhcp_domainname, NULL, &space);
+ if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
+ NDiscDNSSL *dd;
+
+ if (dhcp_domainname)
+ fputs_with_space(f, dhcp_domainname, NULL, &space);
+ if (dhcp6_domains)
+ fputstrv(f, dhcp6_domains, NULL, &space);
- if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp6_domains)
- fputstrv(f, dhcp6_domains, NULL, &space);
+ SET_FOREACH(dd, link->ndisc_dnssl, i)
+ fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
+ }
fputc('\n', f);
fputs("ROUTE_DOMAINS=", f);
fputstrv(f, link->network->route_domains, NULL, NULL);
- if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp_domainname)
- fputs_with_space(f, dhcp_domainname, NULL, &space);
+ if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
+ NDiscDNSSL *dd;
- if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp6_domains)
- fputstrv(f, dhcp6_domains, NULL, &space);
+ if (dhcp_domainname)
+ fputs_with_space(f, dhcp_domainname, NULL, &space);
+ if (dhcp6_domains)
+ fputstrv(f, dhcp6_domains, NULL, &space);
+
+ SET_FOREACH(dd, link->ndisc_dnssl, i)
+ fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
+ }
fputc('\n', f);
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 5efefd27d6..2809b1fe0b 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -68,6 +68,7 @@ typedef struct Link {
int ifindex;
char *ifname;
+ char *kind;
unsigned short iftype;
char *state_file;
struct ether_addr mac;
@@ -98,6 +99,7 @@ typedef struct Link {
unsigned dhcp4_messages;
bool dhcp4_configured;
bool dhcp6_configured;
+
unsigned ndisc_messages;
bool ndisc_configured;
@@ -111,7 +113,10 @@ typedef struct Link {
sd_dhcp_server *dhcp_server;
- sd_ndisc *ndisc_router_discovery;
+ sd_ndisc *ndisc;
+ Set *ndisc_rdnss;
+ Set *ndisc_dnssl;
+
sd_dhcp6_client *dhcp6_client;
bool rtnl_extended_attrs;
@@ -161,7 +166,6 @@ int ipv4ll_configure(Link *link);
int dhcp4_configure(Link *link);
int dhcp6_configure(Link *link);
int dhcp6_request_address(Link *link, int ir);
-int ndisc_configure(Link *link);
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index a0d4fa77d8..2a1ba2bac7 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -17,14 +17,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
#include <netinet/icmp6.h>
-#include <netinet/in.h>
-#include <linux/if.h>
#include "sd-ndisc.h"
#include "networkd.h"
+#include "networkd-ndisc.h"
+
+#define NDISC_DNSSL_MAX 64U
+#define NDISC_RDNSS_MAX 64U
static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
@@ -49,19 +50,92 @@ static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *
return 1;
}
-static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
- unsigned lifetime_preferred, unsigned lifetime_valid, void *userdata) {
- _cleanup_address_free_ Address *address = NULL;
- Link *link = userdata;
+static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
+ _cleanup_route_free_ Route *route = NULL;
+ struct in6_addr gateway;
+ uint16_t lifetime;
+ unsigned preference;
usec_t time_now;
int r;
- assert(nd);
assert(link);
- assert(link->network);
+ assert(rt);
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ r = sd_ndisc_router_get_lifetime(rt, &lifetime);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
+ return;
+ }
+ if (lifetime == 0) /* not a default router */
+ return;
+
+ r = sd_ndisc_router_get_address(rt, &gateway);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
+ return;
+ }
+
+ r = sd_ndisc_router_get_preference(rt, &preference);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
+ return;
+ }
+
+ r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
+ return;
+ }
+
+ r = route_new(&route);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Could not allocate route: %m");
+ return;
+ }
+
+ route->family = AF_INET6;
+ route->table = RT_TABLE_MAIN;
+ route->protocol = RTPROT_RA;
+ route->pref = preference;
+ route->gw.in6 = gateway;
+ route->lifetime = time_now + lifetime * USEC_PER_SEC;
+
+ r = route_configure(route, link, ndisc_netlink_handler);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Could not set default route: %m");
+ link_enter_failed(link);
+ return;
+ }
+
+ link->ndisc_messages++;
+}
+
+static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
+ _cleanup_address_free_ Address *address = NULL;
+ uint32_t lifetime_valid, lifetime_preferred;
+ unsigned prefixlen;
+ int r;
+
+ assert(link);
+ assert(rt);
+
+ r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Failed to get prefix length: %m");
+ return;
+ }
+
+ r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
return;
+ }
+
+ r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
+ return;
+ }
r = address_new(&address);
if (r < 0) {
@@ -69,10 +143,13 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr
return;
}
- assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
-
address->family = AF_INET6;
- address->in_addr.in6 = *prefix;
+ r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Failed to get prefix address: %m");
+ return;
+ }
+
if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
else {
@@ -102,17 +179,33 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr
link->ndisc_messages++;
}
-static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) {
+static void ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
_cleanup_route_free_ Route *route = NULL;
- Link *link = userdata;
usec_t time_now;
+ uint32_t lifetime;
+ unsigned prefixlen;
int r;
- assert(nd);
assert(link);
+ assert(rt);
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
return;
+ }
+
+ r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Failed to get prefix length: %m");
+ return;
+ }
+
+ r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
+ return;
+ }
r = route_new(&route);
if (r < 0) {
@@ -120,16 +213,19 @@ static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *pre
return;
}
- assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
-
route->family = AF_INET6;
route->table = RT_TABLE_MAIN;
route->protocol = RTPROT_RA;
route->flags = RTM_F_PREFIX;
- route->dst.in6 = *prefix;
route->dst_prefixlen = prefixlen;
route->lifetime = time_now + lifetime * USEC_PER_SEC;
+ r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Failed to get prefix address: %m");
+ return;
+ }
+
r = route_configure(route, link, ndisc_netlink_handler);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set prefix route: %m");
@@ -140,32 +236,47 @@ static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *pre
link->ndisc_messages++;
}
-static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) {
+static void ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
_cleanup_route_free_ Route *route = NULL;
- Link *link = userdata;
+ struct in6_addr gateway;
+ uint32_t lifetime;
+ unsigned preference, prefixlen;
usec_t time_now;
int r;
assert(link);
- assert(link->network);
- assert(link->manager);
- assert(link->dhcp6_client);
- assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ r = sd_ndisc_router_route_get_lifetime(rt, &lifetime);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
+ return;
+ }
+ if (lifetime == 0)
return;
- if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
- /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
- r = dhcp6_request_address(link, flags & ND_RA_FLAG_MANAGED ? false : true);
- if (r < 0 && r != -EBUSY)
- log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
- else
- log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
+ r = sd_ndisc_router_get_address(rt, &gateway);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
+ return;
}
- if (!gateway)
+ r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
return;
+ }
+
+ r = sd_ndisc_router_route_get_preference(rt, &preference);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
+ return;
+ }
+
+ r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
+ return;
+ }
r = route_new(&route);
if (r < 0) {
@@ -173,18 +284,23 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a
return;
}
- assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
-
route->family = AF_INET6;
route->table = RT_TABLE_MAIN;
route->protocol = RTPROT_RA;
- route->pref = pref;
- route->gw.in6 = *gateway;
+ route->pref = preference;
+ route->gw.in6 = gateway;
+ route->dst_prefixlen = prefixlen;
route->lifetime = time_now + lifetime * USEC_PER_SEC;
+ r = sd_ndisc_router_route_get_address(rt, &route->dst.in6);
+ if (r < 0) {
+ log_link_error_errno(link, r, "Failed to get route address: %m");
+ return;
+ }
+
r = route_configure(route, link, ndisc_netlink_handler);
if (r < 0) {
- log_link_warning_errno(link, r, "Could not set default route: %m");
+ log_link_warning_errno(link, r, "Could not set additional route: %m");
link_enter_failed(link);
return;
}
@@ -192,7 +308,290 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a
link->ndisc_messages++;
}
-static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
+static void ndisc_rdnss_hash_func(const void *p, struct siphash *state) {
+ const NDiscRDNSS *x = p;
+
+ siphash24_compress(&x->address, sizeof(x->address), state);
+}
+
+static int ndisc_rdnss_compare_func(const void *_a, const void *_b) {
+ const NDiscRDNSS *a = _a, *b = _b;
+
+ return memcmp(&a->address, &b->address, sizeof(a->address));
+}
+
+static const struct hash_ops ndisc_rdnss_hash_ops = {
+ .hash = ndisc_rdnss_hash_func,
+ .compare = ndisc_rdnss_compare_func
+};
+
+static void ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
+ uint32_t lifetime;
+ const struct in6_addr *a;
+ usec_t time_now;
+ int i, n, r;
+
+ assert(link);
+ assert(rt);
+
+ r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
+ return;
+ }
+
+ r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
+ return;
+ }
+
+ n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
+ if (n < 0) {
+ log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
+ return;
+ }
+
+ for (i = 0; i < n; i++) {
+ NDiscRDNSS d = {
+ .address = a[i]
+ }, *x;
+
+ if (lifetime == 0) {
+ (void) set_remove(link->ndisc_rdnss, &d);
+ link_dirty(link);
+ continue;
+ }
+
+ x = set_get(link->ndisc_rdnss, &d);
+ if (x) {
+ x->valid_until = time_now + lifetime * USEC_PER_SEC;
+ continue;
+ }
+
+ ndisc_vacuum(link);
+
+ if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
+ log_link_warning(link, "Too many RDNSS records per link, ignoring.");
+ continue;
+ }
+
+ r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops);
+ if (r < 0) {
+ log_oom();
+ return;
+ }
+
+ x = new0(NDiscRDNSS, 1);
+ if (!x) {
+ log_oom();
+ return;
+ }
+
+ x->address = a[i];
+ x->valid_until = time_now + lifetime * USEC_PER_SEC;
+
+ r = set_put(link->ndisc_rdnss, x);
+ if (r < 0) {
+ free(x);
+ log_oom();
+ return;
+ }
+
+ assert(r > 0);
+ link_dirty(link);
+ }
+}
+
+static void ndisc_dnssl_hash_func(const void *p, struct siphash *state) {
+ const NDiscDNSSL *x = p;
+
+ siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state);
+}
+
+static int ndisc_dnssl_compare_func(const void *_a, const void *_b) {
+ const NDiscDNSSL *a = _a, *b = _b;
+
+ return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
+}
+
+static const struct hash_ops ndisc_dnssl_hash_ops = {
+ .hash = ndisc_dnssl_hash_func,
+ .compare = ndisc_dnssl_compare_func
+};
+
+static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
+ _cleanup_strv_free_ char **l = NULL;
+ uint32_t lifetime;
+ usec_t time_now;
+ char **i;
+ int r;
+
+ assert(link);
+ assert(rt);
+
+ r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
+ return;
+ }
+
+ r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
+ return;
+ }
+
+ r = sd_ndisc_router_dnssl_get_domains(rt, &l);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RDNSS addresses: %m");
+ return;
+ }
+
+ STRV_FOREACH(i, l) {
+ struct {
+ NDiscDNSSL header;
+ char domain[strlen(*i)];
+ } s;
+ NDiscDNSSL *x;
+
+ zero(s.header);
+ strcpy(s.domain, *i);
+
+ if (lifetime == 0) {
+ (void) set_remove(link->ndisc_dnssl, &s);
+ link_dirty(link);
+ continue;
+ }
+
+ x = set_get(link->ndisc_dnssl, &s);
+ if (x) {
+ x->valid_until = time_now + lifetime * USEC_PER_SEC;
+ continue;
+ }
+
+ ndisc_vacuum(link);
+
+ if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
+ log_link_warning(link, "Too many DNSSL records per link, ignoring.");
+ continue;
+ }
+
+ r = set_ensure_allocated(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops);
+ if (r < 0) {
+ log_oom();
+ return;
+ }
+
+ x = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1);
+ if (!x) {
+ log_oom();
+ return;
+ }
+
+ strcpy(NDISC_DNSSL_DOMAIN(x), *i);
+ x->valid_until = time_now + lifetime * USEC_PER_SEC;
+
+ r = set_put(link->ndisc_dnssl, x);
+ if (r < 0) {
+ free(x);
+ log_oom();
+ return;
+ }
+
+ assert(r > 0);
+ link_dirty(link);
+ }
+}
+
+static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
+ int r;
+
+ assert(link);
+ assert(rt);
+
+ r = sd_ndisc_router_option_rewind(rt);
+ for (;;) {
+ uint8_t type;
+
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to iterate through options: %m");
+ return;
+ }
+ if (r == 0) /* EOF */
+ break;
+
+ r = sd_ndisc_router_option_get_type(rt, &type);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RA option type: %m");
+ return;
+ }
+
+ switch (type) {
+
+ case SD_NDISC_OPTION_PREFIX_INFORMATION: {
+ uint8_t flags;
+
+ r = sd_ndisc_router_prefix_get_flags(rt, &flags);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
+ return;
+ }
+
+ if (flags & ND_OPT_PI_FLAG_ONLINK)
+ ndisc_router_process_onlink_prefix(link, rt);
+ if (flags & ND_OPT_PI_FLAG_AUTO)
+ ndisc_router_process_autonomous_prefix(link, rt);
+
+ break;
+ }
+
+ case SD_NDISC_OPTION_ROUTE_INFORMATION:
+ ndisc_router_process_route(link, rt);
+ break;
+
+ case SD_NDISC_OPTION_RDNSS:
+ ndisc_router_process_rdnss(link, rt);
+ break;
+
+ case SD_NDISC_OPTION_DNSSL:
+ ndisc_router_process_dnssl(link, rt);
+ break;
+ }
+
+ r = sd_ndisc_router_option_next(rt);
+ }
+}
+
+static void ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
+ uint64_t flags;
+ int r;
+
+ assert(link);
+ assert(link->network);
+ assert(link->manager);
+ assert(rt);
+
+ r = sd_ndisc_router_get_flags(rt, &flags);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get RA flags: %m");
+ return;
+ }
+
+ if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
+ /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
+ r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
+ if (r < 0 && r != -EBUSY)
+ log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
+ else
+ log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
+ }
+
+ ndisc_router_process_default(link, rt);
+ ndisc_router_process_options(link, rt);
+}
+
+static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
Link *link = userdata;
assert(link);
@@ -201,13 +600,16 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
return;
switch (event) {
+
+ case SD_NDISC_EVENT_ROUTER:
+ ndisc_router_handler(link, rt);
+ break;
+
case SD_NDISC_EVENT_TIMEOUT:
link->ndisc_configured = true;
link_check_ready(link);
break;
- case SD_NDISC_EVENT_STOP:
- break;
default:
log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
}
@@ -216,30 +618,52 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
int ndisc_configure(Link *link) {
int r;
- assert_return(link, -EINVAL);
+ assert(link);
+
+ r = sd_ndisc_new(&link->ndisc);
+ if (r < 0)
+ return r;
- r = sd_ndisc_new(&link->ndisc_router_discovery);
+ r = sd_ndisc_attach_event(link->ndisc, NULL, 0);
if (r < 0)
return r;
- r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0);
+ r = sd_ndisc_set_mac(link->ndisc, &link->mac);
if (r < 0)
return r;
- r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac);
+ r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
if (r < 0)
return r;
- r = sd_ndisc_set_ifindex(link->ndisc_router_discovery, link->ifindex);
+ r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
if (r < 0)
return r;
- r = sd_ndisc_set_callback(link->ndisc_router_discovery,
- ndisc_router_handler,
- ndisc_prefix_onlink_handler,
- ndisc_prefix_autonomous_handler,
- ndisc_handler,
- link);
+ return 0;
+}
+
+void ndisc_vacuum(Link *link) {
+ NDiscRDNSS *r;
+ NDiscDNSSL *d;
+ Iterator i;
+ usec_t time_now;
+
+ assert(link);
+
+ /* Removes all RDNSS and DNSSL entries whose validity time has passed */
+
+ time_now = now(clock_boottime_or_monotonic());
+
+ SET_FOREACH(r, link->ndisc_rdnss, i)
+ if (r->valid_until < time_now) {
+ (void) set_remove(link->ndisc_rdnss, r);
+ link_dirty(link);
+ }
- return r;
+ SET_FOREACH(d, link->ndisc_dnssl, i)
+ if (d->valid_until < time_now) {
+ (void) set_remove(link->ndisc_dnssl, d);
+ link_dirty(link);
+ }
}
diff --git a/src/network/networkd-ndisc.h b/src/network/networkd-ndisc.h
new file mode 100644
index 0000000000..2002f55107
--- /dev/null
+++ b/src/network/networkd-ndisc.h
@@ -0,0 +1,39 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "networkd-link.h"
+
+typedef struct NDiscRDNSS {
+ usec_t valid_until;
+ struct in6_addr address;
+} NDiscRDNSS;
+
+typedef struct NDiscDNSSL {
+ usec_t valid_until;
+ /* The domain name follows immediately. */
+} NDiscDNSSL;
+
+static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
+ return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
+}
+
+int ndisc_configure(Link *link);
+void ndisc_vacuum(Link *link);
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index adc64977b9..a9512cd77b 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -3,6 +3,7 @@
#include "conf-parser.h"
#include "network-internal.h"
#include "networkd-netdev-bond.h"
+#include "networkd-netdev-bridge.h"
#include "networkd-netdev-ipvlan.h"
#include "networkd-netdev-macvlan.h"
#include "networkd-netdev-tunnel.h"
@@ -10,8 +11,8 @@
#include "networkd-netdev-veth.h"
#include "networkd-netdev-vlan.h"
#include "networkd-netdev-vxlan.h"
-#include "networkd-netdev-bridge.h"
#include "networkd-netdev.h"
+#include "vlan-util.h"
%}
struct ConfigPerfItem;
%null_strings
@@ -33,7 +34,7 @@ NetDev.Name, config_parse_ifname, 0,
NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind)
NetDev.MTUBytes, config_parse_iec_size, 0, offsetof(NetDev, mtu)
NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac)
-VLAN.Id, config_parse_uint64, 0, offsetof(VLan, id)
+VLAN.Id, config_parse_vlanid, 0, offsetof(VLan, id)
MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
MACVTAP.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c
index b1f4714afa..3cc072388f 100644
--- a/src/network/networkd-netdev-vlan.c
+++ b/src/network/networkd-netdev-vlan.c
@@ -20,6 +20,7 @@
#include <net/if.h>
#include "networkd-netdev-vlan.h"
+#include "vlan-util.h"
static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
VLan *v;
@@ -33,11 +34,9 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin
assert(v);
- if (v->id <= VLANID_MAX) {
- r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_ID attribute: %m");
- }
+ r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_ID attribute: %m");
return 0;
}
@@ -52,8 +51,8 @@ static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
assert(v);
- if (v->id > VLANID_MAX) {
- log_warning("VLAN without valid Id (%"PRIu64") configured in %s. Ignoring", v->id, filename);
+ if (v->id == VLANID_INVALID) {
+ log_warning("VLAN without valid Id (%"PRIu16") configured in %s.", v->id, filename);
return -EINVAL;
}
@@ -66,7 +65,7 @@ static void vlan_init(NetDev *netdev) {
assert(netdev);
assert(v);
- v->id = VLANID_MAX + 1;
+ v->id = VLANID_INVALID;
}
const NetDevVTable vlan_vtable = {
diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h
index 73aacf4a0f..2dfe314b6e 100644
--- a/src/network/networkd-netdev-vlan.h
+++ b/src/network/networkd-netdev-vlan.h
@@ -23,12 +23,10 @@ typedef struct VLan VLan;
#include "networkd-netdev.h"
-#define VLANID_MAX 4094
-
struct VLan {
NetDev meta;
- uint64_t id;
+ uint16_t id;
};
DEFINE_NETDEV_CAST(VLAN, VLan);
diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c
index d6b7448a43..6e21676d23 100644
--- a/src/network/networkd-network-bus.c
+++ b/src/network/networkd-network-bus.c
@@ -60,7 +60,7 @@ const sd_bus_vtable network_vtable[] = {
SD_BUS_PROPERTY("Description", "s", NULL, offsetof(Network, description), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Network, filename), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, offsetof(Network, match_mac), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MatchPath", "as", NULL, offsetof(Network, match_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MatchDriver", "as", NULL, offsetof(Network, match_driver), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MatchType", "as", NULL, offsetof(Network, match_type), SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 03e4e3b39f..0b0aa58f67 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -4,6 +4,7 @@
#include "networkd.h"
#include "networkd-conf.h"
#include "network-internal.h"
+#include "vlan-util.h"
%}
struct ConfigPerfItem;
%null_strings
@@ -55,6 +56,8 @@ Network.NTP, config_parse_strv,
Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward)
Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade)
Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions)
+Network.IPv6AcceptRA, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra)
+/* legacy alias for the above */
Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra)
Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits)
Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit)
@@ -89,6 +92,8 @@ DHCP.DUIDRawData, config_parse_duid_rawdata,
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
+IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
+IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns)
@@ -108,6 +113,9 @@ Bridge.AllowPortToBeRoot, config_parse_bool,
Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood)
BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
+BridgeVLAN.PVID, config_parse_vlanid, 0, offsetof(Network, pvid)
+BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0
+BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 0, 0
/* backwards compatibility: do not add new entries to this section */
Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local)
DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index dd89b3770c..84bdf75b38 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -51,8 +51,8 @@ static int network_load_one(Manager *manager, const char *filename) {
if (!file) {
if (errno == ENOENT)
return 0;
- else
- return -errno;
+
+ return -errno;
}
if (null_or_empty_fd(fileno(file))) {
@@ -134,6 +134,7 @@ static int network_load_one(Manager *manager, const char *filename) {
network->ipv6_hop_limit = -1;
network->duid.type = _DUID_TYPE_INVALID;
network->proxy_arp = -1;
+ network->ipv6_accept_ra_use_dns = true;
r = config_parse(NULL, filename, file,
"Match\0"
@@ -144,8 +145,10 @@ static int network_load_one(Manager *manager, const char *filename) {
"DHCP\0"
"DHCPv4\0" /* compat */
"DHCPServer\0"
+ "IPv6AcceptRA\0"
"Bridge\0"
- "BridgeFDB\0",
+ "BridgeFDB\0"
+ "BridgeVLAN\0",
config_item_perf_lookup, network_network_gperf_lookup,
false, false, true, network);
if (r < 0)
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 91099161ce..38688cc400 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -28,6 +28,7 @@
#include "resolve-util.h"
#include "networkd-address.h"
+#include "networkd-brvlan.h"
#include "networkd-fdb.h"
#include "networkd-lldp-tx.h"
#include "networkd-netdev.h"
@@ -37,6 +38,9 @@
#define DHCP_ROUTE_METRIC 1024
#define IPV4LL_ROUTE_METRIC 2048
+#define BRIDGE_VLAN_BITMAP_MAX 4096
+#define BRIDGE_VLAN_BITMAP_LEN (BRIDGE_VLAN_BITMAP_MAX / 32)
+
typedef enum DCHPClientIdentifier {
DHCP_CLIENT_ID_MAC,
DHCP_CLIENT_ID_DUID,
@@ -146,6 +150,10 @@ struct Network {
bool unicast_flood;
unsigned cost;
+ uint16_t pvid;
+ uint32_t br_vid_bitmap[BRIDGE_VLAN_BITMAP_LEN];
+ uint32_t br_untagged_bitmap[BRIDGE_VLAN_BITMAP_LEN];
+
AddressFamilyBoolean ip_forward;
bool ip_masquerade;
@@ -154,6 +162,9 @@ struct Network {
int ipv6_hop_limit;
int proxy_arp;
+ bool ipv6_accept_ra_use_dns;
+ DHCPUseDomains ipv6_accept_ra_use_domains;
+
union in_addr_union ipv6_token;
IPv6PrivacyExtensions ipv6_privacy_extensions;
@@ -169,6 +180,10 @@ struct Network {
LIST_HEAD(Route, static_routes);
LIST_HEAD(FdbEntry, static_fdb_entries);
+ unsigned n_static_addresses;
+ unsigned n_static_routes;
+ unsigned n_static_fdb_entries;
+
Hashmap *addresses_by_section;
Hashmap *routes_by_section;
Hashmap *fdb_entries_by_section;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index f001de772a..cedaf47cf8 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -28,6 +28,9 @@
#include "string-util.h"
#include "util.h"
+#define ROUTES_PER_LINK_MAX 2048U
+#define STATIC_ROUTES_PER_NETWORK_MAX 1024U
+
int route_new(Route **ret) {
_cleanup_route_free_ Route *route = NULL;
@@ -51,6 +54,9 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
_cleanup_route_free_ Route *route = NULL;
int r;
+ assert(network);
+ assert(ret);
+
if (section) {
route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section));
if (route) {
@@ -61,6 +67,9 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
}
}
+ if (network->n_static_routes >= STATIC_ROUTES_PER_NETWORK_MAX)
+ return -E2BIG;
+
r = route_new(&route);
if (r < 0)
return r;
@@ -77,6 +86,7 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
route->network = network;
LIST_PREPEND(routes, network->static_routes, route);
+ network->n_static_routes++;
*ret = route;
route = NULL;
@@ -91,9 +101,11 @@ void route_free(Route *route) {
if (route->network) {
LIST_REMOVE(routes, route->network->static_routes, route);
+ assert(route->network->n_static_routes > 0);
+ route->network->n_static_routes--;
+
if (route->section)
- hashmap_remove(route->network->routes_by_section,
- UINT_TO_PTR(route->section));
+ hashmap_remove(route->network->routes_by_section, UINT_TO_PTR(route->section));
}
if (route->link) {
@@ -176,48 +188,55 @@ static const struct hash_ops route_hash_ops = {
int route_get(Link *link,
int family,
- union in_addr_union *dst,
+ const union in_addr_union *dst,
unsigned char dst_prefixlen,
unsigned char tos,
uint32_t priority,
unsigned char table,
Route **ret) {
- Route route = {
+
+ Route route, *existing;
+
+ assert(link);
+ assert(dst);
+
+ route = (Route) {
.family = family,
+ .dst = *dst,
.dst_prefixlen = dst_prefixlen,
.tos = tos,
.priority = priority,
.table = table,
- }, *existing;
-
- assert(link);
- assert(dst);
- assert(ret);
-
- route.dst = *dst;
+ };
existing = set_get(link->routes, &route);
if (existing) {
- *ret = existing;
+ if (ret)
+ *ret = existing;
return 1;
- } else {
- existing = set_get(link->routes_foreign, &route);
- if (!existing)
- return -ENOENT;
}
- *ret = existing;
+ existing = set_get(link->routes_foreign, &route);
+ if (existing) {
+ if (ret)
+ *ret = existing;
+ return 0;
+ }
- return 0;
+ return -ENOENT;
}
-static int route_add_internal(Link *link, Set **routes,
- int family,
- union in_addr_union *dst,
- unsigned char dst_prefixlen,
- unsigned char tos,
- uint32_t priority,
- unsigned char table, Route **ret) {
+static int route_add_internal(
+ Link *link,
+ Set **routes,
+ int family,
+ const union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table,
+ Route **ret) {
+
_cleanup_route_free_ Route *route = NULL;
int r;
@@ -254,23 +273,29 @@ static int route_add_internal(Link *link, Set **routes,
return 0;
}
-int route_add_foreign(Link *link,
- int family,
- union in_addr_union *dst,
- unsigned char dst_prefixlen,
- unsigned char tos,
- uint32_t priority,
- unsigned char table, Route **ret) {
+int route_add_foreign(
+ Link *link,
+ int family,
+ const union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table,
+ Route **ret) {
+
return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
}
-int route_add(Link *link,
+int route_add(
+ Link *link,
int family,
- union in_addr_union *dst,
+ const union in_addr_union *dst,
unsigned char dst_prefixlen,
unsigned char tos,
uint32_t priority,
- unsigned char table, Route **ret) {
+ unsigned char table,
+ Route **ret) {
+
Route *route;
int r;
@@ -303,12 +328,13 @@ int route_add(Link *link,
}
int route_update(Route *route,
- union in_addr_union *src,
+ const union in_addr_union *src,
unsigned char src_prefixlen,
- union in_addr_union *gw,
- union in_addr_union *prefsrc,
+ const union in_addr_union *gw,
+ const union in_addr_union *prefsrc,
unsigned char scope,
unsigned char protocol) {
+
assert(route);
assert(src);
assert(gw);
@@ -449,8 +475,11 @@ int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
return 1;
}
-int route_configure(Route *route, Link *link,
- sd_netlink_message_handler_t callback) {
+int route_configure(
+ Route *route,
+ Link *link,
+ sd_netlink_message_handler_t callback) {
+
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
usec_t lifetime;
@@ -462,6 +491,10 @@ int route_configure(Route *route, Link *link,
assert(link->ifindex > 0);
assert(route->family == AF_INET || route->family == AF_INET6);
+ if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 &&
+ set_size(link->routes) >= ROUTES_PER_LINK_MAX)
+ return -E2BIG;
+
r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
RTM_NEWROUTE, route->family,
route->protocol);
@@ -762,6 +795,7 @@ int config_parse_route_priority(const char *unit,
void *userdata) {
Network *network = userdata;
_cleanup_route_free_ Route *n = NULL;
+ uint32_t k;
int r;
assert(filename);
@@ -774,12 +808,14 @@ int config_parse_route_priority(const char *unit,
if (r < 0)
return r;
- r = config_parse_uint32(unit, filename, line, section,
- section_line, lvalue, ltype,
- rvalue, &n->priority, userdata);
- if (r < 0)
- return r;
+ r = safe_atou32(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
+ return 0;
+ }
+ n->priority = k;
n = NULL;
return 0;
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index 39de8363ed..d4e4dbac0b 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -57,10 +57,10 @@ void route_free(Route *route);
int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback);
-int route_get(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
-int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
-int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
-int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
+int route_get(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf
index 2b5d452662..3231a48d5a 100644
--- a/src/nspawn/nspawn-gperf.gperf
+++ b/src/nspawn/nspawn-gperf.gperf
@@ -27,6 +27,7 @@ Exec.Personality, config_parse_personality, 0, offsetof(Settings,
Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id)
Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory)
Exec.PrivateUsers, config_parse_private_users, 0, 0
+Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready)
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
Files.Bind, config_parse_bind, 0, 0
diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h
index 1c47e37912..231e6d7266 100644
--- a/src/nspawn/nspawn-settings.h
+++ b/src/nspawn/nspawn-settings.h
@@ -56,7 +56,8 @@ typedef enum SettingsMask {
SETTING_CUSTOM_MOUNTS = 1 << 11,
SETTING_WORKING_DIRECTORY = 1 << 12,
SETTING_USERNS = 1 << 13,
- _SETTINGS_MASK_ALL = (1 << 14) -1
+ SETTING_NOTIFY_READY = 1 << 14,
+ _SETTINGS_MASK_ALL = (1 << 15) -1
} SettingsMask;
typedef struct Settings {
@@ -73,6 +74,7 @@ typedef struct Settings {
char *working_directory;
UserNamespaceMode userns_mode;
uid_t uid_shift, uid_range;
+ bool notify_ready;
/* [Image] */
int read_only;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index d1c65e8b0b..ea24de7608 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -104,6 +104,10 @@
* UID range here */
#define UID_SHIFT_PICK_MIN ((uid_t) UINT32_C(0x00080000))
#define UID_SHIFT_PICK_MAX ((uid_t) UINT32_C(0x6FFF0000))
+/* nspawn is listening on the socket at the path in the constant nspawn_notify_socket_path
+ * nspawn_notify_socket_path is relative to the container
+ * the init process in the container pid can send messages to nspawn following the sd_notify(3) protocol */
+#define NSPAWN_NOTIFY_SOCKET_PATH "/run/systemd/nspawn/notify"
typedef enum ContainerStatus {
CONTAINER_TERMINATED,
@@ -187,6 +191,7 @@ static SettingsMask arg_settings_mask = 0;
static int arg_settings_trusted = -1;
static char **arg_parameters = NULL;
static const char *arg_container_service_name = "systemd-nspawn";
+static bool arg_notify_ready = false;
static void help(void) {
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
@@ -267,6 +272,8 @@ static void help(void) {
" the service unit nspawn is running in\n"
" --volatile[=MODE] Run the system in volatile mode\n"
" --settings=BOOLEAN Load additional settings from .nspawn file\n"
+ " --notify-ready=BOOLEAN Receive notifications from the container's init process,\n"
+ " accepted values: yes and no\n"
, program_invocation_short_name);
}
@@ -367,6 +374,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SETTINGS,
ARG_CHDIR,
ARG_PRIVATE_USERS_CHOWN,
+ ARG_NOTIFY_READY,
};
static const struct option options[] = {
@@ -415,6 +423,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "kill-signal", required_argument, NULL, ARG_KILL_SIGNAL },
{ "settings", required_argument, NULL, ARG_SETTINGS },
{ "chdir", required_argument, NULL, ARG_CHDIR },
+ { "notify-ready", required_argument, NULL, ARG_NOTIFY_READY },
{}
};
@@ -987,6 +996,16 @@ static int parse_argv(int argc, char *argv[]) {
arg_settings_mask |= SETTING_WORKING_DIRECTORY;
break;
+ case ARG_NOTIFY_READY:
+ r = parse_boolean(optarg);
+ if (r < 0) {
+ log_error("%s is not a valid notify mode. Valid modes are: yes, no, and ready.", optarg);
+ return -EINVAL;
+ }
+ arg_notify_ready = r;
+ arg_settings_mask |= SETTING_NOTIFY_READY;
+ break;
+
case '?':
return -EINVAL;
@@ -2529,6 +2548,7 @@ static int inner_child(
NULL, /* container_uuid */
NULL, /* LISTEN_FDS */
NULL, /* LISTEN_PID */
+ NULL, /* NOTIFY_SOCKET */
NULL
};
@@ -2656,6 +2676,8 @@ static int inner_child(
(asprintf((char **)(envp + n_env++), "LISTEN_PID=1") < 0))
return log_oom();
}
+ if (asprintf((char **)(envp + n_env++), "NOTIFY_SOCKET=%s", NSPAWN_NOTIFY_SOCKET_PATH) < 0)
+ return log_oom();
env_use = strv_env_merge(2, envp, arg_setenv);
if (!env_use)
@@ -2725,6 +2747,37 @@ static int inner_child(
return log_error_errno(r, "execv() failed: %m");
}
+static int setup_sd_notify_child(void) {
+ static const int one = 1;
+ int fd = -1;
+ union sockaddr_union sa = {
+ .sa.sa_family = AF_UNIX,
+ };
+ int r;
+
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to allocate notification socket: %m");
+
+ (void) mkdir_parents(NSPAWN_NOTIFY_SOCKET_PATH, 0755);
+ (void) unlink(NSPAWN_NOTIFY_SOCKET_PATH);
+
+ strncpy(sa.un.sun_path, NSPAWN_NOTIFY_SOCKET_PATH, sizeof(sa.un.sun_path)-1);
+ r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
+ if (r < 0) {
+ safe_close(fd);
+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
+ }
+
+ r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
+ if (r < 0) {
+ safe_close(fd);
+ return log_error_errno(errno, "SO_PASSCRED failed: %m");
+ }
+
+ return fd;
+}
+
static int outer_child(
Barrier *barrier,
const char *directory,
@@ -2736,6 +2789,7 @@ static int outer_child(
bool secondary,
int pid_socket,
int uuid_socket,
+ int notify_socket,
int kmsg_socket,
int rtnl_socket,
int uid_shift_socket,
@@ -2744,12 +2798,14 @@ static int outer_child(
pid_t pid;
ssize_t l;
int r;
+ _cleanup_close_ int fd = -1;
assert(barrier);
assert(directory);
assert(console);
assert(pid_socket >= 0);
assert(uuid_socket >= 0);
+ assert(notify_socket >= 0);
assert(kmsg_socket >= 0);
cg_unified_flush();
@@ -2936,6 +2992,10 @@ static int outer_child(
if (r < 0)
return log_error_errno(r, "Failed to move root directory: %m");
+ fd = setup_sd_notify_child();
+ if (fd < 0)
+ return fd;
+
pid = raw_clone(SIGCHLD|CLONE_NEWNS|
(arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS) |
(arg_private_network ? CLONE_NEWNET : 0) |
@@ -2945,6 +3005,7 @@ static int outer_child(
if (pid == 0) {
pid_socket = safe_close(pid_socket);
uuid_socket = safe_close(uuid_socket);
+ notify_socket = safe_close(notify_socket);
uid_shift_socket = safe_close(uid_shift_socket);
/* The inner child has all namespaces that are
@@ -2974,8 +3035,13 @@ static int outer_child(
return -EIO;
}
+ l = send_one_fd(notify_socket, fd, 0);
+ if (l < 0)
+ return log_error_errno(errno, "Failed to send notify fd: %m");
+
pid_socket = safe_close(pid_socket);
uuid_socket = safe_close(uuid_socket);
+ notify_socket = safe_close(notify_socket);
kmsg_socket = safe_close(kmsg_socket);
rtnl_socket = safe_close(rtnl_socket);
@@ -3058,6 +3124,96 @@ static int setup_uid_map(pid_t pid) {
return 0;
}
+static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ _cleanup_fdset_free_ FDSet *fds = NULL;
+ char buf[NOTIFY_BUFFER_MAX+1];
+ char *p = NULL;
+ struct iovec iovec = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf)-1,
+ };
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
+ } control = {};
+ struct msghdr msghdr = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
+ struct ucred *ucred = NULL;
+ ssize_t n;
+ pid_t inner_child_pid;
+ _cleanup_strv_free_ char **tags = NULL;
+
+ assert(userdata);
+
+ inner_child_pid = PTR_TO_PID(userdata);
+
+ if (revents != EPOLLIN) {
+ log_warning("Got unexpected poll event for notify fd.");
+ return 0;
+ }
+
+ n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ if (n < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ return log_warning_errno(errno, "Couldn't read notification socket: %m");
+ }
+ cmsg_close_all(&msghdr);
+
+ CMSG_FOREACH(cmsg, &msghdr) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+
+ ucred = (struct ucred*) CMSG_DATA(cmsg);
+ }
+ }
+
+ if (!ucred || ucred->pid != inner_child_pid) {
+ log_warning("Received notify message without valid credentials. Ignoring.");
+ return 0;
+ }
+
+ if ((size_t) n >= sizeof(buf)) {
+ log_warning("Received notify message exceeded maximum size. Ignoring.");
+ return 0;
+ }
+
+ buf[n] = 0;
+ tags = strv_split(buf, "\n\r");
+ if (!tags)
+ return log_oom();
+
+ if (strv_find(tags, "READY=1"))
+ sd_notifyf(false, "READY=1\n");
+
+ p = strv_find_startswith(tags, "STATUS=");
+ if (p)
+ sd_notifyf(false, "STATUS=Container running: %s", p);
+
+ return 0;
+}
+
+static int setup_sd_notify_parent(sd_event *event, int fd, pid_t *inner_child_pid) {
+ int r;
+ sd_event_source *notify_event_source;
+
+ r = sd_event_add_io(event, &notify_event_source, fd, EPOLLIN, nspawn_dispatch_notify_fd, inner_child_pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate notify event source: %m");
+
+ (void) sd_event_source_set_description(notify_event_source, "nspawn-notify");
+
+ return 0;
+}
+
static int load_settings(void) {
_cleanup_(settings_freep) Settings *settings = NULL;
_cleanup_fclose_ FILE *f = NULL;
@@ -3286,6 +3442,9 @@ static int load_settings(void) {
}
}
+ if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0)
+ arg_notify_ready = settings->notify_ready;
+
return 0;
}
@@ -3536,7 +3695,9 @@ int main(int argc, char *argv[]) {
rtnl_socket_pair[2] = { -1, -1 },
pid_socket_pair[2] = { -1, -1 },
uuid_socket_pair[2] = { -1, -1 },
+ notify_socket_pair[2] = { -1, -1 },
uid_shift_socket_pair[2] = { -1, -1 };
+ _cleanup_close_ int notify_socket= -1;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
@@ -3587,6 +3748,11 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, notify_socket_pair) < 0) {
+ r = log_error_errno(errno, "Failed to create notify socket pair: %m");
+ goto finish;
+ }
+
if (arg_userns_mode != USER_NAMESPACE_NO)
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) {
r = log_error_errno(errno, "Failed to create uid shift socket pair: %m");
@@ -3628,6 +3794,7 @@ int main(int argc, char *argv[]) {
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
pid_socket_pair[0] = safe_close(pid_socket_pair[0]);
uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]);
+ notify_socket_pair[0] = safe_close(notify_socket_pair[0]);
uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]);
(void) reset_all_signal_handlers();
@@ -3643,6 +3810,7 @@ int main(int argc, char *argv[]) {
secondary,
pid_socket_pair[1],
uuid_socket_pair[1],
+ notify_socket_pair[1],
kmsg_socket_pair[1],
rtnl_socket_pair[1],
uid_shift_socket_pair[1],
@@ -3661,6 +3829,7 @@ int main(int argc, char *argv[]) {
rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
pid_socket_pair[1] = safe_close(pid_socket_pair[1]);
uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]);
+ notify_socket_pair[1] = safe_close(notify_socket_pair[1]);
uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]);
if (arg_userns_mode != USER_NAMESPACE_NO) {
@@ -3734,6 +3903,13 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ /* We also retrieve the socket used for notifications generated by outer child */
+ notify_socket = receive_one_fd(notify_socket_pair[0], 0);
+ if (notify_socket < 0) {
+ r = log_error_errno(errno, "Failed to receive notification socket from the outer child: %m");
+ goto finish;
+ }
+
log_debug("Init process invoked as PID " PID_FMT, pid);
if (arg_userns_mode != USER_NAMESPACE_NO) {
@@ -3848,6 +4024,16 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ r = sd_event_new(&event);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get default event source: %m");
+ goto finish;
+ }
+
+ r = setup_sd_notify_parent(event, notify_socket, PID_TO_PTR(pid));
+ if (r < 0)
+ goto finish;
+
/* Let the child know that we are ready and wait that the child is completely ready now. */
if (!barrier_place_and_sync(&barrier)) { /* #4 */
log_error("Child died too early.");
@@ -3860,15 +4046,10 @@ int main(int argc, char *argv[]) {
etc_passwd_lock = safe_close(etc_passwd_lock);
sd_notifyf(false,
- "READY=1\n"
"STATUS=Container running.\n"
"X_NSPAWN_LEADER_PID=" PID_FMT, pid);
-
- r = sd_event_new(&event);
- if (r < 0) {
- log_error_errno(r, "Failed to get default event source: %m");
- goto finish;
- }
+ if (!arg_notify_ready)
+ sd_notify(false, "READY=1\n");
if (arg_kill_signal > 0) {
/* Try to kill the init system on SIGINT or SIGTERM */
diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c
index 7e145c64c4..bc6dcf04a4 100644
--- a/src/resolve/resolve-tool.c
+++ b/src/resolve/resolve-tool.c
@@ -66,6 +66,7 @@ static enum {
MODE_RESOLVE_TLSA,
MODE_STATISTICS,
MODE_RESET_STATISTICS,
+ MODE_FLUSH_CACHES,
} arg_mode = MODE_RESOLVE_HOST;
static ServiceFamily service_family_from_string(const char *s) {
@@ -1037,6 +1038,24 @@ static int reset_statistics(sd_bus *bus) {
return 0;
}
+static int flush_caches(sd_bus *bus) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.resolve1",
+ "/org/freedesktop/resolve1",
+ "org.freedesktop.resolve1.Manager",
+ "FlushCaches",
+ &error,
+ NULL,
+ NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
static void help_protocol_types(void) {
if (arg_legend)
puts("Known protocol types:");
@@ -1097,6 +1116,7 @@ static void help(void) {
" --legend=BOOL Print headers and additional info (default: yes)\n"
" --statistics Show resolver statistics\n"
" --reset-statistics Reset resolver statistics\n"
+ " --flush-caches Flush all local DNS caches\n"
, program_invocation_short_name);
}
@@ -1114,6 +1134,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SEARCH,
ARG_STATISTICS,
ARG_RESET_STATISTICS,
+ ARG_FLUSH_CACHES,
};
static const struct option options[] = {
@@ -1134,6 +1155,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "search", required_argument, NULL, ARG_SEARCH },
{ "statistics", no_argument, NULL, ARG_STATISTICS, },
{ "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
+ { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
{}
};
@@ -1307,6 +1329,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_mode = MODE_RESET_STATISTICS;
break;
+ case ARG_FLUSH_CACHES:
+ arg_mode = MODE_FLUSH_CACHES;
+ break;
+
case '?':
return -EINVAL;
@@ -1473,6 +1499,16 @@ int main(int argc, char **argv) {
r = reset_statistics(bus);
break;
+
+ case MODE_FLUSH_CACHES:
+ if (argc > optind) {
+ log_error("Too many arguments.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ r = flush_caches(bus);
+ break;
}
finish:
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 33f7c61557..6d86cbf123 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -1221,7 +1221,7 @@ int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex
return r;
if (with_ifindex) {
- r = sd_bus_message_append(reply, "i", s->link ? s->link->ifindex : 0);
+ r = sd_bus_message_append(reply, "i", dns_server_ifindex(s));
if (r < 0)
return r;
}
@@ -1442,26 +1442,6 @@ static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error
return 0;
}
-static int get_unmanaged_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) {
- Link *l;
- int r;
-
- assert(m);
- assert(ret);
-
- r = get_any_link(m, ifindex, &l, error);
- if (r < 0)
- return r;
-
- if (l->flags & IFF_LOOPBACK)
- return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name);
- if (l->is_managed)
- return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name);
-
- *ret = l;
- return 0;
-}
-
static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
int ifindex, r;
Link *l;
@@ -1475,7 +1455,7 @@ static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_
if (r < 0)
return r;
- r = get_unmanaged_link(m, ifindex, &l, error);
+ r = get_any_link(m, ifindex, &l, error);
if (r < 0)
return r;
@@ -1535,6 +1515,17 @@ static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_e
return sd_bus_reply_method_return(message, "o", p);
}
+static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ assert(message);
+ assert(m);
+
+ manager_flush_caches(m);
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
@@ -1550,6 +1541,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
+ SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, 0),
SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0),
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 990dc03b60..fecf7ecccf 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -27,18 +27,18 @@
int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) {
union in_addr_union address;
- int family, r;
+ int family, r, ifindex = 0;
DnsServer *s;
assert(m);
assert(word);
- r = in_addr_from_string_auto(word, &family, &address);
+ r = in_addr_ifindex_from_string_auto(word, &family, &address, &ifindex);
if (r < 0)
return r;
/* Filter out duplicates */
- s = dns_server_find(manager_get_first_dns_server(m, type), family, &address);
+ s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, ifindex);
if (s) {
/*
* Drop the marker. This is used to find the servers
@@ -50,7 +50,7 @@ int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char
return 0;
}
- return dns_server_new(m, NULL, type, NULL, family, &address);
+ return dns_server_new(m, NULL, type, NULL, family, &address, ifindex);
}
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
@@ -70,7 +70,7 @@ int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, con
r = manager_add_dns_server_by_string(m, type, word);
if (r < 0)
- log_warning_errno(r, "Failed to add DNS server address '%s', ignoring.", word);
+ log_warning_errno(r, "Failed to add DNS server address '%s', ignoring: %m", word);
}
return 0;
@@ -125,7 +125,7 @@ int manager_parse_search_domains_and_warn(Manager *m, const char *string) {
r = manager_add_search_domain_by_string(m, word);
if (r < 0)
- log_warning_errno(r, "Failed to add search domain '%s', ignoring.", word);
+ log_warning_errno(r, "Failed to add search domain '%s', ignoring: %m", word);
}
return 0;
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 66e4585c18..6a69d7b7c2 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -307,7 +307,7 @@ static int dns_scope_socket(
union sockaddr_union sa = {};
socklen_t salen;
static const int one = 1;
- int ret, r;
+ int ret, r, ifindex;
assert(s);
@@ -315,6 +315,8 @@ static int dns_scope_socket(
assert(family == AF_UNSPEC);
assert(!address);
+ ifindex = dns_server_ifindex(server);
+
sa.sa.sa_family = server->family;
if (server->family == AF_INET) {
sa.in.sin_port = htobe16(port);
@@ -323,7 +325,7 @@ static int dns_scope_socket(
} else if (server->family == AF_INET6) {
sa.in6.sin6_port = htobe16(port);
sa.in6.sin6_addr = server->address.in6;
- sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
+ sa.in6.sin6_scope_id = ifindex;
salen = sizeof(sa.in6);
} else
return -EAFNOSUPPORT;
@@ -332,6 +334,7 @@ static int dns_scope_socket(
assert(address);
sa.sa.sa_family = family;
+ ifindex = s->link ? s->link->ifindex : 0;
if (family == AF_INET) {
sa.in.sin_port = htobe16(port);
@@ -340,7 +343,7 @@ static int dns_scope_socket(
} else if (family == AF_INET6) {
sa.in6.sin6_port = htobe16(port);
sa.in6.sin6_addr = address->in6;
- sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
+ sa.in6.sin6_scope_id = ifindex;
salen = sizeof(sa.in6);
} else
return -EAFNOSUPPORT;
@@ -357,14 +360,14 @@ static int dns_scope_socket(
}
if (s->link) {
- uint32_t ifindex = htobe32(s->link->ifindex);
+ be32_t ifindex_be = htobe32(ifindex);
if (sa.sa.sa_family == AF_INET) {
- r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
+ r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be));
if (r < 0)
return -errno;
} else if (sa.sa.sa_family == AF_INET6) {
- r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
+ r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be));
if (r < 0)
return -errno;
}
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 3095c042db..5acfcb4239 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -43,7 +43,8 @@ int dns_server_new(
DnsServerType type,
Link *l,
int family,
- const union in_addr_union *in_addr) {
+ const union in_addr_union *in_addr,
+ int ifindex) {
DnsServer *s;
@@ -75,6 +76,7 @@ int dns_server_new(
s->type = type;
s->family = family;
s->address = *in_addr;
+ s->ifindex = ifindex;
s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
switch (type) {
@@ -518,11 +520,24 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature
return dns_packet_append_opt(packet, packet_size, edns_do, NULL);
}
+int dns_server_ifindex(const DnsServer *s) {
+ assert(s);
+
+ /* The link ifindex always takes precedence */
+ if (s->link)
+ return s->link->ifindex;
+
+ if (s->ifindex > 0)
+ return s->ifindex;
+
+ return 0;
+}
+
const char *dns_server_string(DnsServer *server) {
assert(server);
if (!server->server_string)
- (void) in_addr_to_string(server->family, &server->address, &server->server_string);
+ (void) in_addr_ifindex_to_string(server->family, &server->address, dns_server_ifindex(server), &server->server_string);
return strna(server->server_string);
}
@@ -571,17 +586,28 @@ static void dns_server_hash_func(const void *p, struct siphash *state) {
siphash24_compress(&s->family, sizeof(s->family), state);
siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
+ siphash24_compress(&s->ifindex, sizeof(s->ifindex), state);
}
static int dns_server_compare_func(const void *a, const void *b) {
const DnsServer *x = a, *y = b;
+ int r;
if (x->family < y->family)
return -1;
if (x->family > y->family)
return 1;
- return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
+ r = memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
+ if (r != 0)
+ return r;
+
+ if (x->ifindex < y->ifindex)
+ return -1;
+ if (x->ifindex > y->ifindex)
+ return 1;
+
+ return 0;
}
const struct hash_ops dns_server_hash_ops = {
@@ -623,11 +649,11 @@ void dns_server_mark_all(DnsServer *first) {
dns_server_mark_all(first->servers_next);
}
-DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr) {
+DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex) {
DnsServer *s;
LIST_FOREACH(servers, s, first)
- if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
+ if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0 && s->ifindex == ifindex)
return s;
return NULL;
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index 9f4a69c37a..463c5724a7 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -62,6 +62,7 @@ struct DnsServer {
int family;
union in_addr_union address;
+ int ifindex; /* for IPv6 link-local DNS servers */
char *server_string;
@@ -101,7 +102,8 @@ int dns_server_new(
DnsServerType type,
Link *link,
int family,
- const union in_addr_union *address);
+ const union in_addr_union *address,
+ int ifindex);
DnsServer* dns_server_ref(DnsServer *s);
DnsServer* dns_server_unref(DnsServer *s);
@@ -121,12 +123,13 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s);
int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level);
const char *dns_server_string(DnsServer *server);
+int dns_server_ifindex(const DnsServer *s);
bool dns_server_dnssec_supported(DnsServer *server);
void dns_server_warn_downgrade(DnsServer *server);
-DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr);
+DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex);
void dns_server_unlink_all(DnsServer *first);
void dns_server_unlink_marked(DnsServer *first);
diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c
index 7f21891819..bfb87d78e7 100644
--- a/src/resolve/resolved-link-bus.c
+++ b/src/resolve/resolved-link-bus.c
@@ -18,11 +18,13 @@
***/
#include "alloc-util.h"
+#include "bus-common-errors.h"
#include "bus-util.h"
#include "parse-util.h"
#include "resolve-util.h"
#include "resolved-bus.h"
#include "resolved-link-bus.h"
+#include "resolved-resolv-conf.h"
#include "strv.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support, resolve_support, ResolveSupport);
@@ -157,6 +159,17 @@ static int property_get_dnssec_supported(
return sd_bus_message_append(reply, "b", link_dnssec_supported(l));
}
+static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
+ assert(l);
+
+ if (l->flags & IFF_LOOPBACK)
+ return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name);
+ if (l->is_managed)
+ return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name);
+
+ return 0;
+}
+
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ struct in_addr_data *dns = NULL;
size_t allocated = 0, n = 0;
@@ -167,6 +180,10 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
assert(message);
assert(l);
+ r = verify_unmanaged_link(l, error);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_enter_container(message, 'a', "(iay)");
if (r < 0)
return r;
@@ -218,11 +235,11 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
for (i = 0; i < n; i++) {
DnsServer *s;
- s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address);
+ s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0);
if (s)
dns_server_move_back_and_unmark(s);
else {
- r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address);
+ r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0);
if (r < 0)
goto clear;
}
@@ -232,6 +249,8 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
dns_server_unlink_marked(l->dns_servers);
link_allocate_scopes(l);
+ (void) manager_write_resolv_conf(l->manager);
+
return sd_bus_reply_method_return(message, NULL);
clear:
@@ -246,6 +265,10 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
assert(message);
assert(l);
+ r = verify_unmanaged_link(l, error);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_enter_container(message, 'a', "(sb)");
if (r < 0)
return r;
@@ -306,6 +329,9 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
goto clear;
dns_search_domain_unlink_marked(l->search_domains);
+
+ (void) manager_write_resolv_conf(l->manager);
+
return sd_bus_reply_method_return(message, NULL);
clear:
@@ -322,6 +348,10 @@ int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_er
assert(message);
assert(l);
+ r = verify_unmanaged_link(l, error);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_read(message, "s", &llmnr);
if (r < 0)
return r;
@@ -350,6 +380,10 @@ int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_err
assert(message);
assert(l);
+ r = verify_unmanaged_link(l, error);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_read(message, "s", &mdns);
if (r < 0)
return r;
@@ -378,6 +412,10 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e
assert(message);
assert(l);
+ r = verify_unmanaged_link(l, error);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_read(message, "s", &dnssec);
if (r < 0)
return r;
@@ -405,6 +443,10 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
assert(message);
assert(l);
+ r = verify_unmanaged_link(l, error);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_read_strv(message, &ntas);
if (r < 0)
return r;
@@ -436,14 +478,21 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Link *l = userdata;
+ int r;
assert(message);
assert(l);
+ r = verify_unmanaged_link(l, error);
+ if (r < 0)
+ return r;
+
link_flush_settings(l);
link_allocate_scopes(l);
link_add_rrs(l, false);
+ (void) manager_write_resolv_conf(l->manager);
+
return sd_bus_reply_method_return(message, NULL);
}
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index b0dc65036d..b189c21920 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -216,11 +216,11 @@ static int link_update_dns_servers(Link *l) {
if (r < 0)
goto clear;
- s = dns_server_find(l->dns_servers, family, &a);
+ s = dns_server_find(l->dns_servers, family, &a, 0);
if (s)
dns_server_move_back_and_unmark(s);
else {
- r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
+ r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0);
if (r < 0)
goto clear;
}
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 9600bde1e9..23101cb760 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -284,9 +284,7 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *
log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
}
- r = manager_write_resolv_conf(m);
- if (r < 0)
- log_warning_errno(r, "Could not update "PRIVATE_RESOLV_CONF": %m");
+ (void) manager_write_resolv_conf(m);
return 0;
}
@@ -468,6 +466,18 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si
return 0;
}
+static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *m = userdata;
+
+ assert(s);
+ assert(si);
+ assert(m);
+
+ manager_flush_caches(m);
+
+ return 0;
+}
+
int manager_new(Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@@ -528,6 +538,7 @@ int manager_new(Manager **ret) {
return r;
(void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
+ (void) sd_event_add_signal(m->event, &m->sigusr2_event_source, SIGUSR2, manager_sigusr2, m);
*ret = m;
m = NULL;
@@ -586,6 +597,7 @@ Manager *manager_free(Manager *m) {
sd_bus_unref(m->bus);
sd_event_source_unref(m->sigusr1_event_source);
+ sd_event_source_unref(m->sigusr2_event_source);
sd_event_unref(m->event);
@@ -903,7 +915,7 @@ int manager_send(Manager *m, int fd, int ifindex, int family, const union in_add
if (family == AF_INET)
return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p);
- else if (family == AF_INET6)
+ if (family == AF_INET6)
return manager_ipv6_send(m, fd, ifindex, &addr->in6, port, p);
return -EAFNOSUPPORT;
@@ -1236,3 +1248,14 @@ bool manager_routable(Manager *m, int family) {
return false;
}
+
+void manager_flush_caches(Manager *m) {
+ DnsScope *scope;
+
+ assert(m);
+
+ LIST_FOREACH(scopes, scope, m->dns_scopes)
+ dns_cache_flush(&scope->cache);
+
+ log_info("Flushed all caches.");
+}
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index e82a824f29..ef71202ef9 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -120,6 +120,7 @@ struct Manager {
sd_bus_slot *prepare_for_sleep_slot;
sd_event_source *sigusr1_event_source;
+ sd_event_source *sigusr2_event_source;
unsigned n_transactions_total;
unsigned n_dnssec_verdict[_DNSSEC_VERDICT_MAX];
@@ -169,3 +170,5 @@ bool manager_dnssec_supported(Manager *m);
void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key);
bool manager_routable(Manager *m, int family);
+
+void manager_flush_caches(Manager *m);
diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c
index fa89de4c21..ae17aef3ab 100644
--- a/src/resolve/resolved-resolv-conf.c
+++ b/src/resolve/resolved-resolv-conf.c
@@ -92,7 +92,7 @@ int manager_read_resolv_conf(Manager *m) {
a = first_word(l, "nameserver");
if (a) {
- r = manager_add_dns_server_by_string(m, DNS_SERVER_SYSTEM, a);
+ r = manager_parse_dns_server_string_and_warn(m, DNS_SERVER_SYSTEM, a);
if (r < 0)
log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a);
@@ -149,9 +149,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
assert(f);
assert(count);
- (void) dns_server_string(s);
-
- if (!s->server_string) {
+ if (!dns_server_string(s)) {
log_warning("Our of memory, or invalid DNS address. Ignoring server.");
return;
}
@@ -160,7 +158,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
(*count)++;
- fprintf(f, "nameserver %s\n", s->server_string);
+ fprintf(f, "nameserver %s\n", dns_server_string(s));
}
static void write_resolv_conf_search(
@@ -227,29 +225,31 @@ int manager_write_resolv_conf(Manager *m) {
assert(m);
/* Read the system /etc/resolv.conf first */
- manager_read_resolv_conf(m);
+ (void) manager_read_resolv_conf(m);
/* Add the full list to a set, to filter out duplicates */
r = manager_compile_dns_servers(m, &dns);
if (r < 0)
- return r;
+ return log_warning_errno(r, "Failed to compile list of DNS servers: %m");
r = manager_compile_search_domains(m, &domains);
if (r < 0)
- return r;
+ return log_warning_errno(r, "Failed to compile list of search domains: %m");
r = fopen_temporary_label(PRIVATE_RESOLV_CONF, PRIVATE_RESOLV_CONF, &f, &temp_path);
if (r < 0)
- return r;
+ return log_warning_errno(r, "Failed to open private resolv.conf file for writing: %m");
- fchmod(fileno(f), 0644);
+ (void) fchmod(fileno(f), 0644);
r = write_resolv_conf_contents(f, dns, domains);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to write private resolv.conf contents: %m");
goto fail;
+ }
if (rename(temp_path, PRIVATE_RESOLV_CONF) < 0) {
- r = -errno;
+ r = log_error_errno(errno, "Failed to move private resolv.conf file into place: %m");
goto fail;
}
@@ -258,5 +258,6 @@ int manager_write_resolv_conf(Manager *m) {
fail:
(void) unlink(PRIVATE_RESOLV_CONF);
(void) unlink(temp_path);
+
return r;
}
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index 161ea03412..3a47b82d8a 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -71,7 +71,7 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, -1) >= 0);
r = manager_new(&m);
if (r < 0) {
@@ -85,11 +85,8 @@ int main(int argc, char *argv[]) {
goto finish;
}
- /* Write finish default resolv.conf to avoid a dangling
- * symlink */
- r = manager_write_resolv_conf(m);
- if (r < 0)
- log_warning_errno(r, "Could not create "PRIVATE_RESOLV_CONF": %m");
+ /* Write finish default resolv.conf to avoid a dangling symlink */
+ (void) manager_write_resolv_conf(m);
sd_notify(false,
"READY=1\n"
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 4efbf3710f..8cfa936347 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -1085,6 +1085,19 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
break;
}
+ case SD_BUS_TYPE_DOUBLE: {
+ double d;
+ double *p = userdata;
+
+ r = sd_bus_message_read_basic(m, type, &d);
+ if (r < 0)
+ break;
+
+ *p = d;
+
+ break;
+ }
+
default:
break;
}
diff --git a/src/shared/vlan-util.c b/src/shared/vlan-util.c
new file mode 100644
index 0000000000..78d66dd3d9
--- /dev/null
+++ b/src/shared/vlan-util.c
@@ -0,0 +1,69 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "vlan-util.h"
+#include "parse-util.h"
+#include "conf-parser.h"
+
+int parse_vlanid(const char *p, uint16_t *ret) {
+ uint16_t id;
+ int r;
+
+ r = safe_atou16(p, &id);
+ if (r < 0)
+ return r;
+ if (!vlanid_is_valid(id))
+ return -ERANGE;
+
+ *ret = id;
+ return 0;
+}
+
+int config_parse_vlanid(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ uint16_t *id = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = parse_vlanid(rvalue, id);
+ if (r == -ERANGE) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "VLAN identifier outside of valid range 0…4094, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VLAN identifier value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/src/shared/vlan-util.h b/src/shared/vlan-util.h
new file mode 100644
index 0000000000..ce6763b3a3
--- /dev/null
+++ b/src/shared/vlan-util.h
@@ -0,0 +1,35 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <inttypes.h>
+
+#define VLANID_MAX 4094
+#define VLANID_INVALID UINT16_MAX
+
+/* Note that we permit VLAN Id 0 here, as that is apparently OK by the Linux kernel */
+static inline bool vlanid_is_valid(uint16_t id) {
+ return id <= VLANID_MAX;
+}
+
+int parse_vlanid(const char *p, uint16_t *ret);
+
+int config_parse_vlanid(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index df41182529..784c1cd7b5 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -174,6 +174,7 @@ static bool arg_firmware_setup = false;
static bool arg_now = false;
static int daemon_reload(int argc, char *argv[], void* userdata);
+static int trivial_method(int argc, char *argv[], void *userdata);
static int halt_now(enum action a);
static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state);
@@ -2283,7 +2284,7 @@ static int cancel_job(int argc, char *argv[], void *userdata) {
int r = 0;
if (argc <= 1)
- return daemon_reload(argc, argv, userdata);
+ return trivial_method(argc, argv, userdata);
polkit_agent_open_if_enabled();
@@ -2693,10 +2694,9 @@ static int start_unit_one(
if (r < 0) {
const char *verb;
- if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
- /* There's always a fallback possible for
- * legacy actions. */
- return -EADDRNOTAVAIL;
+ /* There's always a fallback possible for legacy actions. */
+ if (arg_action != ACTION_SYSTEMCTL)
+ return r;
verb = method_to_verb(method);
@@ -3252,7 +3252,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
ACTION_REBOOT,
ACTION_KEXEC,
ACTION_EXIT))
- return daemon_reload(argc, argv, userdata);
+ return trivial_method(argc, argv, userdata);
/* First try logind, to allow authentication with polkit */
if (IN_SET(a,
@@ -3274,6 +3274,18 @@ static int start_special(int argc, char *argv[], void *userdata) {
return start_unit(argc, argv, userdata);
}
+static int start_system_special(int argc, char *argv[], void *userdata) {
+ /* Like start_special above, but raises an error when running in user mode */
+
+ if (arg_scope != UNIT_FILE_SYSTEM) {
+ log_error("Bad action for %s mode.",
+ arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
+ return -EINVAL;
+ }
+
+ return start_special(argc, argv, userdata);
+}
+
static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) {
_cleanup_strv_free_ char **names = NULL;
UnitActiveState active_state;
@@ -5053,6 +5065,7 @@ static int set_property(int argc, char *argv[], void *userdata) {
static int daemon_reload(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
const char *method;
sd_bus *bus;
int r;
@@ -5063,26 +5076,76 @@ static int daemon_reload(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- if (arg_action == ACTION_RELOAD)
+ switch (arg_action) {
+
+ case ACTION_RELOAD:
method = "Reload";
- else if (arg_action == ACTION_REEXEC)
+ break;
+
+ case ACTION_REEXEC:
method = "Reexecute";
- else {
- assert(arg_action == ACTION_SYSTEMCTL);
+ break;
- method =
- streq(argv[0], "clear-jobs") ||
- streq(argv[0], "cancel") ? "ClearJobs" :
- streq(argv[0], "daemon-reexec") ? "Reexecute" :
- streq(argv[0], "reset-failed") ? "ResetFailed" :
- streq(argv[0], "halt") ? "Halt" :
- streq(argv[0], "poweroff") ? "PowerOff" :
- streq(argv[0], "reboot") ? "Reboot" :
- streq(argv[0], "kexec") ? "KExec" :
- streq(argv[0], "exit") ? "Exit" :
- /* "daemon-reload" */ "Reload";
+ case ACTION_SYSTEMCTL:
+ method = streq(argv[0], "daemon-reexec") ? "Reexecute" :
+ /* "daemon-reload" */ "Reload";
+ break;
+
+ default:
+ assert_not_reached("Unexpected action");
}
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
+ * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
+ * their timeout, and for everything else there's the same time budget in place. */
+
+ r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
+
+ /* On reexecution, we expect a disconnect, not a reply */
+ if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && streq(method, "Reexecute"))
+ r = 0;
+
+ if (r < 0 && arg_action == ACTION_SYSTEMCTL)
+ return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
+
+ /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
+ * old ways of doing things, hence don't log any error in that case here. */
+
+ return r < 0 ? r : 0;
+}
+
+static int trivial_method(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ const char *method;
+ sd_bus *bus;
+ int r;
+
+ polkit_agent_open_if_enabled();
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ method =
+ streq(argv[0], "clear-jobs") ||
+ streq(argv[0], "cancel") ? "ClearJobs" :
+ streq(argv[0], "reset-failed") ? "ResetFailed" :
+ streq(argv[0], "halt") ? "Halt" :
+ streq(argv[0], "reboot") ? "Reboot" :
+ streq(argv[0], "kexec") ? "KExec" :
+ streq(argv[0], "exit") ? "Exit" :
+ /* poweroff */ "PowerOff";
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -5092,16 +5155,11 @@ static int daemon_reload(int argc, char *argv[], void *userdata) {
&error,
NULL,
NULL);
- if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
- /* There's always a fallback possible for
- * legacy actions. */
- r = -EADDRNOTAVAIL;
- else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
- /* On reexecution, we expect a disconnect, not a
- * reply */
- r = 0;
- else if (r < 0)
- return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
+ if (r < 0 && arg_action == ACTION_SYSTEMCTL)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+
+ /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
+ * old ways of doing things, hence don't log any error in that case here. */
return r < 0 ? r : 0;
}
@@ -5113,7 +5171,7 @@ static int reset_failed(int argc, char *argv[], void *userdata) {
int r, q;
if (argc <= 1)
- return daemon_reload(argc, argv, userdata);
+ return trivial_method(argc, argv, userdata);
polkit_agent_open_if_enabled();
@@ -7493,71 +7551,71 @@ static int systemctl_main(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_NOCHROOT, list_units },
- { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
- { "list-sockets", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_sockets },
- { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers },
- { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs },
- { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines },
- { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
- { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job },
- { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "condstop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
- { "reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "reload-or-try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatbility with old systemctl <= 228 */
- { "try-reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "force-reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with SysV */
- { "condreload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
- { "condrestart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with RH */
- { "isolate", 2, 2, VERB_NOCHROOT, start_unit },
- { "kill", 2, VERB_ANY, VERB_NOCHROOT, kill_unit },
- { "is-active", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
- { "check", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
- { "is-failed", 2, VERB_ANY, VERB_NOCHROOT, check_unit_failed },
- { "show", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
- { "cat", 2, VERB_ANY, VERB_NOCHROOT, cat },
- { "status", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
- { "help", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
- { "daemon-reload", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
- { "daemon-reexec", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
- { "show-environment", VERB_ANY, 1, VERB_NOCHROOT, show_environment },
- { "set-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
- { "unset-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
- { "import-environment", VERB_ANY, VERB_ANY, VERB_NOCHROOT, import_environment},
- { "halt", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "poweroff", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "reboot", VERB_ANY, 2, VERB_NOCHROOT, start_special },
- { "kexec", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "suspend", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "hibernate", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "hybrid-sleep", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "default", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "rescue", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "emergency", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "exit", VERB_ANY, 2, VERB_NOCHROOT, start_special },
- { "reset-failed", VERB_ANY, VERB_ANY, VERB_NOCHROOT, reset_failed },
- { "enable", 2, VERB_ANY, 0, enable_unit },
- { "disable", 2, VERB_ANY, 0, enable_unit },
- { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
- { "reenable", 2, VERB_ANY, 0, enable_unit },
- { "preset", 2, VERB_ANY, 0, enable_unit },
- { "preset-all", VERB_ANY, 1, 0, preset_all },
- { "mask", 2, VERB_ANY, 0, enable_unit },
- { "unmask", 2, VERB_ANY, 0, enable_unit },
- { "link", 2, VERB_ANY, 0, enable_unit },
- { "revert", 2, VERB_ANY, 0, enable_unit },
- { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root },
- { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies },
- { "set-default", 2, 2, 0, set_default },
- { "get-default", VERB_ANY, 1, 0, get_default },
- { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property },
- { "is-system-running", VERB_ANY, 1, 0, is_system_running },
- { "add-wants", 3, VERB_ANY, 0, add_dependency },
- { "add-requires", 3, VERB_ANY, 0, add_dependency },
- { "edit", 2, VERB_ANY, VERB_NOCHROOT, edit },
+ { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
+ { "list-sockets", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_sockets },
+ { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers },
+ { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs },
+ { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines },
+ { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, trivial_method },
+ { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job },
+ { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "condstop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
+ { "reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "reload-or-try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatbility with old systemctl <= 228 */
+ { "try-reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "force-reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with SysV */
+ { "condreload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
+ { "condrestart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with RH */
+ { "isolate", 2, 2, VERB_NOCHROOT, start_unit },
+ { "kill", 2, VERB_ANY, VERB_NOCHROOT, kill_unit },
+ { "is-active", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
+ { "check", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
+ { "is-failed", 2, VERB_ANY, VERB_NOCHROOT, check_unit_failed },
+ { "show", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
+ { "cat", 2, VERB_ANY, VERB_NOCHROOT, cat },
+ { "status", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
+ { "help", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
+ { "daemon-reload", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
+ { "daemon-reexec", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
+ { "show-environment", VERB_ANY, 1, VERB_NOCHROOT, show_environment },
+ { "set-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
+ { "unset-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
+ { "import-environment", VERB_ANY, VERB_ANY, VERB_NOCHROOT, import_environment },
+ { "halt", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "poweroff", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "reboot", VERB_ANY, 2, VERB_NOCHROOT, start_system_special },
+ { "kexec", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "suspend", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "hibernate", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "hybrid-sleep", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "default", VERB_ANY, 1, VERB_NOCHROOT, start_special },
+ { "rescue", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "emergency", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "exit", VERB_ANY, 2, VERB_NOCHROOT, start_special },
+ { "reset-failed", VERB_ANY, VERB_ANY, VERB_NOCHROOT, reset_failed },
+ { "enable", 2, VERB_ANY, 0, enable_unit },
+ { "disable", 2, VERB_ANY, 0, enable_unit },
+ { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
+ { "reenable", 2, VERB_ANY, 0, enable_unit },
+ { "preset", 2, VERB_ANY, 0, enable_unit },
+ { "preset-all", VERB_ANY, 1, 0, preset_all },
+ { "mask", 2, VERB_ANY, 0, enable_unit },
+ { "unmask", 2, VERB_ANY, 0, enable_unit },
+ { "link", 2, VERB_ANY, 0, enable_unit },
+ { "revert", 2, VERB_ANY, 0, enable_unit },
+ { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root },
+ { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies },
+ { "set-default", 2, 2, 0, set_default },
+ { "get-default", VERB_ANY, 1, 0, get_default },
+ { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property },
+ { "is-system-running", VERB_ANY, 1, 0, is_system_running },
+ { "add-wants", 3, VERB_ANY, 0, add_dependency },
+ { "add-requires", 3, VERB_ANY, 0, add_dependency },
+ { "edit", 2, VERB_ANY, VERB_NOCHROOT, edit },
{}
};
@@ -7571,7 +7629,7 @@ static int reload_with_fallback(void) {
return 0;
/* Nothing else worked, so let's try signals */
- assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
+ assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
return log_error_errno(errno, "kill() failed: %m");
@@ -7585,8 +7643,7 @@ static int start_with_fallback(void) {
if (start_unit(0, NULL, NULL) >= 0)
return 0;
- /* Nothing else worked, so let's try
- * /dev/initctl */
+ /* Nothing else worked, so let's try /dev/initctl */
if (talk_initctl() > 0)
return 0;
diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h
index 5772d5794a..3f35eebea3 100644
--- a/src/systemd/sd-lldp.h
+++ b/src/systemd/sd-lldp.h
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <net/ethernet.h>
+#include <sys/types.h>
#include "sd-event.h"
@@ -30,9 +31,6 @@
_SD_BEGIN_DECLARATIONS;
-typedef struct sd_lldp sd_lldp;
-typedef struct sd_lldp_neighbor sd_lldp_neighbor;
-
/* IEEE 802.3AB Clause 9: TLV Types */
enum {
SD_LLDP_TYPE_END = 0,
@@ -111,6 +109,9 @@ enum {
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7,
};
+typedef struct sd_lldp sd_lldp;
+typedef struct sd_lldp_neighbor sd_lldp_neighbor;
+
typedef enum sd_lldp_event {
SD_LLDP_EVENT_ADDED = 'a',
SD_LLDP_EVENT_REMOVED = 'r',
@@ -120,7 +121,8 @@ typedef enum sd_lldp_event {
typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata);
-int sd_lldp_new(sd_lldp **ret, int ifindex);
+int sd_lldp_new(sd_lldp **ret);
+sd_lldp* sd_lldp_ref(sd_lldp *lldp);
sd_lldp* sd_lldp_unref(sd_lldp *lldp);
int sd_lldp_start(sd_lldp *lldp);
@@ -128,8 +130,10 @@ int sd_lldp_stop(sd_lldp *lldp);
int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority);
int sd_lldp_detach_event(sd_lldp *lldp);
+sd_event *sd_lldp_get_event(sd_lldp *lldp);
int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata);
+int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex);
/* Controls how much and what to store in the neighbors database */
int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n);
@@ -145,6 +149,7 @@ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n);
/* Access to LLDP frame metadata */
int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address);
int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address);
+int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret);
int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
/* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */
@@ -152,7 +157,7 @@ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const vo
int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret);
int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size);
int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret);
-int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret);
+int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec);
int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret);
int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret);
int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret);
diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h
index 2b774233b8..9f7d4ef71a 100644
--- a/src/systemd/sd-ndisc.h
+++ b/src/systemd/sd-ndisc.h
@@ -22,6 +22,8 @@
#include <inttypes.h>
#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <sys/types.h>
#include "sd-event.h"
@@ -29,55 +31,99 @@
_SD_BEGIN_DECLARATIONS;
+/* Neightbor Discovery Options, RFC 4861, Section 4.6 and
+ * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */
enum {
- SD_NDISC_EVENT_STOP = 0,
- SD_NDISC_EVENT_TIMEOUT = 1,
+ SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1,
+ SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2,
+ SD_NDISC_OPTION_PREFIX_INFORMATION = 3,
+ SD_NDISC_OPTION_MTU = 5,
+ SD_NDISC_OPTION_ROUTE_INFORMATION = 24,
+ SD_NDISC_OPTION_RDNSS = 25,
+ SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
+ SD_NDISC_OPTION_DNSSL = 31,
+ SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
+};
+
+/* Route preference, RFC 4191, Section 2.1 */
+enum {
+ SD_NDISC_PREFERENCE_LOW = 3U,
+ SD_NDISC_PREFERENCE_MEDIUM = 0U,
+ SD_NDISC_PREFERENCE_HIGH = 1U,
};
typedef struct sd_ndisc sd_ndisc;
+typedef struct sd_ndisc_router sd_ndisc_router;
-typedef void(*sd_ndisc_router_callback_t)(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata);
-typedef void(*sd_ndisc_prefix_onlink_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
- unsigned lifetime, void *userdata);
-typedef void(*sd_ndisc_prefix_autonomous_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
- unsigned lifetime_prefered, unsigned lifetime_valid, void *userdata);
-typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event, void *userdata);
-
-int sd_ndisc_set_callback(sd_ndisc *nd,
- sd_ndisc_router_callback_t rcb,
- sd_ndisc_prefix_onlink_callback_t plcb,
- sd_ndisc_prefix_autonomous_callback_t pacb,
- sd_ndisc_callback_t cb,
- void *userdata);
-int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index);
-int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
+typedef enum sd_ndisc_event {
+ SD_NDISC_EVENT_TIMEOUT = 't',
+ SD_NDISC_EVENT_ROUTER = 'r',
+} sd_ndisc_event;
-int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
-int sd_ndisc_detach_event(sd_ndisc *nd);
-sd_event *sd_ndisc_get_event(sd_ndisc *nd);
+typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata);
+int sd_ndisc_new(sd_ndisc **ret);
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
-int sd_ndisc_new(sd_ndisc **ret);
-
-int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu);
+int sd_ndisc_start(sd_ndisc *nd);
int sd_ndisc_stop(sd_ndisc *nd);
-int sd_ndisc_router_discovery_start(sd_ndisc *nd);
-#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
+int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
+int sd_ndisc_detach_event(sd_ndisc *nd);
+sd_event *sd_ndisc_get_event(sd_ndisc *nd);
+
+int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, void *userdata);
+int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index);
+int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
-#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \
- be16toh((address).s6_addr16[0]), \
- be16toh((address).s6_addr16[1]), \
- be16toh((address).s6_addr16[2]), \
- be16toh((address).s6_addr16[3]), \
- be16toh((address).s6_addr16[4]), \
- be16toh((address).s6_addr16[5]), \
- be16toh((address).s6_addr16[6]), \
- be16toh((address).s6_addr16[7])
+int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *ret);
+int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret);
+
+int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size);
+sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
+sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
+
+int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr);
+int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
+int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size);
+
+int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
+int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags);
+int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
+int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime);
+int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret);
+
+/* Generic option access */
+int sd_ndisc_router_option_rewind(sd_ndisc_router *rt);
+int sd_ndisc_router_option_next(sd_ndisc_router *rt);
+int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret);
+int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type);
+int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size);
+
+/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */
+int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret);
+int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret);
+int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret);
+int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr);
+int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen);
+
+/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */
+int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret);
+int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr);
+int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen);
+int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret);
+
+/* Specific option access: SD_NDISC_OPTION_RDNSS */
+int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret);
+int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret);
+
+/* Specific option access: SD_NDISC_OPTION_DNSSL */
+int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret);
+int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref);
_SD_END_DECLARATIONS;
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index 3ae110c080..7efa8ebe5a 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -43,7 +43,7 @@ typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *
int sd_netlink_new_from_netlink(sd_netlink **nl, int fd);
int sd_netlink_open(sd_netlink **nl);
int sd_netlink_open_fd(sd_netlink **nl, int fd);
-int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size);
+int sd_netlink_inc_rcvbuf(sd_netlink *nl, const size_t size);
sd_netlink *sd_netlink_ref(sd_netlink *nl);
sd_netlink *sd_netlink_unref(sd_netlink *nl);
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index 4e12071e93..3ed8f23ff9 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -856,7 +856,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
_cleanup_free_ char *name = NULL, *fpath = NULL;
int a, b;
- if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
+ if (de->d_name[0] != 'S')
continue;
if (strlen(de->d_name) < 4)
@@ -886,28 +886,23 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
continue;
}
- if (de->d_name[0] == 'S') {
+ service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
- service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
-
- r = set_ensure_allocated(&runlevel_services[i], NULL);
- if (r < 0) {
- log_oom();
- goto finish;
- }
-
- r = set_put(runlevel_services[i], service);
- if (r < 0) {
- log_oom();
- goto finish;
- }
+ r = set_ensure_allocated(&runlevel_services[i], NULL);
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
+ r = set_put(runlevel_services[i], service);
+ if (r < 0) {
+ log_oom();
+ goto finish;
}
}
}
}
-
for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
SET_FOREACH(service, runlevel_services[i], j) {
r = strv_extend(&service->before, rcnd_table[i].target);
diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c
index 4616314200..8bb5f6e3a3 100644
--- a/src/test/test-process-util.c
+++ b/src/test/test-process-util.c
@@ -28,72 +28,66 @@
#include "architecture.h"
#include "log.h"
#include "macro.h"
+#include "parse-util.h"
#include "process-util.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "util.h"
#include "virt.h"
-static void test_get_process_comm(void) {
+static void test_get_process_comm(pid_t pid) {
struct stat st;
_cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL, *cwd = NULL, *root = NULL;
_cleanup_free_ char *env = NULL;
+ char path[strlen("/proc//comm") + DECIMAL_STR_MAX(pid_t)];
pid_t e;
uid_t u;
gid_t g;
dev_t h;
int r;
- pid_t me;
- if (stat("/proc/1/comm", &st) == 0) {
- assert_se(get_process_comm(1, &a) >= 0);
- log_info("pid1 comm: '%s'", a);
+ xsprintf(path, "/proc/"PID_FMT"/comm", pid);
+
+ if (stat(path, &st) == 0) {
+ assert_se(get_process_comm(pid, &a) >= 0);
+ log_info("PID"PID_FMT" comm: '%s'", pid, a);
} else
- log_warning("/proc/1/comm does not exist.");
+ log_warning("%s not exist.", path);
- assert_se(get_process_cmdline(1, 0, true, &c) >= 0);
- log_info("pid1 cmdline: '%s'", c);
+ assert_se(get_process_cmdline(pid, 0, true, &c) >= 0);
+ log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
- assert_se(get_process_cmdline(1, 8, false, &d) >= 0);
- log_info("pid1 cmdline truncated: '%s'", d);
+ assert_se(get_process_cmdline(pid, 8, false, &d) >= 0);
+ log_info("PID"PID_FMT" cmdline truncated: '%s'", pid, d);
- assert_se(get_process_ppid(1, &e) >= 0);
- log_info("pid1 ppid: "PID_FMT, e);
- assert_se(e == 0);
+ assert_se(get_process_ppid(pid, &e) >= 0);
+ log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e);
+ assert_se(pid == 1 ? e == 0 : e > 0);
- assert_se(is_kernel_thread(1) == 0);
+ assert_se(is_kernel_thread(pid) == 0 || pid != 1);
- r = get_process_exe(1, &f);
+ r = get_process_exe(pid, &f);
assert_se(r >= 0 || r == -EACCES);
- log_info("pid1 exe: '%s'", strna(f));
-
- assert_se(get_process_uid(1, &u) == 0);
- log_info("pid1 uid: "UID_FMT, u);
- assert_se(u == 0);
-
- assert_se(get_process_gid(1, &g) == 0);
- log_info("pid1 gid: "GID_FMT, g);
- assert_se(g == 0);
+ log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
- me = getpid();
-
- r = get_process_cwd(me, &cwd);
- assert_se(r >= 0 || r == -EACCES);
- log_info("pid1 cwd: '%s'", cwd);
+ assert_se(get_process_uid(pid, &u) == 0);
+ log_info("PID"PID_FMT" UID: "UID_FMT, pid, u);
+ assert_se(u == 0 || pid != 1);
- r = get_process_root(me, &root);
- assert_se(r >= 0 || r == -EACCES);
- log_info("pid1 root: '%s'", root);
+ assert_se(get_process_gid(pid, &g) == 0);
+ log_info("PID"PID_FMT" GID: "GID_FMT, pid, g);
+ assert_se(g == 0 || pid != 1);
- r = get_process_environ(me, &env);
+ r = get_process_environ(pid, &env);
assert_se(r >= 0 || r == -EACCES);
- log_info("self strlen(environ): '%zu'", strlen(env));
+ log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
if (!detect_container())
- assert_se(get_ctty_devnr(1, &h) == -ENXIO);
+ assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1);
- getenv_for_pid(1, "PATH", &i);
- log_info("pid1 $PATH: '%s'", strna(i));
+ getenv_for_pid(pid, "PATH", &i);
+ log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
}
static void test_pid_is_unwaited(void) {
@@ -157,7 +151,16 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- test_get_process_comm();
+ if (argc > 1) {
+ pid_t pid = 0;
+
+ (void) parse_pid(argv[1], &pid);
+ test_get_process_comm(pid);
+ } else {
+ test_get_process_comm(1);
+ test_get_process_comm(getpid());
+ }
+
test_pid_is_unwaited();
test_pid_is_alive();
test_personality();
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index b480fdaa9c..1a439bd0d4 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -286,6 +286,55 @@ static void test_in_addr_to_string(void) {
test_in_addr_to_string_one(AF_INET6, "fe80::");
}
+static void test_in_addr_ifindex_to_string_one(int f, const char *a, int ifindex, const char *b) {
+ _cleanup_free_ char *r = NULL;
+ union in_addr_union ua, uuaa;
+ int ff, ifindex2;
+
+ assert_se(in_addr_from_string(f, a, &ua) >= 0);
+ assert_se(in_addr_ifindex_to_string(f, &ua, ifindex, &r) >= 0);
+ printf("test_in_addr_ifindex_to_string_one: %s == %s\n", b, r);
+ assert_se(streq(b, r));
+
+ assert_se(in_addr_ifindex_from_string_auto(b, &ff, &uuaa, &ifindex2) >= 0);
+ assert_se(ff == f);
+ assert_se(in_addr_equal(f, &ua, &uuaa));
+ assert_se(ifindex2 == ifindex || ifindex2 == 0);
+}
+
+static void test_in_addr_ifindex_to_string(void) {
+ test_in_addr_ifindex_to_string_one(AF_INET, "192.168.0.1", 7, "192.168.0.1");
+ test_in_addr_ifindex_to_string_one(AF_INET, "10.11.12.13", 9, "10.11.12.13");
+ test_in_addr_ifindex_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 10, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+ test_in_addr_ifindex_to_string_one(AF_INET6, "::1", 11, "::1");
+ test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 12, "fe80::%12");
+ test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 0, "fe80::");
+ test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::14", 12, "fe80::14%12");
+ test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::15", -7, "fe80::15");
+ test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::16", LOOPBACK_IFINDEX, "fe80::16%1");
+}
+
+static void test_in_addr_ifindex_from_string_auto(void) {
+ int family, ifindex;
+ union in_addr_union ua;
+
+ /* Most in_addr_ifindex_from_string_auto() invocations have already been tested above, but let's test some more */
+
+ assert_se(in_addr_ifindex_from_string_auto("fe80::17", &family, &ua, &ifindex) >= 0);
+ assert_se(family == AF_INET6);
+ assert_se(ifindex == 0);
+
+ assert_se(in_addr_ifindex_from_string_auto("fe80::18%19", &family, &ua, &ifindex) >= 0);
+ assert_se(family == AF_INET6);
+ assert_se(ifindex == 19);
+
+ assert_se(in_addr_ifindex_from_string_auto("fe80::18%lo", &family, &ua, &ifindex) >= 0);
+ assert_se(family == AF_INET6);
+ assert_se(ifindex == LOOPBACK_IFINDEX);
+
+ assert_se(in_addr_ifindex_from_string_auto("fe80::19%thisinterfacecantexist", &family, &ua, &ifindex) == -ENODEV);
+}
+
static void *connect_thread(void *arg) {
union sockaddr_union *sa = arg;
_cleanup_close_ int fd = -1;
@@ -398,6 +447,8 @@ int main(int argc, char *argv[]) {
test_in_addr_prefix_intersect();
test_in_addr_prefix_next();
test_in_addr_to_string();
+ test_in_addr_ifindex_to_string();
+ test_in_addr_ifindex_from_string_auto();
test_nameinfo_pretty();
diff --git a/src/test/test-unaligned.c b/src/test/test-unaligned.c
index b18b3fca0e..4f64398943 100644
--- a/src/test/test-unaligned.c
+++ b/src/test/test-unaligned.c
@@ -159,7 +159,31 @@ static void test_le(void) {
assert_se(memcmp(&scratch[7], &data[7], sizeof(uint64_t)) == 0);
}
+static void test_ne(void) {
+ uint16_t x = 4711;
+ uint32_t y = 123456;
+ uint64_t z = 9876543210;
+
+ /* Note that we don't bother actually testing alignment issues in this function, after all the _ne() functions
+ * are just aliases for the _le() or _be() implementations, which we test extensively above. Hence, in this
+ * function, just ensure that they map to the right version on the local architecture. */
+
+ assert_se(unaligned_read_ne16(&x) == 4711);
+ assert_se(unaligned_read_ne32(&y) == 123456);
+ assert_se(unaligned_read_ne64(&z) == 9876543210);
+
+ unaligned_write_ne16(&x, 1);
+ unaligned_write_ne32(&y, 2);
+ unaligned_write_ne64(&z, 3);
+
+ assert_se(x == 1);
+ assert_se(y == 2);
+ assert_se(z == 3);
+}
+
int main(int argc, const char *argv[]) {
test_be();
test_le();
+ test_ne();
+ return 0;
}
diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c
index ed0ea5ce5f..3c58445836 100644
--- a/src/udev/udev-builtin-blkid.c
+++ b/src/udev/udev-builtin-blkid.c
@@ -147,11 +147,6 @@ static int find_gpt_root(struct udev_device *dev, blkid_probe pr, bool test) {
if (sd_id128_equal(type, GPT_ESP)) {
sd_id128_t id, esp;
- unsigned long long flags;
-
- flags = blkid_partition_get_flags(pp);
- if (flags & GPT_FLAG_NO_AUTO)
- continue;
/* We found an ESP, let's see if it matches
* the ESP we booted from. */
@@ -167,6 +162,11 @@ static int find_gpt_root(struct udev_device *dev, blkid_probe pr, bool test) {
found_esp = true;
} else if (sd_id128_equal(type, GPT_ROOT_NATIVE)) {
+ unsigned long long flags;
+
+ flags = blkid_partition_get_flags(pp);
+ if (flags & GPT_FLAG_NO_AUTO)
+ continue;
/* We found a suitable root partition, let's
* remember the first one. */
diff --git a/test/networkd-test.py b/test/networkd-test.py
index f94224cce2..78da0a213a 100755
--- a/test/networkd-test.py
+++ b/test/networkd-test.py
@@ -205,7 +205,7 @@ DHCP=%s
def test_coldplug_dhcp_yes_ip4_no_ra(self):
# with disabling RA explicitly things should be fast
self.do_test(coldplug=True, ipv6=False,
- extra_opts='IPv6AcceptRouterAdvertisements=False')
+ extra_opts='IPv6AcceptRA=False')
def test_coldplug_dhcp_ip4_only(self):
# we have a 12s timeout on RA, so we need to wait longer
@@ -215,7 +215,7 @@ DHCP=%s
def test_coldplug_dhcp_ip4_only_no_ra(self):
# with disabling RA explicitly things should be fast
self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4',
- extra_opts='IPv6AcceptRouterAdvertisements=False')
+ extra_opts='IPv6AcceptRA=False')
def test_coldplug_dhcp_ip6(self):
self.do_test(coldplug=True, ipv6=True)
diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in
index b7079e4a7c..d8f18bed53 100644
--- a/units/systemd-hostnamed.service.in
+++ b/units/systemd-hostnamed.service.in
@@ -20,3 +20,5 @@ PrivateDevices=yes
PrivateNetwork=yes
ProtectSystem=yes
ProtectHome=yes
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @module @mount @obsolete @raw-io ptrace
diff --git a/units/systemd-importd.service.in b/units/systemd-importd.service.in
index b74ad72cdc..a3d1a1519b 100644
--- a/units/systemd-importd.service.in
+++ b/units/systemd-importd.service.in
@@ -17,3 +17,5 @@ CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_
NoNewPrivileges=yes
WatchdogSec=3min
KillMode=mixed
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @module @mount @obsolete @raw-io ptrace
diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in
index 41bfde5be3..58808d4f8c 100644
--- a/units/systemd-journald.service.in
+++ b/units/systemd-journald.service.in
@@ -24,6 +24,8 @@ StandardOutput=null
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE
WatchdogSec=3min
FileDescriptorStoreMax=1024
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @module @mount @obsolete @raw-io ptrace
# Increase the default a bit in order to allow many simultaneous
# services being run since we keep one fd open per service. Also, when
diff --git a/units/systemd-localed.service.in b/units/systemd-localed.service.in
index 9b13f901a3..5efa677548 100644
--- a/units/systemd-localed.service.in
+++ b/units/systemd-localed.service.in
@@ -20,3 +20,5 @@ PrivateDevices=yes
PrivateNetwork=yes
ProtectSystem=yes
ProtectHome=yes
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @module @mount @obsolete @privileged @raw-io ptrace
diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in
index ff049134ee..a9598760e2 100644
--- a/units/systemd-logind.service.in
+++ b/units/systemd-logind.service.in
@@ -25,6 +25,8 @@ RestartSec=0
BusName=org.freedesktop.login1
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER CAP_SYS_TTY_CONFIG
WatchdogSec=3min
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @module @mount @obsolete @raw-io ptrace
# Increase the default a bit in order to allow many simultaneous
# logins since we keep one fd open per session.
diff --git a/units/systemd-machined.service.in b/units/systemd-machined.service.in
index 685baab21d..82dca05338 100644
--- a/units/systemd-machined.service.in
+++ b/units/systemd-machined.service.in
@@ -17,6 +17,8 @@ ExecStart=@rootlibexecdir@/systemd-machined
BusName=org.freedesktop.machine1
CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD
WatchdogSec=3min
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @module @mount @obsolete @raw-io ptrace
# Note that machined cannot be placed in a mount namespace, since it
# needs access to the host's mount namespace in order to implement the
diff --git a/units/systemd-networkd.service.m4.in b/units/systemd-networkd.service.m4.in
index 27d4d58962..3feb2b84f5 100644
--- a/units/systemd-networkd.service.m4.in
+++ b/units/systemd-networkd.service.m4.in
@@ -31,6 +31,8 @@ CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_N
ProtectSystem=full
ProtectHome=yes
WatchdogSec=3min
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @module @mount @obsolete @raw-io ptrace
[Install]
WantedBy=multi-user.target
diff --git a/units/systemd-resolved.service.m4.in b/units/systemd-resolved.service.m4.in
index 8e1c1dea79..4a94f747e2 100644
--- a/units/systemd-resolved.service.m4.in
+++ b/units/systemd-resolved.service.m4.in
@@ -27,6 +27,8 @@ CapabilityBoundingSet=CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRI
ProtectSystem=full
ProtectHome=yes
WatchdogSec=3min
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@clock @module @mount @obsolete @raw-io ptrace
[Install]
WantedBy=multi-user.target
diff --git a/units/systemd-timedated.service.in b/units/systemd-timedated.service.in
index 0c9599db20..1bdbe65aad 100644
--- a/units/systemd-timedated.service.in
+++ b/units/systemd-timedated.service.in
@@ -18,3 +18,5 @@ WatchdogSec=3min
PrivateTmp=yes
ProtectSystem=yes
ProtectHome=yes
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@module @mount @obsolete @raw-io ptrace
diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in
index a856dad709..8c86021f5e 100644
--- a/units/systemd-timesyncd.service.in
+++ b/units/systemd-timesyncd.service.in
@@ -28,6 +28,8 @@ PrivateDevices=yes
ProtectSystem=full
ProtectHome=yes
WatchdogSec=3min
+MemoryDenyWriteExecute=yes
+SystemCallFilter=~@module @mount @obsolete @raw-io ptrace
[Install]
WantedBy=sysinit.target