NetworkManager 1.26.0


A new NetworkManager version 1.26.0 was released today.

Speedy has already upgraded to the latest version.



Why NetworkManager?


Fleur and Eliška use NetworkManager on all their servers

Configuring the Network




Providing an API for other Tools




Generalist and Featureful

NetworkManager is a generalist and featureful and complex.




Integration of Tools

Using NetworkManager API allows the integration of tools.



What’s Next?





WireGuard in NetworkManager

WireGuard in NetworkManager


Having support in NetworkManager is great for two main reasons:

For Alice it is now easy to configure WireGuard with NetworkManager.


Import an existing WireGuard profile


Address =
Address =
SaveConfig = true
PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=
ListenPort = 51820

PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=
AllowedIPs =,

PublicKey = TrMvSoP4jYQlY6RIzBgbssQqY3vxI2Pi+y71lOWWXX0=
AllowedIPs =,

PublicKey = gN65BkIKy1eCE9pP1wdc8ROUtkHLF2PfAqYdyYBz6EA=
AllowedIPs =

Let’s import this into NetworkManager:

$ CONF_FILE="wg0.conf"
$ nmcli connection import type wireguard file "$CONF_FILE"


You may delete the profile again with

$ nmcli connection delete wg0

About Connection Profiles






And let’s look at the profile:

connection.uuid:                     0d2aed05-2c7f-40ec-81ad-b1b4edd898fc
connection.stable-id:                --
connection.type:                     wireguard
connection.interface-name:           wg0
connection.autoconnect:              yes
ipv4.method:                         disabled
ipv6.method:                         ignore
wireguard.private-key:               --
wireguard.private-key-flags:         0 (none)
wireguard.listen-port:               0
wireguard.fwmark:                    0x0
wireguard.peer-routes:               yes
wireguard.mtu:                       0


Secrets are required to connect WireGuard VPN 'my-wg0'

Confirm that the VPN tunnel is now up:

$ nmcli
wg0: connected to my-wg0
        wireguard, sw, mtu 1420
        route6 ff00::/8
        route6 fe80::/64
$ ip link show wg0
$ sudo WG_HIDE_KEYS=never wg
interface: wg0
  public key: SymChsQwTX5yZrtwtsWpYfHLMgnJpOJ25YOfs7/ImT0=
  private key: eD8wqjLABmg6ClC+6egB/dnMLbbUYSMMrDsrHUwmQlI=
  listening port: 56389


This connection isn’t right yet. Let’s adjust it:

$ nmcli connection modify my-wg0 \
    autoconnect yes \
    ipv4.method manual \
    ipv4.addresses \
    wireguard.listen-port 50000 \


connection.uuid:                        0d2aed05-2c7f-40ec-81ad-b1b4edd898fc
connection.type:                        wireguard
connection.interface-name:              wg0
connection.timestamp:                   1551171032
ipv4.method:                            manual
ipv6.method:                            ignore
wireguard.private-key-flags:            0 (none)
wireguard.listen-port:                  50000
GENERAL.NAME:                           my-wg0
GENERAL.UUID:                           0d2aed05-2c7f-40ec-81ad-b1b4edd898fc
GENERAL.DEVICES:                        wg0
GENERAL.STATE:                          activated
GENERAL.DEFAULT:                        no
GENERAL.DEFAULT6:                       no
GENERAL.SPEC-OBJECT:                    --
GENERAL.VPN:                            no
GENERAL.ZONE:                           --
GENERAL.MASTER-PATH:                    --


$ nmcli connection up my-wg0


Configuring Peers


1.) Import Peers from a wg-quick configuration file




$ python nm-wg-set my-wg0 \
    fwmark 0x500 \
    peer llG3xkDWcEP4KODf45zjntuvUX0oXieRyxXdl5POYX4= \
    endpoint \
    allowed-ips \
    persistent-keepalive 120 \
    peer 2Gl0SATbfrrzxfrSkhNoRR9Jg56y533y07KtIVngAk0= \
    preshared-key \
      <(echo qoNbN/6ABe4wWyz4jh+uwX7vqRpNeGEtgAnUbwNjEug=) \
    preshared-key-flags 0 \
interface:                    wg0
uuid:                         0d2aed05-2c7f-40ec-81ad-b1b4edd898fc
id:                           my-wg0
private-key:                  eD8wqjLABmg6ClC+6egB/dnMLbbUYSMMrDsrHUwmQlI=
private-key-flags:            0 (none)
listen-port:                  50000
fwmark:                       0x500
peer[0].public-key:           llG3xkDWcEP4KODf45zjntuvUX0oXieRyxXdl5POYX4=
peer[0].persistent-keepalive: 120
peer[1].public-key:           2Gl0SATbfrrzxfrSkhNoRR9Jg56y533y07KtIVngAk0=
peer[1].persistent-keepalive: 0

3.) Use libnm directly


4.) Use D-Bus directly


5.) Edit the Profile on Disk


$ sudo cat \







Finally, reactivate the profile and check the result:

$ nmcli connection up my-wg0 
$ sudo WG_HIDE_KEYS=never wg
interface: wg0
  public key: SymChsQwTX5yZrtwtsWpYfHLMgnJpOJ25YOfs7/ImT0=
  private key: eD8wqjLABmg6ClC+6egB/dnMLbbUYSMMrDsrHUwmQlI=
  listening port: 50000
  fwmark: 0x500

peer: llG3xkDWcEP4KODf45zjntuvUX0oXieRyxXdl5POYX4=
  allowed ips:
  persistent keepalive: every 2 minutes

peer: 2Gl0SATbfrrzxfrSkhNoRR9Jg56y533y07KtIVngAk0=
  preshared key: qoNbN/6ABe4wWyz4jh+uwX7vqRpNeGEtgAnUbwNjEug=
  allowed ips: (none)

Reapply and Runtime Configuration


Dynamically Resolving Endpoints




Peer Routes, AllowedIPs and Cryptokey Routing


Routing All Your Traffic




$ nmcli connection modify eth0 \
    +ipv4.routes "$WG_ENDPOINT_ADDR/32"




Key, Peer, and IP Address Management





What’s next?

  • Automatically help avoiding routing loops when routing all traffic.
  • Add nmcli support for configuring WireGuard peers.

MAC Address Spoofing in NetworkManager 1.4.0

The new NetworkManager release 1.4.0 adds new features to change the current MAC address of your Ethernet or Wi-Fi card. This is also called MAC address “spoofing” or “cloning”.

His name is Václav
Václav sleeps better with NetworkManager’s MAC address randomization

Previously NetworkManager 1.2.0 added MAC address randomization for Wi-Fi, as Lubomir explains in his blog post. He also explains why you may want to do that in the first place, so I skip the introduction. Suffice to say, some consider randomizing the MAC address an important feature to protect their privacy. Only be aware that for real™ privacy, more considerations come into play. The Tails distribution and Wikipedia have good reads on the subject.

1.2.0 relies on support from wpa_supplicant to configure a random MAC address. The problem is that it requires API which will only be part of the next major release 2.6 of the supplicant. Such a release does not yet exist to this date and thus virtually nobody is using this feature.

With NetworkManager 1.4.0, changing of the MAC address is done by NetworkManager itself, requiring no support from the supplicant. This allows also for more flexibility to generate “stable” addresses and the “generate-mac-address-mask”. Also, the same options are now available not only for Wi-Fi, but also Ethernet devices.

Tools like macchanger and macchiato are commonly used to change the MAC address of a device. They support flexible mechanisms to generate a random address, most of these options are now also supported by NetworkManager.

Randomization during Wi-Fi scanning

During Wi-Fi scanning, NetworkManager resets the MAC address frequently to a randomly generated address. This was already enabled by default in 1.2.0, but as said, users likely didn’t have the required support from wpa_supplicant.

This default behavior can be disabled with a global configuration option in NetworkManager.conf:


Note that this is a per-device configuration value, because at the time of Wi-Fi scanning, no connection is yet activated. A “connection” in NetworkManager-speak is a profile, a bunch of settings.

Supported Modes

Since long, NetworkManager supports two connection properties “ethernet.cloned-mac-address” and “wifi.cloned-mac-address”. These settings take effect when activating the connection. They got extended in 1.4.0 and support the following values:

  • An explict MAC address: this was already supported before 1.4.0 and allows to spoof a specific MAC address.
  • “permanent”: use the permanent MAC address of the device. Before 1.4.0, the permanent MAC address was used if the “cloned-mac-address” property was left empty, thus it was the default.
  • “preserve”: don’t change the MAC address of the device upon activation.
  • “random”: generate a randomized value upon each connect.
  • “stable”: generate a stable, hashed MAC address.
  • NULL/unset: this is the default value which allows fallback to a globally configured default, see below. In case no global override exists, NetworkManager falls back to “permanent”, like it did before.

Update-2017-01-25: with 1.6 release and newer, the default value changed from “permanent” to “preserve” [commit],[bug].

Note that in the D-Bus API, the “cloned-mac-address” field is not a string and thus could not be extended in a backward compatible way. That is why on D-Bus there are new fields “ethernet.assigned-mac-address” and “wifi.assigned-mac-address” instead. On the other hand, in nmcli,, and keyfile-format the properties are indeed called “cloned-mac-address”.

How to configure it?

It is likely that your favorite NetworkManager client does not expose these options in the UI. In that case, I would suggest to use nmcli to configure the per-connection settings:

$ nmcli connection show
NAME               UUID               TYPE            DEVICE
My Wi-Fi           fca8fc45-c47...    802-11-wireless --

$ nmcli connection show "My Wi-Fi"

$ nmcli connection modify "My Wi-Fi" \
        wifi.cloned-mac-address stable

$ nmcli connection up "My Wi-Fi"

$ ip link show

Stable MAC Address Generation

The “stable” method warrants more explanation. In a way it is similar to “random”, but instead it generates a stable, hashed value. This way every time the connection activates, the same address is generated. However, each connection generates a different address.

This is for example useful so that you get the same IP address from DHCP, which might not be the case with “random”. Or a captive-portal might remember your login-status based on the MAC address. With “random” you may be required to re-authenticate on every connect.

The “stable” mode still makes you easily recognizable when you re-connect to a previous network, but your hardware MAC address is hidden and tracking you across different networks may be harder (YMMV).

The stable address is generated by hashing a private key from /var/lib/NetworkManager/secret_key, the ifname of the device, and a stable-id. The stable-id by default is the UUID of the connection (“connection.uuid”), unless you configure the new property “connection.stable-id“. The latter allows you to have multiple connections that generate the same MAC address. Note that “connection.stable-id” property is also used when generating stable-privacy IPv6 addresses (“ipv6.addr-gen-mode”, RFC 7217).

Format of the MAC Address

The “random” and “stable” modes both generate a MAC address. By default, all 48 bits of the MAC address are scrambled except the following two bits. For one, the LSB of the first octet which must always be cleared to indicate a unicast MAC address. And then, the 2nd-LSB of the first octet is set to indicate a locally administered address — contrary to a burned-in address. This has the same effect as calling macchanger --random with respect to which bits are scrambled.

Which bits are scrambled is configurable by the per-connection properties “ethernet.generate-mac-address-mask” and “wifi.generate-mac-address-mask” [man]. During Wi-Fi scanning, the per-device property “wifi.scan-generate-mac-address-mask” is used instead [man].

The property works as follows. If the mask-setting contains one MAC address, that address is used as a mask. For example “FF:FF:FF:00:00:00” results in randomizing the lower 3 octets and use the vendor OUI of the device’s permanent MAC address. This is similar to macchanger --ending, except that NetworkManager uses the permanent MAC address of the device while macchanger preserves the OUI of the current address.

Update-2016-11-04: it doesn’t use the permanent MAC address, instead the “initial” MAC address, that is the current MAC address that was configured on the device outside of NetworkManager.

If after the initial mask a second MAC address follows, that address is used instead of the device’s permanent address. For example “FF:FF:FF:00:00:00 00:50:E4:00:00:00” sets the OUI to “00:50:E4” but randomizes the last 3 octets. Likewise, “02:00:00:00:00:00 00:00:00:00:00:00” scrambles all bits but clears the second LSB of the first octet, thus creating a burned-in address like macchanger --random --bia.

Actually, there can follow arbitrary many MAC addresses after the mask, in which case one will be chosen randomly. “02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00” will scramble all 47 bits — except the unicast bit which must be always cleared. This allows you to specify a list of OUIs.

Global Default Configuration

NetworkManager supports certain per-connection properties to fallback to a globally configured default value. By having “cloned-mac-address” or “generate-mac-address-mask” unset, it allows fallback to a value configured in NetworkManager.conf.

For example, I have a file /etc/NetworkManager/conf.d/30-mac-randomization.conf like:

# "yes" is already the default for scanning


which sets the default fallback to random. Only for a few selected connection profiles I explicitly switch the per-connection setting to “stable”.

Note: distributions and packages are advised to install configuration snippets to /usr/lib/NetworkManager/conf.d directory instead of /etc.

What’s missing?

What feature do you miss?

One idea would be to support some special “connection.stable-id”. This would allow to implement a “change daily” feature like Windows 10 has. Allowing for a stable-id “time: <date> <time> <period>” could have the effect to start at <date>-<time> and generate a new ID each <period> time. Say, “time: 2016-08-22 6:00:00 7d” could mean to generate a new ID every Monday at 6:00 a.m. Of course, the ID only gets re-generated upon activation of a connection.

Update-2017-01-25: since 1.6, NetworkManager supports dynamic stable-ids like "${BOOT}", "${CONNECTION}", "${RANDOM}" or any combination of these. This also affects RFC7217 stable privacy IPv4 addresses [commit], [example].

Another idea would be to allow a special keyword “preserve” in “generate-mac-address-mask”. It could be used to set a value like “FF:FF:FF:00:00:00 preserve” which should have the same effect as macchanger --ending and use the current MAC address instead of the permanent one.

If you have problems, questions or suggestions, meet us on mailing list, IRC (#nm on freenode) or check our documentation and our bugtracker.

Towards NetworkManager 1.2





What about 1.0?





Where and How?


