|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
c5a612 |
* it under the terms of the GNU General Public License version 2 as
|
|
Packit |
c5a612 |
* published by the Free Software Foundation.
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <stdlib.h>
|
|
Packit |
c5a612 |
#include <stddef.h>
|
|
Packit |
c5a612 |
#include <unistd.h>
|
|
Packit |
c5a612 |
#include <stdio.h>
|
|
Packit |
c5a612 |
#include <errno.h>
|
|
Packit |
c5a612 |
#include <string.h>
|
|
Packit |
c5a612 |
#include <getopt.h>
|
|
Packit |
c5a612 |
#include <fcntl.h>
|
|
Packit |
c5a612 |
#include <sys/types.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <nftables/libnftables.h>
|
|
Packit |
c5a612 |
#include <utils.h>
|
|
Packit |
c5a612 |
#include <cli.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct nft_ctx *nft;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
enum opt_vals {
|
|
Packit |
c5a612 |
OPT_HELP = 'h',
|
|
Packit |
c5a612 |
OPT_VERSION = 'v',
|
|
Packit |
c5a612 |
OPT_CHECK = 'c',
|
|
Packit |
c5a612 |
OPT_FILE = 'f',
|
|
Packit |
c5a612 |
OPT_INTERACTIVE = 'i',
|
|
Packit |
c5a612 |
OPT_INCLUDEPATH = 'I',
|
|
Packit |
c5a612 |
OPT_JSON = 'j',
|
|
Packit |
c5a612 |
OPT_NUMERIC = 'n',
|
|
Packit |
c5a612 |
OPT_STATELESS = 's',
|
|
Packit |
c5a612 |
OPT_IP2NAME = 'N',
|
|
Packit |
c5a612 |
OPT_SERVICE = 'S',
|
|
Packit |
c5a612 |
OPT_DEBUG = 'd',
|
|
Packit |
c5a612 |
OPT_HANDLE_OUTPUT = 'a',
|
|
Packit |
c5a612 |
OPT_ECHO = 'e',
|
|
Packit |
c5a612 |
OPT_GUID = 'u',
|
|
Packit |
c5a612 |
OPT_NUMERIC_PRIO = 'y',
|
|
Packit |
c5a612 |
OPT_NUMERIC_PROTO = 'p',
|
|
Packit |
c5a612 |
OPT_NUMERIC_TIME = 'T',
|
|
Packit |
c5a612 |
OPT_TERSE = 't',
|
|
Packit |
c5a612 |
OPT_INVALID = '?',
|
|
Packit |
c5a612 |
};
|
|
Packit Service |
1894c6 |
#define OPTSTRING "+hvd:cf:iI:jvnsNaeSupypTt"
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct option options[] = {
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "help",
|
|
Packit |
c5a612 |
.val = OPT_HELP,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "version",
|
|
Packit |
c5a612 |
.val = OPT_VERSION,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "check",
|
|
Packit |
c5a612 |
.val = OPT_CHECK,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "file",
|
|
Packit |
c5a612 |
.val = OPT_FILE,
|
|
Packit |
c5a612 |
.has_arg = 1,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "interactive",
|
|
Packit |
c5a612 |
.val = OPT_INTERACTIVE,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "numeric",
|
|
Packit |
c5a612 |
.val = OPT_NUMERIC,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "stateless",
|
|
Packit |
c5a612 |
.val = OPT_STATELESS,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "reversedns",
|
|
Packit |
c5a612 |
.val = OPT_IP2NAME,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "service",
|
|
Packit |
c5a612 |
.val = OPT_SERVICE,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "includepath",
|
|
Packit |
c5a612 |
.val = OPT_INCLUDEPATH,
|
|
Packit |
c5a612 |
.has_arg = 1,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "debug",
|
|
Packit |
c5a612 |
.val = OPT_DEBUG,
|
|
Packit |
c5a612 |
.has_arg = 1,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "handle",
|
|
Packit |
c5a612 |
.val = OPT_HANDLE_OUTPUT,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "echo",
|
|
Packit |
c5a612 |
.val = OPT_ECHO,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "json",
|
|
Packit |
c5a612 |
.val = OPT_JSON,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "guid",
|
|
Packit |
c5a612 |
.val = OPT_GUID,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "numeric-priority",
|
|
Packit |
c5a612 |
.val = OPT_NUMERIC_PRIO,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "numeric-protocol",
|
|
Packit |
c5a612 |
.val = OPT_NUMERIC_PROTO,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "numeric-time",
|
|
Packit |
c5a612 |
.val = OPT_NUMERIC_TIME,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "terse",
|
|
Packit |
c5a612 |
.val = OPT_TERSE,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = NULL
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void show_help(const char *name)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
printf(
|
|
Packit |
c5a612 |
"Usage: %s [ options ] [ cmds... ]\n"
|
|
Packit |
c5a612 |
"\n"
|
|
Packit |
c5a612 |
"Options:\n"
|
|
Packit |
c5a612 |
" -h, --help Show this help\n"
|
|
Packit |
c5a612 |
" -v, --version Show version information\n"
|
|
Packit |
c5a612 |
"\n"
|
|
Packit |
c5a612 |
" -c, --check Check commands validity without actually applying the changes.\n"
|
|
Packit |
c5a612 |
" -f, --file <filename> Read input from <filename>\n"
|
|
Packit |
c5a612 |
" -i, --interactive Read input from interactive CLI\n"
|
|
Packit |
c5a612 |
"\n"
|
|
Packit |
c5a612 |
" -j, --json Format output in JSON\n"
|
|
Packit |
c5a612 |
" -n, --numeric Print fully numerical output.\n"
|
|
Packit |
c5a612 |
" -s, --stateless Omit stateful information of ruleset.\n"
|
|
Packit |
c5a612 |
" -t, --terse Omit contents of sets.\n"
|
|
Packit |
c5a612 |
" -u, --guid Print UID/GID as defined in /etc/passwd and /etc/group.\n"
|
|
Packit |
c5a612 |
" -N Translate IP addresses to names.\n"
|
|
Packit |
c5a612 |
" -S, --service Translate ports to service names as described in /etc/services.\n"
|
|
Packit |
c5a612 |
" -p, --numeric-protocol Print layer 4 protocols numerically.\n"
|
|
Packit |
c5a612 |
" -y, --numeric-priority Print chain priority numerically.\n"
|
|
Packit |
c5a612 |
" -T, --numeric-time Print time values numerically.\n"
|
|
Packit |
c5a612 |
" -a, --handle Output rule handle.\n"
|
|
Packit |
c5a612 |
" -e, --echo Echo what has been added, inserted or replaced.\n"
|
|
Packit |
c5a612 |
" -I, --includepath <directory> Add <directory> to the paths searched for include files. Default is: %s\n"
|
|
Packit |
c5a612 |
" --debug <level [,level...]> Specify debugging level (scanner, parser, eval, netlink, mnl, proto-ctx, segtree, all)\n"
|
|
Packit |
c5a612 |
"\n",
|
|
Packit |
c5a612 |
name, DEFAULT_INCLUDE_PATH);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct {
|
|
Packit |
c5a612 |
const char *name;
|
|
Packit |
c5a612 |
enum nft_debug_level level;
|
|
Packit |
c5a612 |
} debug_param[] = {
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "scanner",
|
|
Packit |
c5a612 |
.level = NFT_DEBUG_SCANNER,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "parser",
|
|
Packit |
c5a612 |
.level = NFT_DEBUG_PARSER,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "eval",
|
|
Packit |
c5a612 |
.level = NFT_DEBUG_EVALUATION,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "netlink",
|
|
Packit |
c5a612 |
.level = NFT_DEBUG_NETLINK,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "mnl",
|
|
Packit |
c5a612 |
.level = NFT_DEBUG_MNL,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "proto-ctx",
|
|
Packit |
c5a612 |
.level = NFT_DEBUG_PROTO_CTX,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "segtree",
|
|
Packit |
c5a612 |
.level = NFT_DEBUG_SEGTREE,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
.name = "all",
|
|
Packit |
c5a612 |
.level = ~0,
|
|
Packit |
c5a612 |
},
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit Service |
095fa0 |
static void nft_options_error(int argc, char * const argv[], int pos)
|
|
Packit Service |
095fa0 |
{
|
|
Packit Service |
095fa0 |
int i;
|
|
Packit Service |
095fa0 |
|
|
Packit Service |
095fa0 |
fprintf(stderr, "Error: syntax error, options must be specified before commands\n");
|
|
Packit Service |
095fa0 |
for (i = 0; i < argc; i++)
|
|
Packit Service |
095fa0 |
fprintf(stderr, "%s ", argv[i]);
|
|
Packit Service |
095fa0 |
printf("\n%4c%*s\n", '^', pos - 2, "~~");
|
|
Packit Service |
095fa0 |
}
|
|
Packit Service |
095fa0 |
|
|
Packit Service |
095fa0 |
static bool nft_options_check(int argc, char * const argv[])
|
|
Packit Service |
095fa0 |
{
|
|
Packit Service |
095fa0 |
bool skip = false, nonoption = false;
|
|
Packit Service |
095fa0 |
int pos = 0, i;
|
|
Packit Service |
095fa0 |
|
|
Packit Service |
095fa0 |
for (i = 1; i < argc; i++) {
|
|
Packit Service |
095fa0 |
pos += strlen(argv[i - 1]) + 1;
|
|
Packit Service |
095fa0 |
if (argv[i][0] == '{') {
|
|
Packit Service |
095fa0 |
break;
|
|
Packit Service |
095fa0 |
} else if (skip) {
|
|
Packit Service |
095fa0 |
skip = false;
|
|
Packit Service |
095fa0 |
continue;
|
|
Packit Service |
095fa0 |
} else if (argv[i][0] == '-') {
|
|
Packit Service |
095fa0 |
if (nonoption) {
|
|
Packit Service |
095fa0 |
nft_options_error(argc, argv, pos);
|
|
Packit Service |
095fa0 |
return false;
|
|
Packit Service |
1894c6 |
} else if (argv[i][1] == 'd' ||
|
|
Packit Service |
1894c6 |
argv[i][1] == 'I' ||
|
|
Packit Service |
095fa0 |
argv[i][1] == 'f' ||
|
|
Packit Service |
1894c6 |
!strcmp(argv[i], "--debug") ||
|
|
Packit Service |
095fa0 |
!strcmp(argv[i], "--includepath") ||
|
|
Packit Service |
095fa0 |
!strcmp(argv[i], "--file")) {
|
|
Packit Service |
095fa0 |
skip = true;
|
|
Packit Service |
095fa0 |
continue;
|
|
Packit Service |
095fa0 |
}
|
|
Packit Service |
095fa0 |
} else if (argv[i][0] != '-') {
|
|
Packit Service |
095fa0 |
nonoption = true;
|
|
Packit Service |
095fa0 |
}
|
|
Packit Service |
095fa0 |
}
|
|
Packit Service |
095fa0 |
|
|
Packit Service |
095fa0 |
return true;
|
|
Packit Service |
095fa0 |
}
|
|
Packit Service |
095fa0 |
|
|
Packit |
c5a612 |
int main(int argc, char * const *argv)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char *buf = NULL, *filename = NULL;
|
|
Packit |
c5a612 |
unsigned int output_flags = 0;
|
|
Packit |
c5a612 |
bool interactive = false;
|
|
Packit |
c5a612 |
unsigned int debug_mask;
|
|
Packit |
c5a612 |
unsigned int len;
|
|
Packit |
c5a612 |
int i, val, rc;
|
|
Packit |
c5a612 |
|
|
Packit Service |
095fa0 |
if (!nft_options_check(argc, argv))
|
|
Packit Service |
095fa0 |
exit(EXIT_FAILURE);
|
|
Packit Service |
095fa0 |
|
|
Packit |
c5a612 |
nft = nft_ctx_new(NFT_CTX_DEFAULT);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
while (1) {
|
|
Packit |
c5a612 |
val = getopt_long(argc, argv, OPTSTRING, options, NULL);
|
|
Packit |
c5a612 |
if (val == -1)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (val) {
|
|
Packit |
c5a612 |
case OPT_HELP:
|
|
Packit |
c5a612 |
show_help(argv[0]);
|
|
Packit |
c5a612 |
exit(EXIT_SUCCESS);
|
|
Packit |
c5a612 |
case OPT_VERSION:
|
|
Packit |
c5a612 |
printf("%s v%s (%s)\n",
|
|
Packit |
c5a612 |
PACKAGE_NAME, PACKAGE_VERSION, RELEASE_NAME);
|
|
Packit |
c5a612 |
exit(EXIT_SUCCESS);
|
|
Packit |
c5a612 |
case OPT_CHECK:
|
|
Packit |
c5a612 |
nft_ctx_set_dry_run(nft, true);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_FILE:
|
|
Packit |
c5a612 |
filename = optarg;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_INTERACTIVE:
|
|
Packit |
c5a612 |
interactive = true;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_INCLUDEPATH:
|
|
Packit |
c5a612 |
if (nft_ctx_add_include_path(nft, optarg)) {
|
|
Packit |
c5a612 |
fprintf(stderr,
|
|
Packit |
c5a612 |
"Failed to add include path '%s'\n",
|
|
Packit |
c5a612 |
optarg);
|
|
Packit |
c5a612 |
exit(EXIT_FAILURE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_NUMERIC:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_NUMERIC_ALL;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_STATELESS:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_STATELESS;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_IP2NAME:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_REVERSEDNS;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_SERVICE:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_SERVICE;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_DEBUG:
|
|
Packit |
c5a612 |
debug_mask = nft_ctx_output_get_debug(nft);
|
|
Packit |
c5a612 |
for (;;) {
|
|
Packit |
c5a612 |
unsigned int i;
|
|
Packit |
c5a612 |
char *end;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
end = strchr(optarg, ',');
|
|
Packit |
c5a612 |
if (end)
|
|
Packit |
c5a612 |
*end = '\0';
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (i = 0; i < array_size(debug_param); i++) {
|
|
Packit |
c5a612 |
if (strcmp(debug_param[i].name, optarg))
|
|
Packit |
c5a612 |
continue;
|
|
Packit |
c5a612 |
debug_mask |= debug_param[i].level;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (i == array_size(debug_param)) {
|
|
Packit |
c5a612 |
fprintf(stderr, "invalid debug parameter `%s'\n",
|
|
Packit |
c5a612 |
optarg);
|
|
Packit |
c5a612 |
exit(EXIT_FAILURE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (end == NULL)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
optarg = end + 1;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_ctx_output_set_debug(nft, debug_mask);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_HANDLE_OUTPUT:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_HANDLE;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_ECHO:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_ECHO;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_JSON:
|
|
Packit |
c5a612 |
#ifdef HAVE_LIBJANSSON
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_JSON;
|
|
Packit |
c5a612 |
#else
|
|
Packit |
c5a612 |
fprintf(stderr, "JSON support not compiled-in\n");
|
|
Packit |
c5a612 |
exit(EXIT_FAILURE);
|
|
Packit |
c5a612 |
#endif
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_GUID:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_GUID;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_NUMERIC_PRIO:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_NUMERIC_PRIO;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_NUMERIC_PROTO:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_NUMERIC_PROTO;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_NUMERIC_TIME:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_NUMERIC_TIME;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_TERSE:
|
|
Packit |
c5a612 |
output_flags |= NFT_CTX_OUTPUT_TERSE;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case OPT_INVALID:
|
|
Packit |
c5a612 |
exit(EXIT_FAILURE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_ctx_output_set_flags(nft, output_flags);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (optind != argc) {
|
|
Packit |
c5a612 |
for (len = 0, i = optind; i < argc; i++)
|
|
Packit |
c5a612 |
len += strlen(argv[i]) + strlen(" ");
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
buf = calloc(1, len);
|
|
Packit |
c5a612 |
if (buf == NULL) {
|
|
Packit |
c5a612 |
fprintf(stderr, "%s:%u: Memory allocation failure\n",
|
|
Packit |
c5a612 |
__FILE__, __LINE__);
|
|
Packit |
c5a612 |
exit(EXIT_FAILURE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
for (i = optind; i < argc; i++) {
|
|
Packit |
c5a612 |
strcat(buf, argv[i]);
|
|
Packit |
c5a612 |
if (i + 1 < argc)
|
|
Packit |
c5a612 |
strcat(buf, " ");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
rc = !!nft_run_cmd_from_buffer(nft, buf);
|
|
Packit |
c5a612 |
} else if (filename != NULL) {
|
|
Packit |
c5a612 |
rc = !!nft_run_cmd_from_filename(nft, filename);
|
|
Packit |
c5a612 |
} else if (interactive) {
|
|
Packit |
c5a612 |
if (cli_init(nft) < 0) {
|
|
Packit |
c5a612 |
fprintf(stderr, "%s: interactive CLI not supported in this build\n",
|
|
Packit |
c5a612 |
argv[0]);
|
|
Packit |
c5a612 |
exit(EXIT_FAILURE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
return EXIT_SUCCESS;
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
fprintf(stderr, "%s: no command specified\n", argv[0]);
|
|
Packit |
c5a612 |
exit(EXIT_FAILURE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
free(buf);
|
|
Packit |
c5a612 |
nft_ctx_free(nft);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return rc;
|
|
Packit |
c5a612 |
}
|