0

I'm trying to write an iptables rule that applies to multiple interfaces based on a variable. Which of the rules is more efficient / faster ? Is there a better way to write this rule with a minimum of code ?

#Variable
Ext_INTF="eth0 usb0 tun0 tun1"

1)

for i in $Ext_INTF;
do
iptables -A FORWARD -i $i -j DROP
done

2)

iptables -A FORWARD -i $Ext_INTF -j DROP
uihdff
  • 435
  • 2
  • 7
  • 17

1 Answers1

1

Method 2 doesn't work — it produces an invalid iptables invocation. Whatever you thought it might do, it only adds one iptables rule, and you can't match an arbitrary set of interfaces in a single rule. Method 1 is the normal way and pretty much the only way.

Not that efficiency of setting iptables rules is a concern. You'd have to work very hard to do something noticeably non-optimal. The concerns here are to get the rules right, possibly the efficiency of the rules themselves, and keep the script readable so that it's easy to maintain.

Writing $Ext_INTF — a variable substitution outside double quotes — splits the value of the variable into whitespace-separated parts, and then expands each part as a wildcard pattern matching file names. Here the variable doesn't contain any wildcard character (\[*?). Thus for i in $Ext_INTF; … loops over the words in the value of the variable. In general you should only use variable substitutions inside double quotes, because $Ext_INTF means “the value of Ext_INTF” only inside double quotes, but here you want the splitting to happen, and the parts don't contain any shell wildcard characters.

Ext_INTF="eth0 usb0 tun0 tun1"
for i in $Ext_INTF; do
  iptables -A FORWARD -i "$i" -j DROP
done

In bash and ksh, but not in plain sh, you can use an array instead of a string variable. (And in zsh you must use an array or explicitly request splitting with $=Ext_INTF.) You have to type a few more characters, but this makes the intent clearer, and allows the elements to contain whitespace and wildcards if need be.

Ext_INTF=(eth0 usb0 tun0 tun1)
for i in "${Ext_INTF[@]}"; do
  iptables -A FORWARD -i "$i" -j DROP
done
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
  • What are the consequences of not placing the $i in quotes ("$i") ? – uihdff May 15 '17 at 13:46
  • 1
    @uihdff [See the thread I linked](https://unix.stackexchange.com/questions/131766/why-does-my-shell-script-choke-on-whitespace-or-other-special-characters). See also [Stéphane Chazelas's examples of how it can be a security hole](https://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable-in-bash-posix-shells/171347#171347). – Gilles 'SO- stop being evil' May 15 '17 at 21:48
  • For brevity, I wrote iptables instead of $IPTABLES which points to /sbin/iptables. Does that pose a vulnerability ? All referenced variables whether they are multi-valued or not, should be double quoted, correct ? – uihdff May 16 '17 at 01:55
  • 1
    @uihdff If you know that the value of `IPTABLES` doesn't contain any whitespace or wildcard characters and you aren't changing the value of `IFS` then writing `$IPTABLES` without quotes is ok. However making such assumptions defeats the purpose of using a variable. What if you want to use a different version of `iptables` that's located in `/opt/advanced networking/bin`? Either write `iptables` (there's very little reason to replace `iptables` by something else) or `"$IPTABLES"`. – Gilles 'SO- stop being evil' May 16 '17 at 11:04