Commit graph

9469 commits

Author SHA1 Message Date
Thomas Haller
b8bc80bcdb all: add base object type in "nm-obj.h"
Platform has it's own, simple implementation of object types:
NMPObject. Extract a base type and move it to "shared/nm-utils/nm-obj.h"
so it can be reused.

The base type is trival, but it allows us to implement other objects
which are compatible with NMPObjects. Currently there is no API for generic
NMObjBaseInst type, so compatible in this case only means, that they
can be used in the same context (see example below).
The only thing that you can do with a NMObjBaseInst is check it's
NMObjBaseClass.

Incidentally, NMObjBaseInst is also made compatible to GTypeInstance.
It means, an NMObjBaseInst is not necessarily a valid GTypeInstance (like NMPObject
is not), but it could be implemented as such.

For example, you could do:

    if (NMP_CLASS_IS_VALID ((NMPClass *) obj->klass)) {
        /* is an NMPObject */
    } else if (G_TYPE_CHECK_INSTANCE_TYPE (obj, NM_TYPE_SOMETHING)) {
        /* it a NMSometing GType */
    } else {
        /* something else? */
    }

The reason why NMPObject is not implemented as proper GTypeInstance is
because it would require us to register a GType (like
g_type_register_fundamental). However, then the NMPClass struct can
no longer be const and immutable memory. But we could.

NMObjBaseInst may or may not be a GTypeInstance. In a sense, it's
a base type of GTypeInstance and all our objects should be based
on it (optionally, they we may make them valid GTypes too).
2017-07-05 14:22:10 +02:00
Thomas Haller
3f76b5b7eb core: use NM_HASH_COMBINE() function 2017-07-05 14:22:10 +02:00
Thomas Haller
b002357f5f platform: fix nm_platform_lnk_macvlan_cmp() to consider "tap" field 2017-07-05 14:22:10 +02:00
Beniamino Galvani
348959cfa2 checkpoint: disconnect device before reactivation during rollback
Since commit 0922a17738 ("manager: avoid that auto-activations
preempt user activations") the manager doesn't allow a internal
activation to disconnect the same connection already active on the
device.  Thus, during a rollback we must ensure that the device is
deactivated before.

Fixes: 0922a17738
2017-07-05 11:01:56 +02:00
Beniamino Galvani
65a0208ba0 core,cli: replace wrong pattern for clearing GError
Use gs_free_error instead of gs_free.
2017-06-27 09:42:28 +02:00
Mike Gorse
6405d17730 Move CONF_DHCP definition to nm-hostname-manager.c
It is only referenced from there. Fixes the build if HOSTNAME_PERSIST_SUSE
is defined.

Fixes: 5bfb7c3c89

https://bugzilla.gnome.org/show_bug.cgi?id=784225
2017-06-27 09:05:42 +02:00
Beniamino Galvani
92fc109183 bond: ignore miimon option only when it is zero
The default value for miimon, when missing in the setting, is 0 if
arp_interval is != 0, and 100 otherwise. So, when generating a
connection, let's ignore miimon=0 (which means that miimon is
disabled) and accept any other value. Adding miimon=100 does not cause
any harm to the connection assumption.

While at it, slightly improve the code: ignore_if_zero() is not useful
for 'updelay','downdelay','arp_interval' because zero is their default
value, so introduce a new function that checks if the value is the
default (and specially handles 'miimon').

Reported-by: Taketo Kabe <rkabe@vega.pgw.jp>

https://bugzilla.redhat.com/show_bug.cgi?id=1463077
2017-06-23 11:18:51 +02:00
Nikolay Martynov
8c91422954 device: handle carrier changes for master device differently
For master devices, instead of ignoring loss of carrier entirely,
handle it.

First of all, master devices are now by default ignore-carrier=yes.
That means, without explict user configuration in NetworkManager.conf,
the previous behavior in carrier_changed() does not change.

If the user decides to configure the master device like

    [device-with-carrier]
    match-device=type:bond,type:bridge,type:team
    ignore-carrier=no

then, master device will disconnect on carrier loss like
regular devices.

https://github.com/NetworkManager/NetworkManager/pull/18

Co-authored-by: Thomas Haller <thaller@redhat.com>
2017-06-22 13:27:01 +02:00
Thomas Haller
b0f6baad90 device: renew IP addressing on carrier change also for master devices
Commit 348452f1e0 (device: renew DHCP
lease for active "ignore-carrier" devices on carrier-on (bgo #743368))
added this behavior for non-master devices.

The same reasoning applies here too.

https://github.com/NetworkManager/NetworkManager/pull/18

Based-on-patch-by: Nikolay Martynov <mar.kolya@gmail.com>
2017-06-22 13:26:53 +02:00
Thomas Haller
e9a917d619 device: refactor how master device's set is_available()
Previously, master device types like bridge, bond, and team
would overwrite is_available() and check_connection_available()
and always return TRUE.

The device already expresses via nm_device_is_master() that it
is of a master kind. Refactor the code, so, instead of having these
device types overwrite is_available() and check_connection_available(),
let the parents implementation react on nm_device_is_master().

There is no change in behavior at all. Instead, the knowledge how to
treat a master device moves from the device implementation to the
parent class.
2017-06-22 13:26:53 +02:00
Thomas Haller
98651b90a1 device: handle default for unset ignore-carrier option depending on device
Currently, device types like Bond hack around ignore-carrier
setting, as they always want to ignore-carrier.

Prepare so that also for such master types, we rely and honor the
ignore-carrier setting better. In the next commit, bond, bridge and
team devices they will get ignore-carrier turned on by default.
2017-06-22 13:26:53 +02:00
Francesco Giudici
d4a033c4ad manager: when a connection is upped on a device, do an early update of its internal state
When a user forces up a connection on a device, mark earlier the
device as managed: this would allow proper clean-up on the device also
when it was previously unmanaged or assumed.
This would avoid skipping IPv6LL address generation when instead it was
needed.

Fixes: adbf383628

https://bugzilla.redhat.com/show_bug.cgi?id=1452046
2017-06-21 16:12:09 +02:00
Beniamino Galvani
0922a17738 manager: avoid that auto-activations preempt user activations
In _internal_activate_device(), we try to find an existing master AC
for the slave AC, and we create a new one in case of failure. The
master AC may already exist, but it may not be detected by
find_master() because it is undergoing authorization.

The result is that we auto-activate the master when there is already a
user activation in place, and the auto-activation will cancel the user
one. This is bad, as user-activation should always have precedence.

To fix this, introduce a last-minute check before activating internal
connections.

https://bugzilla.redhat.com/show_bug.cgi?id=1450219
2017-06-19 15:56:05 +02:00
Thomas Haller
19a98c6f61 dns: don't clone DNS configs list for nm_dns_plugin_update()
No need to clone the list anymore. Unfortunately, GPtrArray is not NULL
terminated (without extra effort), so we have to pass on the GPtrArray
instance for the length.
2017-06-19 15:12:49 +02:00
Thomas Haller
70792e51d9 dns: fix negative ipv4.dns-priority for systemd-resolved
A negative ipv4.dns-priority and ipv6.dns-priority has the meaning to configure
the DNS information of the connection exclusively. With systemd-resolved, that means
we must explicitly unset the configuration from other interfaces.

https://bugzilla.gnome.org/show_bug.cgi?id=783569
2017-06-19 15:12:49 +02:00
Thomas Haller
d582176939 dns: make configs argument to update a const pointer 2017-06-19 15:12:49 +02:00
Thomas Haller
1c9285b06e dns/systemd: remove unused device lookup in add_interface_configuration() 2017-06-19 15:12:49 +02:00
Thomas Haller
c818e46d48 dns: add helper method to get DNS priority from NMDnsIPConfigData 2017-06-19 15:12:49 +02:00
Thomas Haller
aa347182bb dns: minor refactoring in _collect_resolv_conf_data()
The code was correct previously, but it was confusing to me,
because

  - once @skip gets set to TRUE, it stays TRUE for the rest
    of the loop.
  - in each additional skipped iteration, it would still set
    plugin_confs[i] to NULL. Which is not wrong, but confusing.
  - it would set "prev_prio = prio;" in each iteration.
    After @skip is set to TRUE, that doesn't matter anymore,
    but is confusing. Before @skip is set to TRUE it also
    doesn't really matter to set it more then once, because
    we only care about the very first priority.
  - @skip sounded to me like the current iteration would
    be skipped. But really all remaining will be skipped too.
2017-06-19 15:12:49 +02:00
Thomas Haller
10c0632df0 device: fix taking over device after modifying external connection
For externally managed interfaces, we create an in-memory connection
and keep the device with sys-iface-state=external.

When the user actively modifies the connection, we persist it to
storage. But we also must take over managing the device.

One problem is that nm_device_reapply() errors out if the device
is still activating. It's unclear how to reapply the connection
while the device is in the process of activation. So, if the user
modifies the created connection very quickly, reapplying the settings
will fail.

https://bugzilla.redhat.com/show_bug.cgi?id=1462223
2017-06-19 14:57:48 +02:00
Thomas Haller
b84da25713 core: fix registering notify-flags hook in NMActiveConnection
We react on changes to NMSettingsConnection.flags, so that we can update
from an external activation to a managed one.

However, previously we would only register the _settings_connection_notify_flags
callback during _set_settings_connection(). So, if via constructor properties
we first set PROP_SETTINGS_CONNECTION and later PROP_ACTIVATION_TYPE, we wouldn't
register the callback.
2017-06-19 14:28:00 +02:00
Thomas Haller
2656ba8d1d core: log changes to NMSettingsConnection's flags 2017-06-16 13:47:08 +02:00
Tom Gundersen
6c8fe5754c ifcfg-rh: refactor dbus policy
This drops some redundant rules and orderes the remaining ones by
precedence.

The 'root' rules take precedence over the 'default' rules, so order
the file accordingly.

It is not necessary to repeat send_destination rules, as the default
rules already allows everyone to send to the interface.

Moreover, it is not necessary to restrict the ownership of the name
in the default context, as this is already done by the system-wide
default rule.

Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
2017-06-15 13:20:55 +02:00
Thomas Haller
203ffede01 dhcp/systemd: add support for DHCPv4 domain search list (option 119) 2017-06-14 15:49:39 +02:00
Thomas Haller
e02f5454fd dhcp: cleanup formatting of LOG_LEASE() macro in lease_to_ip4_config()
and lease_to_ip6_config().

The use of a prefix should be done by LOG_LEASE() macro, instead
of each caller individually.
2017-06-14 14:04:57 +02:00
Thomas Haller
4fd023b617 dhcp: reuse string buffer in lease_to_ip4_config()
In lease_to_ip4_config() avoid creating multiple GString buffers. Just
reuse it.
2017-06-14 14:04:57 +02:00
Thomas Haller
3c1466b7de dhcp/trivial: rename local variables
lease_to_ip6_config() calls the GString temporary buffer "str".
That makes sense, use the same name in lease_to_ip4_config().

For that, we have to rename other local variables too.
2017-06-14 14:04:57 +02:00
Thomas Haller
6e5cc2b24f wifi: fix cancelling WPS during pending ProcessCredentials
When we cancel WPS, we must cancel the GCancellable. Otherwise,
ProcessCredentials will return and proceed with Start.

Fixes: 9bfb4f0d09
2017-06-14 13:52:40 +02:00
Thomas Haller
be3d897758 systemd: merge branch systemd into master
- adjust nm-sd-adapt.h to new LogRealm
- add support for DHCP search domain list
2017-06-14 13:10:05 +02:00
Thomas Haller
cd5ef1ed7d systemd: update code from upstream (2017-06-14)
This is a direct dump from systemd git on 2017-06-14, git commit
42d3bf86bb75842602d3712caa2baccd09a1c795.

======

SYSTEMD_DIR=../systemd
COMMIT=42d3bf86bb75842602d3712caa2baccd09a1c795

(
  cd "$SYSTEMD_DIR"
  git checkout "$COMMIT"
  git reset --hard
  git clean -fdx
)

git ls-files :/src/systemd/src/ | xargs -d '\n' rm -f

nm_copy_sd() {
    mkdir -p "./src/systemd/$(dirname "$1")"
    cp "$SYSTEMD_DIR/$1" "./src/systemd/$1"
}

nm_copy_sd "src/basic/alloc-util.c"
nm_copy_sd "src/basic/alloc-util.h"
nm_copy_sd "src/basic/async.h"
nm_copy_sd "src/basic/escape.c"
nm_copy_sd "src/basic/escape.h"
nm_copy_sd "src/basic/ether-addr-util.c"
nm_copy_sd "src/basic/ether-addr-util.h"
nm_copy_sd "src/basic/extract-word.c"
nm_copy_sd "src/basic/extract-word.h"
nm_copy_sd "src/basic/fileio.c"
nm_copy_sd "src/basic/fileio.h"
nm_copy_sd "src/basic/fd-util.c"
nm_copy_sd "src/basic/fd-util.h"
nm_copy_sd "src/basic/fs-util.c"
nm_copy_sd "src/basic/fs-util.h"
nm_copy_sd "src/basic/hash-funcs.c"
nm_copy_sd "src/basic/hash-funcs.h"
nm_copy_sd "src/basic/hashmap.c"
nm_copy_sd "src/basic/hashmap.h"
nm_copy_sd "src/basic/hexdecoct.c"
nm_copy_sd "src/basic/hexdecoct.h"
nm_copy_sd "src/basic/hostname-util.c"
nm_copy_sd "src/basic/hostname-util.h"
nm_copy_sd "src/basic/in-addr-util.c"
nm_copy_sd "src/basic/in-addr-util.h"
nm_copy_sd "src/basic/io-util.c"
nm_copy_sd "src/basic/io-util.h"
nm_copy_sd "src/basic/list.h"
nm_copy_sd "src/basic/log.h"
nm_copy_sd "src/basic/macro.h"
nm_copy_sd "src/basic/mempool.h"
nm_copy_sd "src/basic/mempool.c"
nm_copy_sd "src/basic/parse-util.c"
nm_copy_sd "src/basic/parse-util.h"
nm_copy_sd "src/basic/path-util.c"
nm_copy_sd "src/basic/path-util.h"
nm_copy_sd "src/basic/prioq.h"
nm_copy_sd "src/basic/prioq.c"
nm_copy_sd "src/basic/random-util.c"
nm_copy_sd "src/basic/random-util.h"
nm_copy_sd "src/basic/refcnt.h"
nm_copy_sd "src/basic/set.h"
nm_copy_sd "src/basic/signal-util.h"
nm_copy_sd "src/basic/siphash24.c"
nm_copy_sd "src/basic/siphash24.h"
nm_copy_sd "src/basic/socket-util.c"
nm_copy_sd "src/basic/socket-util.h"
nm_copy_sd "src/basic/sparse-endian.h"
nm_copy_sd "src/basic/stdio-util.h"
nm_copy_sd "src/basic/string-table.c"
nm_copy_sd "src/basic/string-table.h"
nm_copy_sd "src/basic/string-util.c"
nm_copy_sd "src/basic/string-util.h"
nm_copy_sd "src/basic/strv.c"
nm_copy_sd "src/basic/strv.h"
nm_copy_sd "src/basic/time-util.c"
nm_copy_sd "src/basic/time-util.h"
nm_copy_sd "src/basic/umask-util.h"
nm_copy_sd "src/basic/unaligned.h"
nm_copy_sd "src/basic/utf8.c"
nm_copy_sd "src/basic/utf8.h"
nm_copy_sd "src/basic/util.c"
nm_copy_sd "src/basic/util.h"
nm_copy_sd "src/libsystemd-network/arp-util.c"
nm_copy_sd "src/libsystemd-network/arp-util.h"
nm_copy_sd "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.c"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.h"
nm_copy_sd "src/libsystemd-network/dhcp-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-network.c"
nm_copy_sd "src/libsystemd-network/dhcp-option.c"
nm_copy_sd "src/libsystemd-network/dhcp-packet.c"
nm_copy_sd "src/libsystemd-network/dhcp-protocol.h"
nm_copy_sd "src/libsystemd-network/lldp-internal.h"
nm_copy_sd "src/libsystemd-network/lldp-neighbor.c"
nm_copy_sd "src/libsystemd-network/lldp-neighbor.h"
nm_copy_sd "src/libsystemd-network/lldp-network.c"
nm_copy_sd "src/libsystemd-network/lldp-network.h"
nm_copy_sd "src/libsystemd-network/network-internal.c"
nm_copy_sd "src/libsystemd-network/network-internal.h"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-lease.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4ll.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4acd.c"
nm_copy_sd "src/libsystemd-network/sd-lldp.c"
nm_copy_sd "src/libsystemd/sd-event/sd-event.c"
nm_copy_sd "src/libsystemd/sd-id128/id128-util.c"
nm_copy_sd "src/libsystemd/sd-id128/id128-util.h"
nm_copy_sd "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd "src/shared/dns-domain.c"
nm_copy_sd "src/shared/dns-domain.h"
nm_copy_sd "src/systemd/_sd-common.h"
nm_copy_sd "src/systemd/sd-dhcp6-client.h"
nm_copy_sd "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd "src/systemd/sd-dhcp-client.h"
nm_copy_sd "src/systemd/sd-dhcp-lease.h"
nm_copy_sd "src/systemd/sd-event.h"
nm_copy_sd "src/systemd/sd-ndisc.h"
nm_copy_sd "src/systemd/sd-id128.h"
nm_copy_sd "src/systemd/sd-ipv4acd.h"
nm_copy_sd "src/systemd/sd-ipv4ll.h"
nm_copy_sd "src/systemd/sd-lldp.h"
2017-06-14 12:05:03 +02:00
Thomas Haller
9bfb4f0d09 supplicant: chain asynchronous requests for WPS
Don't have pending asynchronous requests in parallel, like setting
"ProcessCredentials" and "Start", or "Cancel" and "Start".
Instead, "Start" is only scheduled after "ProcessCredentials" completed
and "ProcessCredentials" is only scheduled after "Cancel" completed.

Also, handle the async response of these requests. For one, to achive the
chaining mentioned above and to log what happens and possible errors.

Upon new enrollment, a previously created GDBusProxy is now reused,
where the first operation is to Cancel the previous action.

Also, consistently <trace> log what is happening.

Not doing all of this is less lines of code. It's also simpler, and
faster. But in my opinion, it is (usually) better to check and wait for
return values, instead of firing off async requests uncontrolled. It
allows us to better know where we are and to log about each individual
step. This also makes all operations cancellable.
Undoubtedly, correctness and handling failures conflicts with simplicity
in this case -- or at least: what I think is "correctness" conflicts.
2017-06-14 11:07:11 +02:00
Thomas Haller
d4d00ee09c supplicant/trivial: move code around 2017-06-14 11:07:11 +02:00
Beniamino Galvani
b6fa87a4c0 core: sort addresses in captured IPv4 configuration
When IPv4 addresses are synchronized to platform, the order of IPv4
addresses matters because the first address is considered the primary
one. Thus, nm_ip4_config_capture() should put the primary address as
first, otherwise during synchronization addresses will be removed and
added back with a different primary/secondary role.

https://bugzilla.redhat.com/show_bug.cgi?id=1459813
2017-06-13 23:27:33 +02:00
Thomas Haller
4ca3002b86 device: don't set MTU of device unless explicitly configured
Since commit 2b51d3967 "device: merge branch 'th/device-mtu-bgo777251'",
we always set the MTU for certain device types during activation. Even
if the MTU is neither specified via the connection nor other means, like
DHCP.

Revert that change. On activation, if nothing explicitly configures the
MTU, leave it unchanged. This is like what we do with ethernet's
cloned-mac-address, which has a default value "preserve".
So, as last resort the default value for MTU is now 0 (don't change),
instead of depending on the device type.

Note that you also can override the default value in global
configuration via NetworkManager.conf.

This behavior makes sense, because whenever NM actively resets the MTU,
it remembers the previous value and restores it when deactivating
the connection. That wasn't implemented before 2b51d3967, and the
MTU would depend on which connection was previously active. That
is no longer an issue as the MTU gets reset when deactivating.

https://bugzilla.redhat.com/show_bug.cgi?id=1460760
2017-06-13 15:05:30 +02:00
Thomas Haller
b9af32b056 ppp: fix cancelling timeout when pppd process exits
Otherwise, we get pppd_timed_out() later, which will
emit a DEAD state change at unexpected times.
2017-06-09 16:15:07 +02:00
Thomas Haller
250e723951 ppp: cleanup logging pppd exit reason in ppp_watch_cb
- don't use assert but be more graceful with g_return_if_fail().
- in case of failure, don't log a debug message after the warning.
  One message is sufficient, drop "pppd pid %d cleaned up".
- print GPid type as long long.
- increase log level to warning. pppd dying unexpectedly warrants a
  warning.
2017-06-09 16:07:47 +02:00
Thomas Haller
a814b96ebf ppp: don't log newlines 2017-06-09 15:42:49 +02:00
Thomas Haller
3f64910b52 ppp: refactor ppp_exit_code() to split out error to string conversion
ppp_exit_code() does too much or too little. Either it should log
about all reasons why pppd exited, including signals, or it should
just do the status to string conversion. Split it.
2017-06-09 15:42:49 +02:00
Thomas Haller
5c5fbe0a9f ppp/trivial: fix whitespace 2017-06-09 15:42:49 +02:00
Thomas Haller
0f16649ba2 ppp: inline and drop trivial function remove_timeout_handler() 2017-06-09 15:42:49 +02:00
Beniamino Galvani
aa099906f9 device: apply route metric penality only when the default route exists
It's useless (and in some cases also harmful) to commit the
configuration to update the default route metric when the device has
no default route. Also, don't commit configuration for externally
activated devices.

https://bugzilla.redhat.com/show_bug.cgi?id=1459604
2017-06-09 13:52:03 +02:00
Thomas Haller
0c26ffd638 device: suppress logging and return error reason from nm_device_generate_connection()
Don't log in a function that basically just inspects state, without
mutating it. Instead, pass the reason why a connection could not be
generated to the caller so that we have one sensible log message.
2017-06-08 21:50:23 +02:00
Thomas Haller
962f8f42d9 manager: cleanup logging message during recheck_assume_connection()/get_existing_connection()
recheck_assume_connection() calls get_existing_connection(). We want *one* logging
message telling what's happening. Let get_existing_connection() log "assume:"
messages and remove duplicate messages from recheck_assume_connection().
2017-06-08 21:50:23 +02:00
Thomas Haller
cc47a6a8b2 device: remove logging for emitting RECHECK_ASSUME signal
The device's RECHECK_ASSUME signal has only NMManager as subscriber
and it immediately calls recheck_assume_connection().

With the previous commit, recheck_assume_connection() always logs
a debug message, so we don't need this duplicate message anymore.
2017-06-08 21:50:23 +02:00
Thomas Haller
94534e0327 manager: add more logging to recheck_assume_connection()
and give all lines a logging prefix.
2017-06-08 21:50:23 +02:00
Thomas Haller
dd53c879d2 manager: add "rfkill" prefix to related logging messages 2017-06-08 21:50:23 +02:00
Thomas Haller
6962f14d4a manager: add logging macro _NMLOG3() for logging connection messages
It unifies the way how we print the logging prefix, but also it
passes the con_uuid down for structured logging.
2017-06-08 21:50:23 +02:00
Thomas Haller
1f6078bcf5 manager: add logging macro _NMLOG2() for logging device messages
It unifies the way how we print the logging prefix, but also it
passes the ifname down for structured logging.
2017-06-08 21:50:23 +02:00
Thomas Haller
2ae891b592 logging: add LOG3 macros 2017-06-08 21:50:23 +02:00
Thomas Haller
4b15df2656 device: expose nm_device_state_to_str() function for NMDeviceState 2017-06-08 21:50:23 +02:00