There more than one ways to set up your wifi on your linux system, and almost all of them would require you to basically install a network manager of some sort, to handle everything for you. But here i am going to show you a mininal way to set up your own wifi network manager.
Dependencies:
- wpa_supplicant
- A dhcp client ( e.g. dhclient or dhcpcd )
- iproute2
- libnotify ( optional )
wpa_supplicant NetworkManager and many other network management tools uses wpa_supplicant behind the scene to actually establish the (secure) connection. For an insecure network you don't even need that, Just the good old iw is enough. But Here we considering secure networks as well so we would be using wpa_supplicant.
dhcp A dhcp client becomes necessary for establishing and securing an IP address from the Access Point in a dynamic set up, hence we would need that too.
iproute2 iproute2 gives us the ever important tool ip that we can utilise to manage our network interfaces
notify-send to send qute little notifications
Some of this would be present your system .If not, install them.
First let's set up the basics
# your interface name, check it with the ip addr command. For me it's wlo1
Interface="wlo1"
# Your dhcp client, for me it is dhcpcd
dhcpclient="dhcpcd"
# Path to your local wpa_supplicant directory
WPA_SUPPLICANT=$HOME/.config/wpa
#if the directory doesn't exist this one takes care of it.
mkdir -p $WPA_SUPPLICANT
WPA_SUPPLICANT=$WPA_SUPPLICANT/wpa_supplicant
#Make sure the interface is not blocked
sudo rfkill unblock "$(rfkill|grep wlan|cut -d' ' -f2)"
# Check whether the interface down.If so, set it up
[ "$(grep $Interface <(ip link show up ))" ] || sudo ip link set $Interface up
Check whether required programs are installed
check()
{
[ $(type $1 > /dev/null) ] || { echo "$1 not installed" && exit 1 ; }
}
check wpa_supplicant
check $dhcpclient
check ip
type notify-send > /dev/null && notify=1
And now we will set up functions that takes care of specific tasks.
First we would configure a help() function that basically outputs basic usage with fine figlet ASCII text of the program name accompanied by a one line description of the program This function would display the options along with a short description of what it means:
help() {
cat <<END
$(figlet $(basename $0))
A minimal wifi network manager
____________________________________________________
Args --------- Meaning
____________________________________________________
-n|-new ---------- create new connnection/password
-s|-term --------- Terminate wpa_supplicant & dhcp client
-h|-help --------- Help
-v|-verbose ------ Verbose output
END
exit 0
}
Let's write the code to generate/handle new connection:
# Generate new network/password
new_connection() {
(( don )) || return
read -r -p "Entere the SSID: " SSID
__asterisk_prompt_for_passphrase
read -r -p "Would you like to control wpa_supplicant with its frontend tool wpa_cli?(y/N) " YesNo
[[ $YesNo =~ [Yy] ]] && echo -e "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=$USER\nmac_addr=1\npreassoc_mac_addr=1\ngas_rand_mac_addr=1" > "$WPA_SUPPLICANTCONF"
[[ $SSID ]] && wpa_passphrase "$SSID" "$passphrase" >> "$WPA_SUPPLICANTCONF"
(( $(pgrep wpa_supplicant) )) && terminate
don=1
unset YesNo
main
}
In the above function, notice the line echo -e "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=$USER\nmac_addr=1\npreassoc_mac_addr=1\ngas_rand_mac_addr=1"
.
By assigning the ctrl_interface
we can control wpa_supplicant
via the wpa_cli
tool. wpa_supplicant
can generate random MAC addresses for your interface and the options mac_addr
, preassoc_mac_addr
,gas_rand_mac_addr
configures it do exactly that. Since we want to be able to control it with wpa_cli
and also have it manage random MAC addresses for our interface, we put it in our wpa_supplicant
configuration file.
Then The function that manages termination of the connection, it basically uses wpa_cli to kill the network and then kills the dhcp client as well. Use it only when you are not using the dhcp client for networks.
# Teminate connection
terminate() {
sudo pkill $dhcpclient
sudo wpa_cli terminate $Interface && (( notify )) && notify-send "" "Wifi disconnected"
}
wpa_supplicant
handles password protected networks, so we need to have a secure way of typing our passwords. We do that with this function that masks your input characters with asterisks. This is an internal function and would called by other functions whenever required.
#generate asterisk for passphrase prompt
__asterisk_prompt_for_passphrase() {
unset passphrase
prompt="Enter Passphrase: "
while IFS= read -r -p "$prompt" -s -n 1 char
do
#Enter - accept passphrase
if [[ $char == $'\0' ]] ; then
echo
break
fi
#Backspace
if [[ $char == $'\177' ]]; then
prompt=$'\b \b'
passphrase="${passphrase%?}"
else
prompt="*"
passphrase+="$char"
fi
done
}
The function is the core of our pgogram, the main function.
main() {
#you may require to mention a driver wrapper with -D nl80211,wext. Refer wpa_supplicant(8)
[ $( pgrep wpa_supplicant ) ] || { sudo wpa_supplicant -c "$WPA_SUPPLICANTCONF" -i"$Interface" -B && exit_code=$? ; }
if [[ $exit_code -eq 0 ]];then
echo "wpa supplicant initialised"
elif [[ -n $exit_code ]]; then
echo "wpa supplicant initialisation error: $exit_code"
exit 1
fi
#6. If dhcp client is not running, start it to get a lease:
if [[ $(pidof $dhcpclient) ]]; then
sudo $dhcpclient -k $Interface
sudo $dhcpclient $Interface
else
echo "starting $dhcpclient ..."
echo "scanning for network..."
sudo $dhcpclient $Interface
e_status=$?
if [[ $e_status -eq 1 ]]; then
(( notify )) && notify-send "No wifi found" "Check and confirm the network is visible"
echo "No wifi network found"
exit 1
elif [[ $e_status -ne 0 ]]; then
(( notify )) && notify-send "Wifi problem" "Couldn't initiate connection : $e_status "
exit $?
fi
echo "$dhcpclient started!"
fi
echo " Connection established"
(( notify )) && notify-send " " "Connection established"
unset dhcpclient Interface
if ping google.com -c 1 &>/dev/null; then
(( notify )) && notify-send "Network is up" "enjoy 🙂"
return 0
fi
(( notify )) && notify-send "😢" "Can't ping google"
}
The necessary functions are all set. Now some logic that that would prompt the user for establishing a new connection if no configured network is detected:
# generate wpa_supplicant.conf with SSID and passphrase if it doesn't already exist:
if ! [ -s "$WPA_SUPPLICANTCONF" ]; then
read -r -p "It appears no Network is configured. Would you like to configure one(y/N)? " YN
[[ $YN =~ [nN] || -z $YN ]] && exit 0;
if [[ $YN =~ [yY] ]]; then
read -r -p "Would you like to control wpa_supplicant with its frontend tool wpa_cli?(y/N) " YesNo
[[ $YesNo =~ [Yy] ]] && echo -e "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=$USER" > "$WPA_SUPPLICANTCONF"
read -r -p "Entere the SSID: " SSID
__asterisk_prompt_for_passphrase
wpa_passphrase "$SSID" "$passphrase" >> "$WPA_SUPPLICANTCONF"
chmod 600 "$WPA_SUPPLICANTCONF"
(( $(pgrep wpa_supplicant) )) && terminate
unset YN
main
don=1
else
echo "Wrong choice" >&2
echo "try again" >&2
exit 1
fi
fi
now we use getopt to scan through the options being passed and call the assigned functions accordingly.
OPT=$(getopt -o :hntv --long :help,new,term,verbose -a -n 'wifi_s' -- "$@")
eval set -- "$OPT"
unset OPT
while true;do
case $1 in
-h|--help) help ;shift ;;
-n|--new) new_connection ;shift ;;
-t|--term) terminate ; shift ;;
-v|--verbose) set -x;shift ;;
*) main;break;;
esac
done
------------------------------------------------------------------------------------
So all combined, the final script looks like this:
#!/usr/bin/sh
# Author: charlie39( iamkg050392 at gmail dot com)
# Github : https://github.com/charlie39
# I release this script in the public domain
# you can do whatever you like with it
# your wifi interface:
Interface="wlo1"
#y our DHCP client:e.g - dhcpcd,dhclient
dhcpclient="dhcpcd"
# path to your wpa_supplicant.conf
WPA_SUPPLICANTCONF=$HOME/.config/wpa/wpa_supplicant.conf
# mkdir -p "$WPA_SUPPLICANTCONF"
# make sure interface is not blocked:
sudo rfkill unblock "$(rfkill|grep wlan|cut -d' ' -f2)"
# initiate the interface:
[ "$(grep $Interface <(ip link show up ))" ] || sudo ip link set $Interface up
# you can install wireless_tools and get the SSIDs of available networks
# iwlist scan | grep SSID
check() {
type $1 > /dev/null || { echo "$1 is installed" && exit 1 ; }
}
check wpa_supplicant
check $dhcpclient
check ip
type notify-send >/dev/null && notify=1
help() {
cat <<END
$(figlet $(basename $0))
A minimal wifi network manager
____________________________________________________
Args --------- Meaning
____________________________________________________
-n|-new ---------- create new connnection/password
-s|-term --------- Terminate wpa_supplicant & dhcp client
-h|-help --------- Help
-v|-verbose ------ Verbose output
END
exit 0
}
# Generate new network/password
new_connection() {
(( don )) || return
read -r -p "Entere the SSID: " SSID
__asterisk_prompt_for_passphrase
read -r -p "Would you like to control wpa_supplicant with its frontend tool wpa_cli?(y/N) " YesNo
[[ $YesNo =~ [Yy] ]] && echo -e "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=$USER" > "$WPA_SUPPLICANTCONF"
[[ $SSID ]] && wpa_passphrase "$SSID" "$passphrase" >> "$WPA_SUPPLICANTCONF"
(( $(pgrep wpa_supplicant) )) && terminate
don=1
unset YesNo
main
}
# Teminate connection
terminate() {
sudo pkill -KILL $dhcpclient
sudo wpa_cli terminate $Interface && (( notify )) && notify-send "" "$Interface is disconnected"
exit
}
#generate asterisk for passphrase prompt
__asterisk_prompt_for_passphrase() {
unset passphrase
prompt="Enter Passphrase: "
while IFS= read -r -p "$prompt" -s -n 1 char
do
#Enter - accept passphrase
if [[ $char == $'\0' ]] ; then
echo
break
fi
#Backspace
if [[ $char == $'\177' ]]; then
prompt=$'\b \b'
passphrase="${passphrase%?}"
else
prompt="*"
passphrase+="$char"
fi
done
}
main() {
#you may require to mention a driver wrapper with -D nl80211,wext. Refer wpa_supplicant(8)
[ $( pgrep wpa_supplicant ) ] || { sudo wpa_supplicant -c "$WPA_SUPPLICANTCONF" -i"$Interface" -B && exit_code=$? ; }
if [[ $exit_code -eq 0 ]];then
echo "wpa supplicant initialised"
elif [[ -n $exit_code ]]; then
echo "wpa supplicant initialisation error: $exit_code"
exit 1
fi
#6. If dhcp client is not running, start it to get a lease:
if [[ $(pidof $dhcpclient) ]]; then
sudo $dhcpclient -k $Interface
sudo $dhcpclient $Interface
else
echo "starting $dhcpclient ..."
echo "scanning for network..."
sudo $dhcpclient $Interface
e_status=$?
if [[ $e_status -eq 1 ]]; then
(( notify )) && notify-send "No wifi found" "Check and confirm the network is visible"
echo "No wifi network found"
exit 1
elif [[ $e_status -ne 0 ]]; then
(( notify )) && notify-send "Wifi problem" "Couldn't initiate connection : $e_status "
exit $?
fi
echo "$dhcpclient started!"
fi
echo " Connection established"
(( notify )) && notify-send " " "Connection established"
unset dhcpclient Interface
if ping google.com -c 1 &>/dev/null; then
(( notify )) && notify-send "Network is up" "enjoy 🙂"
return 0
fi
(( notify )) && notify-send "😢" "Can't ping google"
}
# generate wpa_supplicant.conf with SSID and passphrase if it doesn't already exist:
if ! [ -s "$WPA_SUPPLICANTCONF" ]; then
read -r -p "It appears no Network is configured. Would you like to configure one(y/N)? " YN
[[ $YN =~ [nN] || -z $YN ]] && exit 0;
if [[ $YN =~ [yY] ]]; then
read -r -p "Would you like to control wpa_supplicant with its frontend tool wpa_cli?(y/N) " YesNo
[[ $YesNo =~ [Yy] ]] && echo -e "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=$USER" > "$WPA_SUPPLICANTCONF"
read -r -p "Entere the SSID: " SSID
__asterisk_prompt_for_passphrase
wpa_passphrase "$SSID" "$passphrase" >> "$WPA_SUPPLICANTCONF"
chmod 600 "$WPA_SUPPLICANTCONF"
(( $(pgrep wpa_supplicant) )) && terminate
unset YN
main
don=1
else
echo "Wrong choice" >&2
echo "try again" >&2
exit 1
fi
fi
OPT=$(getopt -o :hntv --long :help,new,term,verbose -a -n 'wifi_s' -- "$@")
eval set -- "$OPT"
unset OPT
while true;do
case $1 in
-h|--help) help $1 ;shift ;;
-n|--new) new_connection ;shift ;;
-t|--term) terminate ; shift ;;
-v|--verbose) set -x;shift ;;
*) main;break;;
esac
done
The complete script is on my github gist for easier copy pasting.