0

When I run

$ /usr/sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT

from the command line it works fine. However when I compile and run this code

#include <unistd.h>
int main() {
    char *args[6];
    args[0] = "/usr/sbin/iptables";
    args[1] = "-I INPUT";
    args[2] = "-p tcp";
    args[3] = "--dport 80";
    args[4] = "-j ACCEPT";
    args[5] = NULL;
    execve(args[0], args, NULL);
}

I get the following output

$ ./code
iptables v1.4.6: unknown protocol ` tcp' specified
Try `iptables -h' or 'iptables --help' for more information.

I tried removing the space

#include <unistd.h>
int main() {
    char *args[6];
    args[0] = "/usr/sbin/iptables";
    args[1] = "-I INPUT";
    args[2] = "-ptcp";
    args[3] = "--dport 80";
    args[4] = "-j ACCEPT";
    args[5] = NULL;
    execve(args[0], args, NULL);
}

and I got

$./code
iptables v1.4.6: unknown option `--dport 80'
Try `iptables -h' or 'iptables --help' for more information.

Can anyone help me out here? What am I doing wrong?

Here is the help output

$ iptables --help
iptables v1.4.6

Usage: iptables -[AD] chain rule-specification [options]
       iptables -I chain [rulenum] rule-specification [options]
       iptables -R chain rulenum rule-specification [options]
       iptables -D chain rulenum [options]
       iptables -[LS] [chain [rulenum]] [options]
       iptables -[FZ] [chain] [options]
       iptables -[NX] chain
       iptables -E old-chain-name new-chain-name
       iptables -P chain target [options]
       iptables -h (print this help information)

Commands:
Either long or short options are allowed.
  --append  -A chain        Append to chain
  --delete  -D chain        Delete matching rule from chain
  --delete  -D chain rulenum
                Delete rule rulenum (1 = first) from chain
  --insert  -I chain [rulenum]
                Insert in chain as rulenum (default 1=first)
  --replace -R chain rulenum
                Replace rule rulenum (1 = first) in chain
  --list    -L [chain [rulenum]]
                List the rules in a chain or all chains
  --list-rules -S [chain [rulenum]]
                Print the rules in a chain or all chains
  --flush   -F [chain]      Delete all rules in  chain or all chains
  --zero    -Z [chain [rulenum]]
                Zero counters in chain or all chains
  --new     -N chain        Create a new user-defined chain
  --delete-chain
            -X [chain]      Delete a user-defined chain
  --policy  -P chain target
                Change policy on chain to target
  --rename-chain
            -E old-chain new-chain
                Change chain name, (moving any references)
Options:
[!] --proto -p proto    protocol: by number or name, eg. `tcp'
[!] --source    -s address[/mask][...]
                source specification
[!] --destination -d address[/mask][...]
                destination specification
[!] --in-interface -i input name[+]
                network interface name ([+] for wildcard)
 --jump -j target
                target for rule (may load target extension)
  --goto      -g chain
                              jump to chain with no return
  --match   -m match
                extended match (may load extension)
  --numeric -n      numeric output of addresses and ports
[!] --out-interface -o output name[+]
                network interface name ([+] for wildcard)
  --table   -t table    table to manipulate (default: `filter')
  --verbose -v      verbose mode
  --line-numbers        print line numbers when listing
  --exact   -x      expand numbers (display exact values)
[!] --fragment  -f      match second or further fragments only
  --modprobe=<command>      try to insert modules using this command
  --set-counters PKTS BYTES set the counter during insert/append
[!] --version   -V      print package version.
2

You need to split your arguments in the same way the shell would:

#include <unistd.h>
int main() {
    char *args[10];
    int i = 0;
    args[i++] = "/usr/sbin/iptables";
    args[i++] = "-I";
    args[i++] = "INPUT";
    args[i++] = "-p";
    args[i++] = "tcp";
    args[i++] = "--dport";
    args[i++] = "80";
    args[i++] = "-j";
    args[i++] = "ACCEPT";
    args[i++] = NULL;
    execve(args[0], args, NULL);
}

The shell splits on all spaces.

  • Great! That's what I was missing. Thank you. – graphia Mar 19 '18 at 14:59
  • That variable index increment for a statically declared array, LOL. – Marco Bonelli Mar 20 '18 at 2:58
0

The flags and their arguments should be separate:

int main() {
    char *args[] = {
      "/usr/sbin/iptables",
      "-I", "INPUT",
      "-ptcp",
      "--dport", "80",
      "-j", "ACCEPT",
      NULL
    };
...
}

For commands where the option and option argument can be given as a single argument, there shouldn't be a space between them (e.g., tail and -n6), or have a separator like = depending on the command, e.g. grep and --color=always.

  • @stephen-kitt just beat you to it, thanks anyway! – graphia Mar 19 '18 at 15:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.