0

In PHP 7.3.33 and Apache 2.4 I want to run iptables from PHP (web server enviroment) in order to block/unblock IPs, from command line, this works fine:

/usr/sbin/iptables --insert INPUT --source example.com --jump DROP

But if I try from PHP with this code:

exec('/usr/sbin/iptables --insert INPUT --source example.com --jump DROP', $return);
print_r($return);

I get a blank result and iptables rule is not added:

Array
(
)

However, iptables path seems correct and iptables runs, because the --help command returns content, so why doesn't the above command work then ?

exec('/usr/sbin/iptables --help', $return);
print_r($return);
Array
(
    [0] => iptables v1.8.4
    [1] => 
    [2] => Usage: iptables -[ACD] chain rule-specification [options]
    [3] =>  iptables -I chain [rulenum] rule-specification [options]
    [4] =>  iptables -R chain rulenum rule-specification [options]
    [5] =>  iptables -D chain rulenum [options]
    [6] =>  iptables -[LS] [chain [rulenum]] [options]
    [7] =>  iptables -[FZ] [chain] [options]
    [8] =>  iptables -[NX] chain
    [9] =>  iptables -E old-chain-name new-chain-name
    [10] =>     iptables -P chain target [options]
    [11] =>     iptables -h (print this help information)
    [12] => 
    [13] => Commands:
    [14] => Either long or short options are allowed.
    [15] =>   --append  -A chain        Append to chain
    [16] =>   --check   -C chain        Check for the existence of a rule
    [17] =>   --delete  -D chain        Delete matching rule from chain
    [18] =>   --delete  -D chain rulenum
    [19] =>                 Delete rule rulenum (1 = first) from chain
    [20] =>   --insert  -I chain [rulenum]
    [21] =>                 Insert in chain as rulenum (default 1=first)
    [22] =>   --replace -R chain rulenum
    [23] =>                 Replace rule rulenum (1 = first) in chain
    [24] =>   --list    -L [chain [rulenum]]
    [25] =>                 List the rules in a chain or all chains
    [26] =>   --list-rules -S [chain [rulenum]]
    [27] =>                 Print the rules in a chain or all chains
    [28] =>   --flush   -F [chain]      Delete all rules in  chain or all chains
    [29] =>   --zero    -Z [chain [rulenum]]
    [30] =>                 Zero counters in chain or all chains
    [31] =>   --new     -N chain        Create a new user-defined chain
    [32] =>   --delete-chain
    [33] =>          -X [chain]     Delete a user-defined chain
    [34] =>   --policy  -P chain target
    [35] =>                 Change policy on chain to target
    [36] =>   --rename-chain
    [37] =>          -E old-chain new-chain
    [38] =>                 Change chain name, (moving any references)
    [39] => Options:
    [40] =>     --ipv4  -4      Nothing (line is ignored by ip6tables-restore)
    [41] =>     --ipv6  -6      Error (line is ignored by iptables-restore)
    [42] => [!] --proto -p proto    protocol: by number or name, eg. `tcp'
    [43] => [!] --source    -s address[/mask][...]
    [44] =>                 source specification
    [45] => [!] --destination -d address[/mask][...]
    [46] =>                 destination specification
    [47] => [!] --in-interface -i input name[+]
    [48] =>                 network interface name ([+] for wildcard)
    [49] =>  --jump -j target
    [50] =>                 target for rule (may load target extension)
    [51] =>   --goto      -g chain
    [52] =>                    jump to chain with no return
    [53] =>   --match   -m match
    [54] =>                 extended match (may load extension)
    [55] =>   --numeric -n      numeric output of addresses and ports
    [56] => [!] --out-interface -o output name[+]
    [57] =>                 network interface name ([+] for wildcard)
    [58] =>   --table   -t table    table to manipulate (default: `filter')
    [59] =>   --verbose -v      verbose mode
    [60] =>   --wait    -w [seconds]    maximum wait to acquire xtables lock before give up
    [61] =>   --wait-interval -W [usecs]    wait time to try to acquire xtables lock
    [62] =>                 default is 1 second
    [63] =>   --line-numbers        print line numbers when listing
    [64] =>   --exact   -x      expand numbers (display exact values)
    [65] => [!] --fragment  -f      match second or further fragments only
    [66] =>   --modprobe=<command>      try to insert modules using this command
    [67] =>   --set-counters PKTS BYTES set the counter during insert/append
    [68] => [!] --version   -V      print package version.
)
adrianTNT
  • 1,077
  • 6
  • 22
  • 43

1 Answers1

1

As what user are you running the iptables command? If you run iptables as a non-root user, it will print an error message to stderr and return an error code, but when you write:

exec('/usr/sbin/iptables --insert INPUT --source example.com --jump DROP', $return);

You are (a) only capturing stdout and (b) you're not checking the error code. That code runs just fine for me if I run it from the command line as root. E.g, if in iptables.php I have this content:

<?php

exec('iptables --insert INPUT --source example.com --jump DROP', $output, $retval);
echo "return code: $retval\n";
echo "output:\n";
print_r($output);
?>

I get as output:

return code: 0
output:
Array
(
)

And I see the rule has been created:

# iptables -S INPUT
-P INPUT ACCEPT
-A INPUT -s 93.184.216.34/32 -j DROP

But if I run the same thing as a non-root user:

$ php iptables.php
iptables v1.8.8 (nf_tables): Could not fetch rule set generation id: Permission denied (you must be root)

return code: 4
output:
Array
(
)

Note that the error message was printed directly on the console and was not cpatured by PHP, so we see an empty output array -- but we do see an error return code. Depending on how you're running the code, you may not be able to see the error message (if you're running this via a web server, the error message may show up in the server error logs).

larsks
  • 43,623
  • 14
  • 121
  • 180
  • yes, this was exactly the case and I remember `4` was the code returned but not the above message in web server enviroment (as you said) I thought if the `iptables --help` runs fine it has the right permissions, but no, iptables needs more permissions when adding/deleting rules. – adrianTNT Jan 31 '23 at 14:04