Switch WiFi Networks Via Command Line On Multiple Machines (Linux / Windows) At Once10 Jul 2016
I use two laptops at home. One runs Ubuntu and the other runs Windows 10. Generally I use a wireless router to connect the machines. But, sometimes when my broadband is down or slow, I use my Android phone as a wireless router and use it’s 3G connection to connect to the Internet.
The default method of switching networks is well known. On Ubuntu, I select the wireless network in Network Manager. On Windows, I do so using the network selection applet accessible from system tray.
Simple, right? Except that, there are a number of problems with this approach:
Laziness, impatience and dislike of UI’s (unless they are well programmed).
Windows network selection applet is too slow. Sometimes, it takes 30 seconds or more to populate it with available networks.
Windows keeps forgetting DNS settings as I switch between wireless networks. So, I have to go to network settings, select the wifi connection and edit the DNS settings manually. (I don’t know if it is the norm, but, when I go to network and sharing center in Windows 10, it just hangs before displaying the network connections.)
I run a proxy server on Windows machine which is used by Linux machine to access the Internet.
I run a web server on Linux which I generally access from browser on Windows.
There are samba shares on Linux which I access from Windows. When I switch networks, they become inaccessible until I change the Linux machine’s ip in hosts file.
I use Synergy to share keyboard and touchpad of Linux machine with Windows. Needless to say, it goes haywire when networks are switched. It needs to be restarted on Linux to pick up the new ip address on the new network and Windows needs its hosts files updated with ip address of Linux machine to connect to the Synergy server.
Taking care of all the above manually is tedious and directly makes the problem #1 worse.
In the following text and code, I’ll illustrate my approach of automating all of the above to be executed in a single step.
Windows part is a two step process. First, we establish WinRM session and upload powershell scripts. Second, we execute those scripts.
Start WinRM Session, Upload Powershell Scripts, Execute Them
On Windows machine, I have WinRM installed, enabled and configured. A python script does the job of uploading files and doing the WinRM stuff. Python script uses pywinrm module. It’s PyPI page has excellent notes on WinRM configuration as well.
The script uses pysftp module to upload files to Windows. (Although, it’ll be a good exercise to eliminate its use by using the powershell command Set-Content to upload files to Windows.) For setting up openssh and sftp on Windows, here are step by step instructions.
The script also uses redcmd module to parse the command line.
The script has two subcommands:
- switchnet: switches Windows to the given profile
- edit_hosts: edits Windows hosts file with given ip address for the Linux machine (See last step of Linux section for why we need this.)
When given a profile name with switchnet subcommand:
- it uploads relevant config file to Windows (using sftp, see details of config file in section for Linux)
- then uploads the network switching script itself to Windows
- starts a WinRM session using username/password (basic) authentication
- executes the script on Windows
Switch Wireless Network, Change DNS And Edit Hosts File
This step is part of the previous step.
A powershell script (named switchnet.ps1) does all the operations on Windows. As we saw in previous step, it is uploaded to Windows and executed via WinRM by a python script.
The script uses netsh to switch network and update the DNS server. It uses config file as described in section for Linux to read in the wifi profile name, last known ip of Linux machine and DNS server ip.
Optionally, Update IP Address Of Linux Machine
This is done from Linux, so, the details are in that section. Here, I’ll just show the powershell script (named edit_hosts.ps1) which uploaded to Windows and executed by python script.
Synergy Client Restart
It is not needed !! The synergy service picks up the updated ip address from hosts file and connects to it in a few seconds. This serendipitous behavior saves us some code.
Switch Wireless Network Using ‘nmcli’
Update Hosts File With Windows IP Address
This script receives profile name as first command line argument ($1).
Settings for a profile are stored in a config file in the same directory. The name of the config file is
Example contents of phone.cfg (comments not expected in actual config file):
wifi_profile=wrouter # wifi network profile name ubuntu_ip=192.168.0.101 # last assigned ip for Ubuntu machine win10_ip=192.168.0.100 # last assigned ip for Windows machine dns=192.168.0.1 # DNS server
The following code snippet first tries to get ip address of Windows machine (using its mac address) using ‘ip neigh’. The known problem with this approach is that neighbors aren’t updated for a while and we don’t get the ip address in this step. (Needs to be fixed.) So, upon failure, we use the last known stored ip from the config file. Of course, we only update the hosts file if it differs from the one already in there. (It saves a sudo password prompt.)
As mentioned above, Synergy server needs to be restarted to pick up the new ip address. So, we kill the running instance, restart it and send ‘Alt+F4’ to it so that it nicely minimizes to Unity top menu bar.
Update Linux IP Address In Windows Hosts File
As an additional step, if the ip address assigned to Linux machine changes, we edit the Windows hosts file to update it.
That’s it. I have outlined the major components. You can put them together as needed and write up the Linux shell script that calls them all from one place.
It leaves a lot to be desired.
- Updating the ip addresses. Both ‘ip’ and ‘arp’ are slow to update the neighbors. Using ‘dig’ to get it from router does not always work either.
- After switching network for Windows, WinRM session disconnects as Windows is now on a different network. It’ll be nice to reconnect and get results.
- As mentioned already, removing use of sftp to upload files can eliminate dependency on sftp/openssh.