1

Scope

I am working on a bash-script for handling repetitive tasks with putting wlan interfaces on, of, in and out monitor mode and displaying relevant information thru each step.

I started out something like this:

wx="wlan${1}"
wxm="${wx}mon"

# $wx
echo "$wx"
echo -n "stop $wxm if up....";airmon-ng stop $wxm  &> /dev/null; echo " done.";
echo -n "bringing down $wx if up....";ifconfig $wx down  &> /dev/null; echo " done.";
echo -n "changing mac to random....";macchanger -r $wx  &> /dev/null; echo " done.";
echo "mac-adresses randomized"
echo -n "bringing up $wx....";ifconfig $wx up&> /dev/null; echo " done.";
echo -n "putting $wx in monitor mode....";airmon-ng start $wx  &> /dev/null; echo " done.";
echo "$wxm successfully put in monitor mode"
wait

I tried to different ways to import available wlan-nics and with some help from a friend, ended up with this function using find

function setup_if() {
  local wx="${1}"
  local wxm="${wx}mon"

  echo "setting up: $wx..."
  run_cmd airmon-ng stop $wxm &&
    run_cmd ifconfig $wx down &&
    run_cmd macchanger -r $wx &&
    run_cmd ifconfig $wx up &&
    run_cmd airmon-ng start $wx
  wait
}

for interface in $(find /sys/class/net -name 'wlan*'); do
  interface=$(basename ${interface})
  setup_if ${interface}  || echo "FAILED: ${interface} $previous_command"
done

Where I got stuck

Now for the next step i want to print some useful information about the status of the wlans like cat /sys/class/net/wlan*/address and iwconfig |grep --regexp wlan

Finally i would like to export my operating nics to another script for capturing traffic with airodump-ng like airodump-ng -w /root/pcap/air_capture -c 1,4,6,8,11 $all_operating_wlans

Questions:

  1. How do i make unique variables for all detected wlans, like $w1, $w2 etc. I haven't figured out how to make it thru find /sys/class/net -name 'wlan?mon'since it is several lines of output that requires several variables.

  2. How to make those variables accessible to my other script that will capture packets.

  3. Are there better ways to achieve the same results still in a bash-script context?

This is my first question on stackoverflow, and i'm happy to receive feedback on how my next question could be better!

Community
  • 1
  • 1
Tapper
  • 5
  • 1
  • 7

1 Answers1

0

In programming in general it is common to create an array variable when there is a need to store a dynamic collection of values. In Bash 4, it is possible to create an indexed array using mapfile built-in function:

mapfile -t ifaces <<< "$(find /sys/class/net -mindepth 1 -printf '%f\n')"

In this example, mapfile creates an indexed array ifaces by reading lines from a here string. The content of the here string is built using the command substitution. Trailing newlines are removed with -t option.

Note the use of -mindepth 1 option. The option excludes the /sys/class/net directory itself.

Instead of invoking basename, the command uses the -printf action (in terms of find) with %f format specifier:

%f File's name with any leading directories removed (only the last element).

The ifaces variable will be available in the current scope. The array can be traversed as follows:

for i in "${ifaces[@]}"
do
  printf "%s\n" "$i"
done

Note, mapfile was introduced in Bash version 4.

Process Substitution

The here string can be replaced with process substitution:

mapfile -t ifaces < <(find /sys/class/net -mindepth 1 -printf '%f\n')

It's just a matter of preference.

Using mapfile in a Pipeline

It is possible to use mapfile in a pipeline, but the value of the array will be available only in the scope of the piped command. For example, the following script prints zero:

find /sys/class/net -mindepth 1 -printf '%f\n' | mapfile -t ifaces
printf "%d" "${#ifaces[@]}"

In order to use the ifaces variable within the pipe context, use the grouping commands, e.g.:

find /sys/class/net -mindepth 1 -printf '%f\n' | {
  mapfile -t ifaces
  printf "%d" "${#ifaces[@]}"
}

Obviously, in this case, the scope of the ifaces variable will be limited to the group.

Using Functions

There is a number of ways to return a value from a function. The simplest way is to set, or modify a global variable:

get_ifaces() {
  mapfile -t ifaces < <(find /sys/class/net -mindepth 1 -printf '%f\n')
}

But it is a bad practice, since it is possible to overwrite an existing variable unintentionally.

Another way is to write a function that accepts a variable name:

get_ifaces() {
  local var_name=$1
  local __ifaces

  mapfile -t __ifaces < <(find /sys/class/net -mindepth 1 -printf '%f\n')

  eval $var_name=\( "${__ifaces[@]}" \)
}

get_ifaces ifaces

Ah, I must write this, as I have eval in the sample: warning, warning, warning! You should avoid using eval as much as you can, as it may evaluate more than expected See this discussion, for instance. But in this particular example, I don't see any risks of using eval.

Community
  • 1
  • 1
Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60