Qubes OS - Disposable sys-net - Automatically connect wifi
0 - Description
This guide aims to answer to the (reccuring?) question:
How can I make my wifi connection remember my password?
In the “Configuration file” main section, you have 3 methods.
In the “RPC service” main section, you have an example of how to store your wifi credentials outside of the disposable template.
1 - Configuration file
1.1 - Copy the config file
Connect to your wifi with the Network-Manager panel icon.
Once connected, open the Network-Manager setting (right cick on the panel icon) and edit your connection:
Network-Manager > Edit Connections > Wi-FI: YOUR_SSID > Wi-Fi tab
In the Device
field you might have wls6
or wls7
value (or else).
Delete it and leave the field empty.
Optionaly, instead of empty value, you could use your MAC address only (e.g. 3C:97:0E:42:1A:19
).
Save and close the Network-Manager setting.
In your sys-net
disposable:
Copy your config file to your dispobable template:
[user@sys-net-dvm ~]$ qvm-copy /etc/NetworkManager/system-connections/MY_SSID.nmconnection
Replace MY_SSID
with your wireless SSID name.
Choose your sys-net
disposable template in the popup prompt.
Shutdown your sys-net
disposable.
In your sys-net
disposable template:
Create NM-system-connections
directory:
[user@sys-net-dvm-template ~]$ sudo mkdir -p /rw/config/NM-system-connections/
Copy your config file into it:
[user@sys-net-dvm-template ~]$ sudo cp /home/user/QubesIncoming/sys-net-dvm/MY_SSID.nmconnection /rw/config/NM-system-connections/
Delete QubesIncoming
directory:
[user@sys-net-dvm-template ~]$ rm -r /home/user/QubesIncoming
Shutdown your sys-net
disposable template.
Start your sys-net
disposable.
1.2 - Create the config file
In your sys-net
disposable template:
Create the following script (e.g /home/user/auto_connect_wifi.sh
).
#!/usr/bin/bash
wifi_dir=/rw/config/NM-system-connections/
wifi_cfg=$wifi_dir/home.nmconnection
sudo mkdir -p $wifi_dir
echo '
[wifi]
ssid=MY_SSID_NAME
[wifi-security]
key-mgmt=wpa-psk
psk=MY_PASSWORD' | sudo tee $wifi_cfg > /dev/null
sudo chmod 600 $wifi_cfg
These 3 fields (ssid
, key-mgmt
and psk
) are the minimum required.
The non-defined fields will use default values.
Replace home.nmconnection
with your SSID or any meaningful name (e.g. SSID.nmconnection
).
Replace MY_SSID_NAME
and MY_PASSWORD
with your values.
Make your script executable and launch it.
[user@sys-net-dvm-template ~]$ chmod +x auto_connect_wifi.sh
[user@sys-net-dvm-template ~]$ ./auto_connect_wifi.sh
[user@sys-net-dvm-template ~]$ rm auto_connect_wifi.sh
Shutdown your sys-net
disposable template.
Start your sys-net
disposable.
1.3 - Connect in the disposable template
This method is not recommended.
Because it require to connect your disposable template to the network.
And because there are other methods available.
Shutdown your sys-net
disposable.
Change the setting of your sys-net
disposable template:
Set the virtualization mode to hvm
:
[user@dom0 ~]$ qvm-prefs sys-net-dvm-template virt_mode hvm
Attach your wireless controller:
wifi_devid
is your wireless network id
as shown by qvm-pci
(e.g. dom0:00_42.0
).
[user@dom0 ~]$ wifi_devid=$(qvm-pci | grep Network | cut -d ' ' -f 1)
[user@dom0 ~]$ qvm-pci attach sys-net-dvm-template $wifi_devid
Enable the Network-Manager service:
netvm
must be set to none
(it should already be the case).
[user@dom0 ~]$ qvm-prefs sys-net-dvm-template provides_network true
Start your sys-net
disposable template.
Connect to your wifi with the Network-Manager panel icon.
In your connection setting:
Delete the Device
field value and leave the field empty.
Shutdown your sys-net
disposable template.
Disable the Network-Manager service:
[user@dom0 ~]$ qvm-prefs sys-net-dvm-template provides_network false
Detach your wireless controller:
[user@dom0 ~]$ qvm-pci detach sys-net-dvm-template $wifi_devid
Set back the virtualization mode to pvh
:
[user@dom0 ~]$ qvm-prefs sys-net-dvm-template virt_mode pvh
Start your sys-net
disposable.
2 - RPC service
Somehow mandatory reading to understand this part of the guide.
https://www.qubes-os.org/doc/qrexec/
Brief summary of client/server definition for this guide:
The client is your sys-net
disposable.
The server is where you will store your wifi credentials.
The client will ask the server to send the wifi credentials (via stdin/stdout).
2.1 - AdminVM server
In this section, the wifi credentials will be stored in the @adminvm
(aka dom0
).
2.1.1 - RPC policies
In dom0
, create the policies to allow the communication between the server and the client.
echo '
qubes.user.ConnectWifi + sys-net-dvm @adminvm allow
qubes.user.ConnectWifi * @anyvm @anyvm deny' \
| sudo tee -a /etc/qubes/policy.d/30-user.policy > /dev/null
2.1.2 - Server
In dom0
, create the script that will send the wifi credentials to the client.
server_script=/etc/qubes-rpc/qubes.user.ConnectWifi
echo "
#!/usr/bin/bash
echo 'MY_SSID' 'MY_PASSWD'" | sudo tee $server_script > /dev/null
sudo chmod +x $server_script
2.1.3 - Client
In your sys-net
disposable template, create the script that will connect your wifi.
client_script=/rw/config/qConnectWifi
echo '
#!/usr/bin/bash
read my_ssid my_passwd
nmcli device wifi connect "$my_ssid" password "$my_passwd"' \
| sudo tee $client_script > /dev/null
sudo chown user:user $client_script
sudo chmod +x $client_script
In your sys-net
disposable template, append the below code to the rc.local
script.
The sys-net
disposable template could be used for all of your system qubes (e.g. sys-net
, sys-firewall
and sys-usb
).
Therefore, we test if the qube is sys-net-dvm
.
If this is the case, we wait until the network and Network-Manager are ready, then we make an RPC call to connect our wifi.
echo '
/etc/qubes-rpc/qubes.WaitForSession
if [[ $(qubesdb-read /name) == sys-net-dvm ]]
then
until systemctl is-active network.target; do sleep 1; done
nm-online --quiet --wait-for-startup
qrexec-client-vm @adminvm qubes.user.ConnectWifi '$client_script'
fi' | sudo tee -a /rw/config/rc.local > /dev/null
2.2 - App qube server
In this section, the wifi credentials will be stored in an app qube (e.g vault-wifi
).
2.2.1 - RPC policies
In dom0
, create the policies (@adminvm
is replaced with vault-wifi
).
echo '
qubes.user.ConnectWifi + sys-net-dvm vault-wifi allow
qubes.user.ConnectWifi * @anyvm @anyvm deny' \
| sudo tee -a /etc/qubes/policy.d/30-user.policy > /dev/null
https://www.qubes-os.org/doc/admin-api/
In dom0
, add these policies.
admin.vm.CurrentState
will be used in the client to know when vault-wifi
is running/ready.
admin.vm.Start
and admin.vm.Shutdown
will allow the client to start and stop the server.
These 2 policies (Start
and Shutdown
) are optional, you could instead make vault-wifi
to start automatically on boot.
echo '
admin.vm.CurrentState + sys-net-dvm vault-wifi allow target=@adminvm
admin.vm.Start + sys-net-dvm vault-wifi allow target=@adminvm
admin.vm.Shutdown + sys-net-dvm vault-wifi allow target=@adminvm' \
| sudo tee -a /etc/qubes/policy.d/30-admin-policy.policy > /dev/null
2.2.2 - Server
In your vault-wifi
app qube, create the script to send the wifi credentials.
This time, instead of creating it directly in /etc/qubes-rpc/
, let’s store it in the home directory.
server_script=/home/user/qubes_connect_wifi.sh
echo "
#!/usr/bin/bash
echo 'MY_SSID' 'MY_PASSWD'" > $server_script
chmod +x $server_script
As you want to use this script only in the app qube and not in the template, create a symbolic link to /usr/local/etc/qubes-rpc/qubes.user.ConnectWifi
(instead of /etc/qubes-rpc/
in the template).
sudo mkdir -p /usr/local/etc/qubes-rpc/
sudo ln -s $server_script /usr/local/etc/qubes-rpc/qubes.user.ConnectWifi
2.2.3 - Client
In your sys-net
disposable template, create the script that will connect your wifi.
This is the same one as with dom0
as server.
In your sys-net
disposable template, append the below code to the rc.local
script.
(optional) We start the vault-wifi
qube.
We wait until vault-wifi
is running before making the RPC call.
(optional) We shutdown the vault-wifi
qube.
client_script=/rw/config/qConnectWifi
echo '
/etc/qubes-rpc/qubes.WaitForSession
if [[ $(qubesdb-read /name) == sys-net-dvm ]]
then
qrexec-client-vm vault-wifi admin.vm.Start < /dev/null
while [[ $(qrexec-client-vm vault-wifi admin.vm.CurrentState < /dev/null \
| sed -E "s/.*power_state=([^ ]+).*/\1/") != Running ]]
do
sleep 1
done
until systemctl is-active network.target; do sleep 1; done
nm-online --quiet --wait-for-startup
qrexec-client-vm vault-wifi qubes.user.ConnectWifi '$client_script'
qrexec-client-vm vault-wifi admin.vm.Shutdown < /dev/null
fi' | sudo tee -a /rw/config/rc.local > /dev/null
2.3 - Several connections
In this section, the wifi credentials of several wifi connections will be stored in @adminvm
.
This can be adjusted to store them in an app qube.
2.3.1 - RPC policies
In dom0
, create the necessary policies.
We use the RPC service argument to differentiate each network (the +something
after the service).
echo '
qubes.user.ConnectWifi +home sys-net-dvm @adminvm allow
qubes.user.ConnectWifi +work sys-net-dvm @adminvm allow
qubes.user.ConnectWifi * @anyvm @anyvm deny' \
| sudo tee -a /etc/qubes/policy.d/30-user.policy > /dev/null
2.3.2 - Server
In dom0
, create the script that will send the wifi credentials to the client.
We will send different wifi credentials according to the received argument.
server_script=/etc/qubes-rpc/qubes.user.ConnectWifi
echo "
#!/usr/bin/bash
case $1 in
home) echo 'MY_HOME_SSID' 'MY_HOME_PASSWD';;
work) echo 'MY_WORK_SSID' 'MY_WORK_PASSWD';;
*) ;;
esac" | sudo tee $server_script > /dev/null
sudo chmod +x $server_script
2.3.3 - Client
In your sys-net
disposable template, create the script that will connect your wifi.
This is the same one as with dom0
as server.
In your sys-net
disposable template, append the below code to the rc.local
script.
We scan the available wifi connection and connect accordingly.
The first match will be use as an argument to our RPC call.
client_script=/rw/config/qConnectWifi
echo '
/etc/qubes-rpc/qubes.WaitForSession
if [[ $(qubesdb-read /name) == sys-net-dvm ]]
then
until systemctl is-active network.target; do sleep 1; done
nm-online --quiet --wait-for-startup
wifi_ssids=($(nmcli --get-values SSID device wifi))
rpc_arg=$(for ssid in "${wifi_ssids[@]}"
do
[[ $ssid == home ]] && echo home && break
[[ $ssid == work ]] && echo work && break
done)
qrexec-client-vm @adminvm qubes.user.ConnectWifi+$rpc_arg '$client_script'
fi' | sudo tee -a /rw/config/rc.local > /dev/null
3 - Remarks
For the RPC service:
It shouldn’t happens, but if there is a race condition and your wifi is not automatically connected.
Open your sys-net
disposable terminal and launch the RPC call manually.
[user@sys-net-dvm ~]$ cat /rw/config/rc.local
Copy/paste the qrexec-client-vm
call and execute it.
This race condition only happens to me twice in a month of testing.
And the two times was because I had modified dom0
max memory.