Beispiel #1
0
/*
 * retrieve target addresses
 * format
 * 192.168.0.1:80-192.168.0.2:8080,192.168.0.1:8080-192.168.0.3:80
 */
static int
retrieve_target_addresses(char *raw_transfer,
        ip_port_pair_mappings_t *transfer)
{
    int   i;
    char *p, *seq;

    if (raw_transfer == NULL) {
        tc_log_info(LOG_ERR, 0, "it must have -x argument");
        fprintf(stderr, "no -x argument\n");
        return -1;
    }

    for (transfer->num = 1, p = raw_transfer; *p; p++) {
        if (*p == ',') {
            transfer->num++;
        }
    }

    transfer->mappings = malloc(transfer->num *
                                sizeof(ip_port_pair_mapping_t *));
    if (transfer->mappings == NULL) {
        return -1;
    }
    memset(transfer->mappings, 0 , 
            transfer->num * sizeof(ip_port_pair_mapping_t *));

    for (i = 0; i < transfer->num; i++) {
        transfer->mappings[i] = malloc(sizeof(ip_port_pair_mapping_t));
        if (transfer->mappings[i] == NULL) {
            return -1;
        }
        memset(transfer->mappings[i], 0, sizeof(ip_port_pair_mapping_t));
    }

    p = raw_transfer;
    i = 0;
    for ( ;; ) {
        if ((seq = strchr(p, ',')) == NULL) {
            if (parse_target(transfer->mappings[i++], p) == -1) {
                return -1;
            }
            break;
        } else {
            *seq = '\0';
            if (parse_target(transfer->mappings[i++], p) == -1) {
                return -1;
            }

            *seq = ',';
            p = seq + 1;
        }
    }

    return 0;
}
Beispiel #2
0
/*
 * retrieve target addresses
 * format
 * 192.168.0.1:80-192.168.0.2:8080,192.168.0.1:8080-192.168.0.3:80
 */
static int
retr_target_addrs(char *raw_tf, transfer_maps_t *tf)
{
    int   i;
    char *p, *seq;

    if (raw_tf == NULL) {
        tc_log_info(LOG_ERR, 0, "it must have -x argument");
        fprintf(stderr, "no -x argument\n");
        return -1;
    }

    for (tf->num = 1, p = raw_tf; *p; p++) {
        if (*p == ',') {
            tf->num++;
        }
    }

    tf->map = tc_palloc(clt_settings.pool, tf->num * sizeof(transfer_map_t *));
    if (tf->map == NULL) {
        return -1;
    }
    tc_memzero(tf->map, tf->num * sizeof(transfer_map_t *));

    for (i = 0; i < tf->num; i++) {
        tf->map[i] = tc_palloc(clt_settings.pool, sizeof(transfer_map_t));
        if (tf->map[i] == NULL) {
            return -1;
        }
        tc_memzero(tf->map[i], sizeof(transfer_map_t));
    }

    p = raw_tf;
    i = 0;
    for ( ;; ) {
        if ((seq = strchr(p, ',')) == NULL) {
            if (parse_target(tf->map[i++], p) == -1) {
                return -1;
            }
            break;
        } else {
            *seq = '\0';
            if (parse_target(tf->map[i++], p) == -1) {
                return -1;
            }

            *seq = ',';
            p = seq + 1;
        }
    }

    return 0;
}
Beispiel #3
0
static int do_command(char *str)
{
	int action, id;
	char action_str[10+1] = {0}, id_str[64+1] = {0};

	if (0 == strncasecmp(str, "HELP", strlen(str))) {
		print_help(stdout);
		return 0;
	}

	if (2 != sscanf(str, " %10s %64s", action_str, id_str))
		return -1;

	if (0 == strncasecmp(action_str, "TARGET", strlen(action_str)))
		return parse_target(id_str);

	action = parse_action(action_str);
	id = parse_id(id_str);

	if (action == BAD_ACTION || id == BAD_ID)
		return -1;

	if (id == AMBIGUOUS_ID) {
		fprintf(stdout, "id %s is too ambiguous\n", id_str);
		return 0;
	}

	fprintf(stdout, "sending: %s %s\n",
		action_string[action], idtab[id].name);

	idtab[id].func(action, id, str);

	return 0;
}
Beispiel #4
0
static int SET_parse(int c, char **argv, int invert, unsigned int *flags,
                     const void *entry, struct xt_entry_target **target)
{
	struct ipt_set_info_target *myinfo =
	    (struct ipt_set_info_target *) (*target)->data;

	switch (c) {
	case '1':		/* --add-set <set> <flags> */
		parse_target(argv, invert, flags,
			     &myinfo->add_set, "add-set");
		break;
	case '2':		/* --del-set <set>[:<flags>] <flags> */
		parse_target(argv, invert, flags,
			     &myinfo->del_set, "del-set");
		break;

	default:
		return 0;
	}
	return 1;
}
static void command_jump(struct iptables_command_state *cs)
{
	size_t size;

	set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags, cs->invert);
	cs->jumpto = parse_target(optarg);
	/* TRY_LOAD (may be chain name) */
	cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);

	if (cs->target == NULL)
		return;

	size = XT_ALIGN(sizeof(struct xt_entry_target))
		+ cs->target->size;

	cs->target->t = xtables_calloc(1, size);
	cs->target->t->u.target_size = size;
	if (cs->target->real_name == NULL) {
		strcpy(cs->target->t->u.user.name, cs->jumpto);
	} else {
		/* Alias support for userspace side */
		strcpy(cs->target->t->u.user.name, cs->target->real_name);
		if (!(cs->target->ext_flags & XTABLES_EXT_ALIAS))
			fprintf(stderr, "Notice: The %s target is converted into %s target "
				"in rule listing and saving.\n",
				cs->jumpto, cs->target->real_name);
	}
	cs->target->t->u.user.revision = cs->target->revision;
	xs_init_target(cs->target);

	if (cs->target->x6_options != NULL)
		opts = xtables_options_xfrm(xtables_globals.orig_opts, opts,
					    cs->target->x6_options,
					    &cs->target->option_offset);
	else
		opts = xtables_merge_options(xtables_globals.orig_opts, opts,
					     cs->target->extra_opts,
					     &cs->target->option_offset);
	if (opts == NULL)
		xtables_error(OTHER_PROBLEM, "can't alloc memory!");
}
Beispiel #6
0
static struct cconf* parse(void *buf, size_t size) {

	struct cconf *c = calloc(1, sizeof(struct cconf));
	int i;

	/* move! */
	c->map.buf = buf;
	c->map.size = size;

	buf = read_entry_nr(buf + sizeof(struct cconf_header), &c->nr);

	c->target = calloc(sizeof(struct target), c->nr);

	for(i=0; i < c->nr; i++) {
		struct target *target = c->target + i;

		buf += parse_target(buf, target);
		buf += parse_filter(buf, target);
	}
	return c;
}
static void
parse_options(int argc, char *argv[])
{
    static struct option long_options[] = {
        {"local", required_argument, NULL, 'l'},
        {"remote", required_argument, NULL, 'r'},
        {"batches", required_argument, NULL, 'b'},
        {"sockets", required_argument, NULL, 's'},
        {"max-rate", required_argument, NULL, 'c'},
        {"timeout", required_argument, NULL, 'T'},
        {"help", no_argument, NULL, 'h'},
        {"version", no_argument, NULL, 'V'},
        {NULL, 0, NULL, 0},
    };
    char *short_options = long_options_to_short_options(long_options);

    local_addr.s_addr = htonl(INADDR_ANY);
    local_min_port = local_max_port = 0;

    remote_addr.s_addr = htonl(0);
    remote_min_port = remote_max_port = 0;

    for (;;) {
        int c;

        c = getopt_long(argc, argv, short_options, long_options, NULL);
        if (c == -1) {
            break;
        }

        switch (c) {
        case 'l':
            parse_target(optarg,
                         &local_addr, &local_min_port, &local_max_port);
            break;

        case 'r':
            parse_target(optarg,
                         &remote_addr, &remote_min_port, &remote_max_port);
            if (remote_addr.s_addr == htonl(INADDR_ANY)) {
                ovs_fatal(0, "remote IP address is required");
            }
            break;

        case 'b':
            n_batches = atoi(optarg);
            if (n_batches < 0) {
                ovs_fatal(0, "--batches or -b argument must be at least 1");
            }
            break;

        case 's':
            n_sockets = atoi(optarg);
            if (n_sockets < 1 || n_sockets > MAX_SOCKETS) {
                ovs_fatal(0, "--sockets or -s argument must be between 1 "
                          "and %d (inclusive)", MAX_SOCKETS);
            }
            break;

        case 'c':
            max_rate = atof(optarg);
            if (max_rate <= 0.0) {
                ovs_fatal(0, "--max-rate or -c argument must be positive");
            }
            break;

        case 'T':
            timeout = atoi(optarg);
            if (!timeout) {
                ovs_fatal(0, "-T or --timeout argument must be positive");
            }
            break;

        case 'h':
            usage();

        case 'V':
            ovs_print_version(0, 0);
            exit(EXIT_SUCCESS);

        case '?':
            exit(EXIT_FAILURE);

        default:
            abort();
        }
    }
    free(short_options);
}
Beispiel #8
0
/****************************************************************************
  main program
****************************************************************************/
int main(int argc,char *argv[])
{
	int opt, i;
	bool correct = true;
	int max_runtime=0;
	int argc_new;
	struct torture_context *torture;
	struct torture_results *results;
	const struct torture_ui_ops *ui_ops;
	char **argv_new;
	poptContext pc;
	static const char *target = "other";
	NTSTATUS status;
	int shell = false;
	static const char *ui_ops_name = "subunit";
	const char *basedir = NULL;
	const char *extra_module = NULL;
	static int list_tests = 0;
	int num_extra_users = 0;
	enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
	      OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,
	      OPT_EXTRA_USER,};

	struct poptOption long_options[] = {
		POPT_AUTOHELP
		{"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
		{"smb-ports",	'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,	"SMB ports", 	NULL},
		{"basedir",	  0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
		{"seed",	  0, POPT_ARG_INT,  &torture_seed, 	0,	"Seed to use for randomizer", 	NULL},
		{"num-progs",	  0, POPT_ARG_INT,  NULL, 	OPT_NUMPROGS,	"num progs",	NULL},
		{"num-ops",	  0, POPT_ARG_INT,  &torture_numops, 	0, 	"num ops",	NULL},
		{"entries",	  0, POPT_ARG_INT,  &torture_entries, 	0,	"entries",	NULL},
		{"loadfile",	  0, POPT_ARG_STRING,	NULL, 	OPT_LOADFILE,	"NBench load file to use", 	NULL},
		{"list", 	  0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
		{"unclist",	  0, POPT_ARG_STRING,	NULL, 	OPT_UNCLIST,	"unclist", 	NULL},
		{"timelimit",	't', POPT_ARG_INT,	NULL, 	OPT_TIMELIMIT,	"Set time limit (in seconds)", 	NULL},
		{"failures",	'f', POPT_ARG_INT,  &torture_failures, 	0,	"failures", 	NULL},
		{"parse-dns",	'D', POPT_ARG_STRING,	NULL, 	OPT_DNS,	"parse-dns", 	NULL},
		{"dangerous",	'X', POPT_ARG_NONE,	NULL,   OPT_DANGEROUS,
		 "run dangerous tests (eg. wiping out password database)", NULL},
		{"load-module",  0,  POPT_ARG_STRING, &extra_module,     0, "load tests from DSO file",    "SOFILE"},
		{"shell", 		0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
		{"target", 		'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
		{"async",       'a', POPT_ARG_NONE,     NULL,   OPT_ASYNC,
		 "run async tests", NULL},
		{"num-async",    0, POPT_ARG_INT,  &torture_numasync,  0,
		 "number of simultaneous async requests", NULL},
		{"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, 
		 "set maximum time for smbtorture to live", "seconds"},
		{"extra-user",   0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
		 "extra user credentials", NULL},
		POPT_COMMON_SAMBA
		POPT_COMMON_CONNECTION
		POPT_COMMON_CREDENTIALS
		POPT_COMMON_VERSION
		{ NULL }
	};

	setlinebuf(stdout);

	/* we are never interested in SIGPIPE */
	BlockSignals(true, SIGPIPE);

	pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
			    POPT_CONTEXT_KEEP_FIRST);

	poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");

	while((opt = poptGetNextOpt(pc)) != -1) {
		switch (opt) {
		case OPT_LOADFILE:
			lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
			break;
		case OPT_UNCLIST:
			lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
			break;
		case OPT_TIMELIMIT:
			lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
			break;
		case OPT_NUMPROGS:
			lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
			break;
		case OPT_DNS:
			parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
			break;
		case OPT_DANGEROUS:
			lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
			break;
		case OPT_ASYNC:
			lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
			break;
		case OPT_SMB_PORTS:
			lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
			break;
		case OPT_EXTRA_USER:
			{
				char *option = talloc_asprintf(NULL, "torture:extra_user%u",
							       ++num_extra_users);
				const char *value = poptGetOptArg(pc);
				lp_set_cmdline(cmdline_lp_ctx, option, value);
				talloc_free(option);
			}
			break;
		default:
			printf("bad command line option\n");
			exit(1);
		}
	}

	if (strcmp(target, "samba3") == 0) {
		lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
		lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
	} else if (strcmp(target, "samba4") == 0) {
		lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
	} else if (strcmp(target, "winxp") == 0) {
		lp_set_cmdline(cmdline_lp_ctx, "torture:winxp", "true");
	} else if (strcmp(target, "w2k3") == 0) {
		lp_set_cmdline(cmdline_lp_ctx, "torture:w2k3", "true");
	} else if (strcmp(target, "w2k8") == 0) {
		lp_set_cmdline(cmdline_lp_ctx, "torture:w2k8", "true");
		lp_set_cmdline(cmdline_lp_ctx,
		    "torture:invalid_lock_range_support", "false");
	} else if (strcmp(target, "win7") == 0) {
		lp_set_cmdline(cmdline_lp_ctx, "torture:win7", "true");
		lp_set_cmdline(cmdline_lp_ctx, "torture:cn_max_buffer_size",
		    "0x00010000");
		lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");

		/* RAW-SEARCH for fails for inexplicable reasons against win7 */
		lp_set_cmdline(cmdline_lp_ctx, "torture:search_ea_support", "false");

		lp_set_cmdline(cmdline_lp_ctx, "torture:hide_on_access_denied",
		    "true");
	} else if (strcmp(target, "onefs") == 0) {
		lp_set_cmdline(cmdline_lp_ctx, "torture:onefs", "true");
		lp_set_cmdline(cmdline_lp_ctx, "torture:openx_deny_dos_support",
		    "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:sacl_support", "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:ea_support", "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:smblock_pdu_support",
		    "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:2_step_break_to_none",
		    "true");
		lp_set_cmdline(cmdline_lp_ctx, "torture:deny_dos_support", "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:deny_fcb_support", "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:read_support", "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:writeclose_support", "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:resume_key_support", "false");
		lp_set_cmdline(cmdline_lp_ctx, "torture:rewind_support", "false");
	}

	if (max_runtime) {
		/* this will only work if nobody else uses alarm(),
		   which means it won't work for some tests, but we
		   can't use the event context method we use for smbd
		   as so many tests create their own event
		   context. This will at least catch most cases. */
		signal(SIGALRM, max_runtime_handler);
		alarm(max_runtime);
	}

	if (extra_module != NULL) {
	    init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));

	    if (fn == NULL) 
		d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
	    else {
		status = fn();
		if (NT_STATUS_IS_ERR(status)) {
		    d_printf("Error initializing module %s: %s\n", 
			     poptGetOptArg(pc), nt_errstr(status));
		}
	    }
	} else { 
		torture_init();
	}

	if (list_tests) {
		print_test_list();
		return 0;
	}

	if (torture_seed == 0) {
		torture_seed = time(NULL);
	} 
	printf("Using seed %d\n", torture_seed);
	srandom(torture_seed);

	argv_new = discard_const_p(char *, poptGetArgs(pc));

	argc_new = argc;
	for (i=0; i<argc; i++) {
		if (argv_new[i] == NULL) {
			argc_new = i;
			break;
		}
	}

	if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
		usage(pc);
		exit(1);
	}

	if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
		usage(pc);
		exit(1);
	}

	if (!strcmp(ui_ops_name, "simple")) {
		ui_ops = &std_ui_ops;
	} else if (!strcmp(ui_ops_name, "subunit")) {
		ui_ops = &torture_subunit_ui_ops;
	} else {
		printf("Unknown output format '%s'\n", ui_ops_name);
		exit(1);
	}

	results = torture_results_init(talloc_autofree_context(), ui_ops);

	torture = torture_context_init(s4_event_context_init(NULL), results);
	if (basedir != NULL) {
		if (basedir[0] != '/') {
			fprintf(stderr, "Please specify an absolute path to --basedir\n");
			return 1;
		}
		torture->outputdir = basedir;
	} else {
		char *pwd = talloc_size(torture, PATH_MAX);
		if (!getcwd(pwd, PATH_MAX)) {
			fprintf(stderr, "Unable to determine current working directory\n");
			return 1;
		}
		torture->outputdir = pwd;
	}

	torture->lp_ctx = cmdline_lp_ctx;

	gensec_init(cmdline_lp_ctx);

	if (argc_new == 0) {
		printf("You must specify a test to run, or 'ALL'\n");
	} else if (shell) {
		run_shell(torture);
	} else {
		for (i=2;i<argc_new;i++) {
			if (!run_test(torture, argv_new[i])) {
				correct = false;
			}
		}
	}

	if (torture->results->returncode && correct) {
		return(0);
	} else {
		return(1);
	}
}
Beispiel #9
0
/* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table)
{
	char *buffer;
	int c, i;
	int zerochain = -1; /* Needed for the -Z option (we can have -Z <this> -L <that>) */
	int chcounter = 0; /* Needed for -C */
	int rule_nr = 0;
	int rule_nr_end = 0;
	int ret = 0;
	unsigned int flags = 0;
	struct xtables_target *t, *w;
	struct xtables_match *m;
	struct ebtables_command_state cs;
	char command = 'h';
	const char *chain = NULL;
	const char *policy = NULL;
	int exec_style = EXEC_STYLE_PRG;
	int selected_chain = -1;
	struct xtables_rule_match *xtrm_i;
	struct ebt_match *match;

	memset(&cs, 0, sizeof(cs));
	cs.argv = argv;

	if (nft_init(h, xtables_bridge) < 0)
		xtables_error(OTHER_PROBLEM,
			      "Could not initialize nftables layer.");

	h->ops = nft_family_ops_lookup(h->family);
	if (h->ops == NULL)
		xtables_error(PARAMETER_PROBLEM, "Unknown family");

	/* manually registering ebt matches, given the original ebtables parser
	 * don't use '-m matchname' and the match can't loaded dinamically when
	 * the user calls it.
	 */
	ebt_load_match_extensions();

	/* clear mflags in case do_commandeb gets called a second time
	 * (we clear the global list of all matches for security)*/
	for (m = xtables_matches; m; m = m->next)
		m->mflags = 0;

	for (t = xtables_targets; t; t = t->next) {
		t->tflags = 0;
		t->used = 0;
	}

	/* prevent getopt to spoil our error reporting */
	opterr = false;

	/* Getopt saves the day */
	while ((c = getopt_long(argc, argv,
	   "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) {
		cs.c = c;
		cs.invert = ebt_invert;
		switch (c) {

		case 'A': /* Add a rule */
		case 'D': /* Delete a rule */
		case 'C': /* Change counters */
		case 'P': /* Define policy */
		case 'I': /* Insert a rule */
		case 'N': /* Make a user defined chain */
		case 'E': /* Rename chain */
		case 'X': /* Delete chain */
			/* We allow -N chainname -P policy */
			/* XXX: Not in ebtables-compat */
			if (command == 'N' && c == 'P') {
				command = c;
				optind--; /* No table specified */
				goto handle_P;
			}
			if (OPT_COMMANDS)
				xtables_error(PARAMETER_PROBLEM,
					      "Multiple commands are not allowed");

			command = c;
			chain = optarg;
			selected_chain = get_current_chain(chain);
			flags |= OPT_COMMAND;
			/*if (!(replace->flags & OPT_KERNELDATA))
				ebt_get_kernel_table(replace, 0);*/
			/*if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!")))
				ebt_print_error2("No chain name specified");*/
			if (c == 'N') {
				ret = nft_chain_user_add(h, chain, *table);
				break;
			} else if (c == 'X') {
				ret = nft_chain_user_del(h, chain, *table);
				break;
			}

			if (c == 'E') {
				if (optind >= argc)
					xtables_error(PARAMETER_PROBLEM, "No new chain name specified");
				else if (optind < argc - 1)
					xtables_error(PARAMETER_PROBLEM, "No extra options allowed with -E");
				else if (strlen(argv[optind]) >= NFT_CHAIN_MAXNAMELEN)
					xtables_error(PARAMETER_PROBLEM, "Chain name length can't exceed %d"" characters", NFT_CHAIN_MAXNAMELEN - 1);
				else if (strchr(argv[optind], ' ') != NULL)
					xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names");

				ret = nft_chain_user_rename(h, chain, *table,
							    argv[optind]);
				if (ret != 0 && errno == ENOENT)
					xtables_error(PARAMETER_PROBLEM, "Chain '%s' doesn't exists", chain);

				optind++;
				break;
			} else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
				if (optind != argc - 1)
					xtables_error(PARAMETER_PROBLEM,
							 "No extra options allowed with -D start_nr[:end_nr]");
				if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end))
					xtables_error(PARAMETER_PROBLEM,
							 "Problem with the specified rule number(s) '%s'", argv[optind]);
				optind++;
			} else if (c == 'C') {
				if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, exec_style, &cs)) == -1)
					return -1;
			} else if (c == 'I') {
				if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')))
					rule_nr = 1;
				else {
					rule_nr = parse_rule_number(argv[optind]);
					optind++;
				}
			} else if (c == 'P') {
handle_P:
				if (optind >= argc)
					xtables_error(PARAMETER_PROBLEM,
						      "No policy specified");
				for (i = 0; i < NUM_STANDARD_TARGETS; i++)
					if (!strcmp(argv[optind], nft_ebt_standard_target(i))) {
						policy = argv[optind];
						if (-i-1 == EBT_CONTINUE)
							xtables_error(PARAMETER_PROBLEM,
								      "Wrong policy '%s'",
								      argv[optind]);
						break;
					}
				if (i == NUM_STANDARD_TARGETS)
					xtables_error(PARAMETER_PROBLEM,
						      "Unknown policy '%s'", argv[optind]);
				optind++;
			}
			break;
		case 'L': /* List */
		case 'F': /* Flush */
		case 'Z': /* Zero counters */
			if (c == 'Z') {
				if ((flags & OPT_ZERO) || (flags & OPT_COMMAND && command != 'L'))
print_zero:
					xtables_error(PARAMETER_PROBLEM,
						      "Command -Z only allowed together with command -L");
				flags |= OPT_ZERO;
			} else {
				if (flags & OPT_COMMAND)
					xtables_error(PARAMETER_PROBLEM,
						      "Multiple commands are not allowed");
				command = c;
				flags |= OPT_COMMAND;
				if (flags & OPT_ZERO && c != 'L')
					goto print_zero;
			}

#ifdef SILENT_DAEMON
			if (c== 'L' && exec_style == EXEC_STYLE_DAEMON)
				xtables_error(PARAMETER_PROBLEM,
					      "-L not supported in daemon mode");
#endif

			/*if (!(replace->flags & OPT_KERNELDATA))
				ebt_get_kernel_table(replace, 0);
			i = -1;
			if (optind < argc && argv[optind][0] != '-') {
				if ((i = ebt_get_chainnr(replace, argv[optind])) == -1)
					ebt_print_error2("Chain '%s' doesn't exist", argv[optind]);
				optind++;
			}
			if (i != -1) {
				if (c == 'Z')
					zerochain = i;
				else
					replace->selected_chain = i;
			}*/
			break;
		case 'V': /* Version */
			if (OPT_COMMANDS)
				xtables_error(PARAMETER_PROBLEM,
					      "Multiple commands are not allowed");
			command = 'V';
			if (exec_style == EXEC_STYLE_DAEMON)
				xtables_error(PARAMETER_PROBLEM,
					      "%s %s\n", prog_name, prog_vers);
			printf("%s %s\n", prog_name, prog_vers);
			exit(0);
		case 'h': /* Help */
#ifdef SILENT_DAEMON
			if (exec_style == EXEC_STYLE_DAEMON)
				xtables_error(PARAMETER_PROBLEM,
					      "-h not supported in daemon mode");
#endif
			if (OPT_COMMANDS)
				xtables_error(PARAMETER_PROBLEM,
					      "Multiple commands are not allowed");
			command = 'h';

			/* All other arguments should be extension names */
			while (optind < argc) {
				/*struct ebt_u_match *m;
				struct ebt_u_watcher *w;*/

				if (!strcasecmp("list_extensions", argv[optind])) {
					ebt_list_extensions(xtables_targets, cs.matches);
					exit(0);
				}
				/*if ((m = ebt_find_match(argv[optind])))
					ebt_add_match(new_entry, m);
				else if ((w = ebt_find_watcher(argv[optind])))
					ebt_add_watcher(new_entry, w);
				else {*/
					if (!(t = xtables_find_target(argv[optind], XTF_TRY_LOAD)))
						xtables_error(PARAMETER_PROBLEM,"Extension '%s' not found", argv[optind]);
					if (flags & OPT_JUMP)
						xtables_error(PARAMETER_PROBLEM,"Sorry, you can only see help for one target extension at a time");
					flags |= OPT_JUMP;
					cs.target = t;
				//}
				optind++;
			}
			break;
		case 't': /* Table */
			if (OPT_COMMANDS)
				xtables_error(PARAMETER_PROBLEM,
					      "Please put the -t option first");
			ebt_check_option2(&flags, OPT_TABLE);
			if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
				xtables_error(PARAMETER_PROBLEM,
					      "Table name length cannot exceed %d characters",
					      EBT_TABLE_MAXNAMELEN - 1);
			*table = optarg;
			break;
		case 'i': /* Input interface */
		case 2  : /* Logical input interface */
		case 'o': /* Output interface */
		case 3  : /* Logical output interface */
		case 'j': /* Target */
		case 'p': /* Net family protocol */
		case 's': /* Source mac */
		case 'd': /* Destination mac */
		case 'c': /* Set counters */
			if (!OPT_COMMANDS)
				xtables_error(PARAMETER_PROBLEM,
					      "No command specified");
			if (command != 'A' && command != 'D' && command != 'I' && command != 'C')
				xtables_error(PARAMETER_PROBLEM,
					      "Command and option do not match");
			if (c == 'i') {
				ebt_check_option2(&flags, OPT_IN);
				if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
					xtables_error(PARAMETER_PROBLEM,
						      "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains");
				if (ebt_check_inverse2(optarg, argc, argv))
					cs.fw.invflags |= EBT_IIN;

				if (strlen(optarg) >= IFNAMSIZ)
big_iface_length:
					xtables_error(PARAMETER_PROBLEM,
						      "Interface name length cannot exceed %d characters",
						      IFNAMSIZ - 1);
				xtables_parse_interface(optarg, cs.fw.in, cs.fw.in_mask);
				break;
			} else if (c == 2) {
				ebt_check_option2(&flags, OPT_LOGICALIN);
				if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
					xtables_error(PARAMETER_PROBLEM,
						      "Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains");
				if (ebt_check_inverse2(optarg, argc, argv))
					cs.fw.invflags |= EBT_ILOGICALIN;

				if (strlen(optarg) >= IFNAMSIZ)
					goto big_iface_length;
				strcpy(cs.fw.logical_in, optarg);
				if (parse_iface(cs.fw.logical_in, "--logical-in"))
					return -1;
				break;
			} else if (c == 'o') {
				ebt_check_option2(&flags, OPT_OUT);
				if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
					xtables_error(PARAMETER_PROBLEM,
						      "Use -o only in OUTPUT, FORWARD and POSTROUTING chains");
				if (ebt_check_inverse2(optarg, argc, argv))
					cs.fw.invflags |= EBT_IOUT;

				if (strlen(optarg) >= IFNAMSIZ)
					goto big_iface_length;

				xtables_parse_interface(optarg, cs.fw.out, cs.fw.out_mask);
				break;
			} else if (c == 3) {
				ebt_check_option2(&flags, OPT_LOGICALOUT);
				if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
					xtables_error(PARAMETER_PROBLEM,
						      "Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains");
				if (ebt_check_inverse2(optarg, argc, argv))
					cs.fw.invflags |= EBT_ILOGICALOUT;

				if (strlen(optarg) >= IFNAMSIZ)
					goto big_iface_length;
				strcpy(cs.fw.logical_out, optarg);
				if (parse_iface(cs.fw.logical_out, "--logical-out"))
					return -1;
				break;
			} else if (c == 'j') {
				ebt_check_option2(&flags, OPT_JUMP);
				cs.jumpto = parse_target(optarg);
				cs.target = command_jump(&cs, cs.jumpto);
				break;
			} else if (c == 's') {
				ebt_check_option2(&flags, OPT_SOURCE);
				if (ebt_check_inverse2(optarg, argc, argv))
					cs.fw.invflags |= EBT_ISOURCE;

				if (ebt_get_mac_and_mask(optarg, cs.fw.sourcemac, cs.fw.sourcemsk))
					xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
				cs.fw.bitmask |= EBT_SOURCEMAC;
				break;
			} else if (c == 'd') {
				ebt_check_option2(&flags, OPT_DEST);
				if (ebt_check_inverse2(optarg, argc, argv))
					cs.fw.invflags |= EBT_IDEST;

				if (ebt_get_mac_and_mask(optarg, cs.fw.destmac, cs.fw.destmsk))
					xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
				cs.fw.bitmask |= EBT_DESTMAC;
				break;
			} else if (c == 'c') {
				ebt_check_option2(&flags, OPT_COUNT);
				if (ebt_check_inverse2(optarg, argc, argv))
					xtables_error(PARAMETER_PROBLEM,
						      "Unexpected '!' after -c");
				if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-')
					xtables_error(PARAMETER_PROBLEM,
						      "Option -c needs 2 arguments");

				cs.counters.pcnt = strtoull(optarg, &buffer, 10);
				if (*buffer != '\0')
					xtables_error(PARAMETER_PROBLEM,
						      "Packet counter '%s' invalid",
						      optarg);
				cs.counters.bcnt = strtoull(argv[optind], &buffer, 10);
				if (*buffer != '\0')
					xtables_error(PARAMETER_PROBLEM,
						      "Packet counter '%s' invalid",
						      argv[optind]);
				optind++;
				break;
			}
			ebt_check_option2(&flags, OPT_PROTOCOL);
			if (ebt_check_inverse2(optarg, argc, argv))
				cs.fw.invflags |= EBT_IPROTO;

			cs.fw.bitmask &= ~((unsigned int)EBT_NOPROTO);
			i = strtol(optarg, &buffer, 16);
			if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
				xtables_error(PARAMETER_PROBLEM,
					      "Problem with the specified protocol");
			if (*buffer != '\0') {
				struct ethertypeent *ent;

				if (!strcasecmp(optarg, "LENGTH")) {
					cs.fw.bitmask |= EBT_802_3;
					break;
				}
				ent = getethertypebyname(optarg);
				if (!ent)
					xtables_error(PARAMETER_PROBLEM,
						      "Problem with the specified Ethernet protocol '%s', perhaps "_PATH_ETHERTYPES " is missing", optarg);
				cs.fw.ethproto = ent->e_ethertype;
			} else
				cs.fw.ethproto = i;

			if (cs.fw.ethproto < 0x0600)
				xtables_error(PARAMETER_PROBLEM,
					      "Sorry, protocols have values above or equal to 0x0600");
			break;
		case 4  : /* Lc */
#ifdef SILENT_DAEMON
			if (exec_style == EXEC_STYLE_DAEMON)
				xtables_error(PARAMETER_PROBLEM,
					      "--Lc is not supported in daemon mode");
#endif
			ebt_check_option2(&flags, LIST_C);
			if (command != 'L')
				xtables_error(PARAMETER_PROBLEM,
					      "Use --Lc with -L");
			flags |= LIST_C;
			break;
		case 5  : /* Ln */
#ifdef SILENT_DAEMON
			if (exec_style == EXEC_STYLE_DAEMON)
				xtables_error(PARAMETER_PROBLEM,
					      "--Ln is not supported in daemon mode");
#endif
			ebt_check_option2(&flags, LIST_N);
			if (command != 'L')
				xtables_error(PARAMETER_PROBLEM,
					      "Use --Ln with -L");
			if (flags & LIST_X)
				xtables_error(PARAMETER_PROBLEM,
					      "--Lx is not compatible with --Ln");
			flags |= LIST_N;
			break;
		case 6  : /* Lx */
#ifdef SILENT_DAEMON
			if (exec_style == EXEC_STYLE_DAEMON)
				xtables_error(PARAMETER_PROBLEM,
					      "--Lx is not supported in daemon mode");
#endif
			ebt_check_option2(&flags, LIST_X);
			if (command != 'L')
				xtables_error(PARAMETER_PROBLEM,
					      "Use --Lx with -L");
			if (flags & LIST_N)
				xtables_error(PARAMETER_PROBLEM,
					      "--Lx is not compatible with --Ln");
			flags |= LIST_X;
			break;
		case 12 : /* Lmac2 */
#ifdef SILENT_DAEMON
			if (exec_style == EXEC_STYLE_DAEMON)
				xtables_error(PARAMETER_PROBLEM,
					      "--Lmac2 is not supported in daemon mode");
#endif
			ebt_check_option2(&flags, LIST_MAC2);
			if (command != 'L')
				xtables_error(PARAMETER_PROBLEM,
					       "Use --Lmac2 with -L");
			flags |= LIST_MAC2;
			break;
		case 8 : /* atomic-commit */
/*			if (exec_style == EXEC_STYLE_DAEMON)
				ebt_print_error2("--atomic-commit is not supported in daemon mode");
			replace->command = c;
			if (OPT_COMMANDS)
				ebt_print_error2("Multiple commands are not allowed");
			replace->flags |= OPT_COMMAND;
			if (!replace->filename)
				ebt_print_error2("No atomic file specified");*/
			/* Get the information from the file */
			/*ebt_get_table(replace, 0);*/
			/* We don't want the kernel giving us its counters,
			 * they would overwrite the counters extracted from
			 * the file */
			/*replace->num_counters = 0;*/
			/* Make sure the table will be written to the kernel */
			/*free(replace->filename);
			replace->filename = NULL;
			break;*/
		/*case 7 :*/ /* atomic-init */
		/*case 10:*/ /* atomic-save */
		/*case 11:*/ /* init-table */
		/*	if (exec_style == EXEC_STYLE_DAEMON) {
				if (c == 7) {
					ebt_print_error2("--atomic-init is not supported in daemon mode");
				} else if (c == 10)
					ebt_print_error2("--atomic-save is not supported in daemon mode");
				ebt_print_error2("--init-table is not supported in daemon mode");
			}
			replace->command = c;
			if (OPT_COMMANDS)
				ebt_print_error2("Multiple commands are not allowed");
			if (c != 11 && !replace->filename)
				ebt_print_error2("No atomic file specified");
			replace->flags |= OPT_COMMAND;
			{
				char *tmp = replace->filename;*/

				/* Get the kernel table */
				/*replace->filename = NULL;
				ebt_get_kernel_table(replace, c == 10 ? 0 : 1);
				replace->filename = tmp;
			}
			break;
		case 9 :*/ /* atomic */
			/*if (exec_style == EXEC_STYLE_DAEMON)
				ebt_print_error2("--atomic is not supported in daemon mode");
			if (OPT_COMMANDS)
				ebt_print_error2("--atomic has to come before the command");*/
			/* A possible memory leak here, but this is not
			 * executed in daemon mode */
			/*replace->filename = (char *)malloc(strlen(optarg) + 1);
			strcpy(replace->filename, optarg);
			break;
		case 13 : *//* concurrent */
			/*signal(SIGINT, sighandler);
			signal(SIGTERM, sighandler);
			use_lockfd = 1;
			break;*/
		case 1 :
			if (!strcmp(optarg, "!"))
				ebt_check_inverse2(optarg, argc, argv);
			else
				xtables_error(PARAMETER_PROBLEM,
					      "Bad argument : '%s'", optarg);
			/* ebt_ebt_check_inverse2() did optind++ */
			optind--;
			continue;
		default:
			/* Is it a target option? */
			if (cs.target != NULL && cs.target->parse != NULL) {
				int opt_offset = cs.target->option_offset;
				if (cs.target->parse(c - opt_offset,
						     argv, ebt_invert,
						     &cs.target->tflags,
						     NULL, &cs.target->t))
					goto check_extension;
			}

			/* Is it a match_option? */
			for (m = xtables_matches; m; m = m->next) {
				if (m->parse(c - m->option_offset, argv, ebt_invert, &m->mflags, NULL, &m->m)) {
					ebt_add_match(m, &cs);
					goto check_extension;
				}
			}

			/* Is it a watcher option? */
			for (w = xtables_targets; w; w = w->next) {
				if (w->parse(c - w->option_offset, argv,
					     ebt_invert, &w->tflags,
					     NULL, &w->t)) {
					ebt_add_watcher(w, &cs);
					goto check_extension;
				}
			}
			/*
			if (w == NULL && c == '?')
				ebt_print_error2("Unknown argument: '%s'", argv[optind - 1], (char)optopt, (char)c);
			else if (w == NULL) {
				if (!strcmp(t->name, "standard"))
					ebt_print_error2("Unknown argument: don't forget the -t option");
				else
					ebt_print_error2("Target-specific option does not correspond with specified target");
			}
			if (ebt_errormsg[0] != '\0')
				return -1;
			if (w->used == 0) {
				ebt_add_watcher(new_entry, w);
				w->used = 1;
			}*/
check_extension:
			if (command != 'A' && command != 'I' &&
			    command != 'D' && command != 'C')
				xtables_error(PARAMETER_PROBLEM,
					      "Extensions only for -A, -I, -D and -C");
		}
		ebt_invert = 0;
	}

	/* Just in case we didn't catch an error */
	/*if (ebt_errormsg[0] != '\0')
		return -1;

	if (!(table = ebt_find_table(replace->name)))
		ebt_print_error2("Bad table name");*/

	if (command == 'h' && !(flags & OPT_ZERO)) {
		print_help(cs.target, cs.matches, *table);
		if (exec_style == EXEC_STYLE_PRG)
			exit(0);
	}

	/* Do the final checks */
	if (command == 'A' || command == 'I' ||
	    command == 'D' || command == 'C') {
		for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next)
			xtables_option_mfcall(xtrm_i->match);

		for (match = cs.match_list; match; match = match->next) {
			if (match->ismatch)
				continue;

			xtables_option_tfcall(match->u.watcher);
		}

		if (cs.target != NULL)
			xtables_option_tfcall(cs.target);
	}
	/* So, the extensions can work with the host endian.
	 * The kernel does not have to do this of course */
	cs.fw.ethproto = htons(cs.fw.ethproto);

	if (command == 'P') {
		if (selected_chain < 0) {
			xtables_error(PARAMETER_PROBLEM,
				      "Policy %s not allowed for user defined chains",
				      policy);
		}
		if (strcmp(policy, "RETURN") == 0) {
			xtables_error(PARAMETER_PROBLEM,
				      "Policy RETURN only allowed for user defined chains");
		}
		ret = nft_chain_set(h, *table, chain, policy, NULL);
		if (ret < 0)
			xtables_error(PARAMETER_PROBLEM, "Wrong policy");
	} else if (command == 'L') {
		ret = list_rules(h, chain, *table, rule_nr,
				 flags&OPT_VERBOSE,
				 flags&OPT_NUMERIC,
				 /*flags&OPT_EXPANDED*/0,
				 flags&LIST_N,
				 flags&LIST_C);
		if (!(flags & OPT_ZERO) && exec_style == EXEC_STYLE_PRG)
			exit(0);
	}
	if (flags & OPT_ZERO) {
		selected_chain = zerochain;
		ret = nft_chain_zero_counters(h, chain, *table);
	} else if (command == 'F') {
		ret = nft_rule_flush(h, chain, *table);
	} else if (command == 'A') {
		ret = append_entry(h, chain, *table, &cs, 0,
				   flags&OPT_VERBOSE, true);
	} else if (command == 'I') {
		ret = append_entry(h, chain, *table, &cs, rule_nr - 1,
				   flags&OPT_VERBOSE, false);
	} else if (command == 'D') {
		ret = delete_entry(h, chain, *table, &cs, rule_nr - 1,
				   rule_nr_end, flags&OPT_VERBOSE);
	} /*else if (replace->command == 'C') {
		ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter);
		if (ebt_errormsg[0] != '\0')
			return -1;
	}*/
	/* Commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
	 * --init-table fall through */

	/*if (ebt_errormsg[0] != '\0')
		return -1;
	if (table->check)
		table->check(replace);

	if (exec_style == EXEC_STYLE_PRG) {*//* Implies ebt_errormsg[0] == '\0' */
		/*ebt_deliver_table(replace);

		if (replace->nentries)
			ebt_deliver_counters(replace);*/

	ebt_cs_clean(&cs);
	return ret;
}
Beispiel #10
0
void parse(std::vector<unique_ptr<Token>>::iterator it,
           std::vector<unique_ptr<Token>>::iterator tokens_end,
           ProguardConfiguration* pg_config,
           unsigned int* parse_errors,
           const std::string& filename) {
  *parse_errors = 0;
  bool ok;
  while (it != tokens_end) {
    // Break out if we are at the end of the token stream.
    if ((*it)->type == token::eof_token) {
      break;
    }
    uint32_t line = (*it)->line;
    if (!(*it)->is_command()) {
      cerr << "Expecting command but found " << (*it)->show() << " at line "
           << (*it)->line << endl;
      ++it;
      skip_to_next_command(&it);
      continue;
    }

    // Input/Output Options
    if (parse_filepath_command(&it,
                               token::include,
                               pg_config->basedirectory,
                               &pg_config->includes))
      continue;
    if (parse_single_filepath_command(
            &it, token::basedirectory, &pg_config->basedirectory))
      continue;
    if (parse_jars(
            &it, token::injars, pg_config->basedirectory, &pg_config->injars))
      continue;
    if (parse_jars(
            &it, token::outjars, pg_config->basedirectory, &pg_config->outjars))
      continue;
    if (parse_jars(&it,
                   token::libraryjars,
                   pg_config->basedirectory,
                   &pg_config->libraryjars))
      continue;
    // -skipnonpubliclibraryclasses not supported
    if ((*it)->type == token::dontskipnonpubliclibraryclasses) {
      // Silenty ignore the dontskipnonpubliclibraryclasses option.
      ++it;
      continue;
    }
    // -dontskipnonpubliclibraryclassmembers not supported
    if (parse_filepath_command(&it,
                               token::keepdirectories,
                               pg_config->basedirectory,
                               &pg_config->keepdirectories))
      continue;
    if (parse_target(&it, &pg_config->target_version)) continue;
    // -forceprocessing not supported

    // Keep Options
    if (parse_keep(&it,
                   token::keep,
                   &pg_config->keep_rules,
                   true, // mark_classes
                   false, // mark_conditionally
                   false, // allowshrinking
                   filename,
                   line,
                   &ok)) {
      if (!ok) {
        (*parse_errors)++;
      }
      continue;
    }
    if (parse_keep(&it,
                   token::keepclassmembers,
                   &pg_config->keep_rules,
                   false, // mark_classes
                   false, // mark_conditionally
                   false, // allowshrinking
                   filename,
                   line,
                   &ok)) {
      if (!ok) {
        (*parse_errors)++;
      }
      continue;
    }
    if (parse_keep(&it,
                   token::keepclasseswithmembers,
                   &pg_config->keep_rules,
                   false, // mark_classes
                   true, // mark_conditionally
                   false, // allowshrinking
                   filename,
                   line,
                   &ok)) {
      if (!ok) {
        (*parse_errors)++;
      }
      continue;
    }
    if (parse_keep(&it,
                   token::keepnames,
                   &pg_config->keep_rules,
                   true, // mark_classes
                   false, // mark_conditionally
                   true, // allowshrinking
                   filename,
                   line,
                   &ok)) {
      if (!ok) {
        (*parse_errors)++;
      }
      continue;
    }
    if (parse_keep(&it,
                   token::keepclassmembernames,
                   &pg_config->keep_rules,
                   false, // mark_classes
                   false, // mark_conditionally
                   true, // allowshrinking
                   filename,
                   line,
                   &ok)) {
      if (!ok) {
        (*parse_errors)++;
      }
      continue;
    }
    if (parse_keep(&it,
                   token::keepclasseswithmembernames,
                   &pg_config->keep_rules,
                   false, // mark_classes
                   true, // mark_conditionally
                   true, // allowshrinking
                   filename,
                   line,
                   &ok)) {
      if (!ok) {
        (*parse_errors)++;
      }
      continue;
    }
    if (parse_optional_filepath_command(
            &it, token::printseeds, &pg_config->printseeds))
      continue;

    // Shrinking Options
    if (parse_bool_command(&it, token::dontshrink, false, &pg_config->shrink))
      continue;
    if (parse_optional_filepath_command(
            &it, token::printusage, &pg_config->printusage))
      continue;

    // Optimization Options
    if (parse_boolean_command(
            &it, token::dontoptimize, &pg_config->optimize, false))
      continue;
    if (parse_filter_list_command(
            &it, token::optimizations, &pg_config->optimization_filters))
      continue;
    if (parse_optimizationpasses_command(&it)) {
      continue;
    }
    if (parse_keep(&it,
                   token::assumenosideeffects,
                   &pg_config->assumenosideeffects_rules,
                   false, // mark_classes
                   false, // mark_conditionally
                   false, // allowshrinking
                   filename,
                   line,
                   &ok))
      continue;
    if (parse_keep(&it,
                   token::whyareyoukeeping,
                   &pg_config->whyareyoukeeping_rules,
                   false, // mark_classes
                   false, // mark_conditionally
                   false, // allowshrinking
                   filename,
                   line,
                   &ok))
      continue;

    // Obfuscation Options
    if ((*it)->type == token::dontobfuscate) {
      pg_config->dontobfuscate = true;
      ++it;
      continue;
    }
    // Redex ignores -dontskipnonpubliclibraryclasses
    if ((*it)->type == token::dontskipnonpubliclibraryclasses) {
      ++it;
      continue;
    }
    if (parse_optional_filepath_command(
            &it, token::printmapping, &pg_config->printmapping))
      continue;
    if (parse_optional_filepath_command(
            &it, token::printconfiguration, &pg_config->printconfiguration))
      continue;

    if (parse_allowaccessmodification(&it, &pg_config->allowaccessmodification))
      continue;
    if (parse_dontusemixedcaseclassnames(
            &it, &pg_config->dontusemixedcaseclassnames))
      continue;
    if (parse_filter_list_command(
            &it, token::keeppackagenames, &pg_config->keeppackagenames))
      continue;
    if (parse_dontpreverify(&it, &pg_config->dontpreverify)) continue;
    if (parse_verbose(&it, &pg_config->verbose)) continue;
    if (parse_repackageclasses(&it)) continue;

    if (parse_filter_list_command(&it, token::dontwarn, &pg_config->dontwarn))
      continue;
    if (parse_filter_list_command(
            &it, token::keepattributes, &pg_config->keepattributes))
      continue;

    // Skip unknown token.
    if ((*it)->is_command()) {
      cerr << "Unimplemented command (skipping): " << (*it)->show()
           << " at line " << (*it)->line << endl;
    } else {
      cerr << "Unexpected token " << (*it)->show() << " at line " << (*it)->line
           << endl;
      (*parse_errors)++;
    }
    ++it;
    skip_to_next_command(&it);
  }
}
int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
		bool restore)
{
	struct iptables_command_state cs;
	int verbose = 0;
	const char *chain = NULL;
	const char *policy = NULL, *newname = NULL;
	unsigned int rulenum = 0, command = 0;
	int ret = 1;
	struct xtables_match *m;
	struct xtables_rule_match *matchp;
	struct xtables_target *t;
	struct xtables_args args = {
		.family	= h->family,
	};

	memset(&cs, 0, sizeof(cs));
	cs.jumpto = "";
	cs.argv = argv;

	/* re-set optind to 0 in case do_command4 gets called
	 * a second time */
	optind = 0;

	/* clear mflags in case do_command4 gets called a second time
	 * (we clear the global list of all matches for security)*/
	for (m = xtables_matches; m; m = m->next)
		m->mflags = 0;

	for (t = xtables_targets; t; t = t->next) {
		t->tflags = 0;
		t->used = 0;
	}

	/* Suppress error messages: we may add new options if we
	   demand-load a protocol. */
	opterr = 0;

	h->ops = nft_family_ops_lookup(h->family);
	if (h->ops == NULL)
		xtables_error(PARAMETER_PROBLEM, "Unknown family");

	opts = xt_params->orig_opts;
	while ((cs.c = getopt_long(argc, argv,
	   "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:46",
					   opts, NULL)) != -1) {
		switch (cs.c) {
			/*
			 * Command selection
			 */
		case 'A':
			add_command(&command, CMD_APPEND, CMD_NONE,
				    cs.invert);
			chain = optarg;
			break;

		case 'C':
			add_command(&command, CMD_CHECK, CMD_NONE,
				    cs.invert);
			chain = optarg;
			break;

		case 'D':
			add_command(&command, CMD_DELETE, CMD_NONE,
				    cs.invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!') {
				rulenum = parse_rulenumber(argv[optind++]);
				command = CMD_DELETE_NUM;
			}
			break;

		case 'R':
			add_command(&command, CMD_REPLACE, CMD_NONE,
				    cs.invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				rulenum = parse_rulenumber(argv[optind++]);
			else
				xtables_error(PARAMETER_PROBLEM,
					   "-%c requires a rule number",
					   cmd2char(CMD_REPLACE));
			break;

		case 'I':
			add_command(&command, CMD_INSERT, CMD_NONE,
				    cs.invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				rulenum = parse_rulenumber(argv[optind++]);
			else rulenum = 1;
			break;

		case 'L':
			add_command(&command, CMD_LIST,
				    CMD_ZERO | CMD_ZERO_NUM, cs.invert);
			if (optarg) chain = optarg;
			else if (optind < argc && argv[optind][0] != '-'
				 && argv[optind][0] != '!')
				chain = argv[optind++];
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				rulenum = parse_rulenumber(argv[optind++]);
			break;

		case 'S':
			add_command(&command, CMD_LIST_RULES,
				    CMD_ZERO|CMD_ZERO_NUM, cs.invert);
			if (optarg) chain = optarg;
			else if (optind < argc && argv[optind][0] != '-'
				 && argv[optind][0] != '!')
				chain = argv[optind++];
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				rulenum = parse_rulenumber(argv[optind++]);
			break;

		case 'F':
			add_command(&command, CMD_FLUSH, CMD_NONE,
				    cs.invert);
			if (optarg) chain = optarg;
			else if (optind < argc && argv[optind][0] != '-'
				 && argv[optind][0] != '!')
				chain = argv[optind++];
			break;

		case 'Z':
			add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
				    cs.invert);
			if (optarg) chain = optarg;
			else if (optind < argc && argv[optind][0] != '-'
				&& argv[optind][0] != '!')
				chain = argv[optind++];
			if (optind < argc && argv[optind][0] != '-'
				&& argv[optind][0] != '!') {
				rulenum = parse_rulenumber(argv[optind++]);
				command = CMD_ZERO_NUM;
			}
			break;

		case 'N':
			if (optarg && (*optarg == '-' || *optarg == '!'))
				xtables_error(PARAMETER_PROBLEM,
					   "chain name not allowed to start "
					   "with `%c'\n", *optarg);
			if (xtables_find_target(optarg, XTF_TRY_LOAD))
				xtables_error(PARAMETER_PROBLEM,
					   "chain name may not clash "
					   "with target name\n");
			add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
				    cs.invert);
			chain = optarg;
			break;

		case 'X':
			add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
				    cs.invert);
			if (optarg) chain = optarg;
			else if (optind < argc && argv[optind][0] != '-'
				 && argv[optind][0] != '!')
				chain = argv[optind++];
			break;

		case 'E':
			add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
				    cs.invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				newname = argv[optind++];
			else
				xtables_error(PARAMETER_PROBLEM,
					   "-%c requires old-chain-name and "
					   "new-chain-name",
					    cmd2char(CMD_RENAME_CHAIN));
			break;

		case 'P':
			add_command(&command, CMD_SET_POLICY, CMD_NONE,
				    cs.invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				policy = argv[optind++];
			else
				xtables_error(PARAMETER_PROBLEM,
					   "-%c requires a chain and a policy",
					   cmd2char(CMD_SET_POLICY));
			break;

		case 'h':
			if (!optarg)
				optarg = argv[optind];

			/* iptables -p icmp -h */
			if (!cs.matches && cs.protocol)
				xtables_find_match(cs.protocol,
					XTF_TRY_LOAD, &cs.matches);

			exit_printhelp(cs.matches);

			/*
			 * Option selection
			 */
		case 'p':
			set_option(&cs.options, OPT_PROTOCOL, &args.invflags,
				   cs.invert);

			/* Canonicalize into lower case */
			for (cs.protocol = optarg; *cs.protocol; cs.protocol++)
				*cs.protocol = tolower(*cs.protocol);

			cs.protocol = optarg;
			args.proto = xtables_parse_protocol(cs.protocol);

			if (args.proto == 0 && (args.invflags & XT_INV_PROTO))
				xtables_error(PARAMETER_PROBLEM,
					   "rule would never match protocol");

			/* This needs to happen here to parse extensions */
			h->ops->proto_parse(&cs, &args);
			break;

		case 's':
			set_option(&cs.options, OPT_SOURCE, &args.invflags,
				   cs.invert);
			args.shostnetworkmask = optarg;
			break;

		case 'd':
			set_option(&cs.options, OPT_DESTINATION,
				   &args.invflags, cs.invert);
			args.dhostnetworkmask = optarg;
			break;

#ifdef IPT_F_GOTO
		case 'g':
			set_option(&cs.options, OPT_JUMP, &args.invflags,
				   cs.invert);
			args.goto_set = true;
			cs.jumpto = parse_target(optarg);
			break;
#endif

		case 'j':
			command_jump(&cs);
			break;


		case 'i':
			if (*optarg == '\0')
				xtables_error(PARAMETER_PROBLEM,
					"Empty interface is likely to be "
					"undesired");
			set_option(&cs.options, OPT_VIANAMEIN, &args.invflags,
				   cs.invert);
			xtables_parse_interface(optarg,
						args.iniface,
						args.iniface_mask);
			break;

		case 'o':
			if (*optarg == '\0')
				xtables_error(PARAMETER_PROBLEM,
					"Empty interface is likely to be "
					"undesired");
			set_option(&cs.options, OPT_VIANAMEOUT, &args.invflags,
				   cs.invert);
			xtables_parse_interface(optarg,
						args.outiface,
						args.outiface_mask);
			break;

		case 'f':
			if (args.family == AF_INET6) {
				xtables_error(PARAMETER_PROBLEM,
					"`-f' is not supported in IPv6, "
					"use -m frag instead");
			}
			set_option(&cs.options, OPT_FRAGMENT, &args.invflags,
				   cs.invert);
			args.flags |= IPT_F_FRAG;
			break;

		case 'v':
			if (!verbose)
				set_option(&cs.options, OPT_VERBOSE,
					   &args.invflags, cs.invert);
			verbose++;
			break;

		case 'm':
			command_match(&cs);
			break;

		case 'n':
			set_option(&cs.options, OPT_NUMERIC, &args.invflags,
				   cs.invert);
			break;

		case 't':
			if (cs.invert)
				xtables_error(PARAMETER_PROBLEM,
					   "unexpected ! flag before --table");
			*table = optarg;
			break;

		case 'x':
			set_option(&cs.options, OPT_EXPANDED, &args.invflags,
				   cs.invert);
			break;

		case 'V':
			if (cs.invert)
				printf("Not %s ;-)\n", prog_vers);
			else
				printf("%s v%s\n",
				       prog_name, prog_vers);
			exit(0);

		case 'w':
			if (restore) {
				xtables_error(PARAMETER_PROBLEM,
					      "You cannot use `-w' from "
					      "iptables-restore");
			}
			break;

		case '0':
			set_option(&cs.options, OPT_LINENUMBERS,
				   &args.invflags, cs.invert);
			break;

		case 'M':
			xtables_modprobe_program = optarg;
			break;

		case 'c':

			set_option(&cs.options, OPT_COUNTERS, &args.invflags,
				   cs.invert);
			args.pcnt = optarg;
			args.bcnt = strchr(args.pcnt + 1, ',');
			if (args.bcnt)
			    args.bcnt++;
			if (!args.bcnt && optind < argc &&
			    argv[optind][0] != '-' &&
			    argv[optind][0] != '!')
				args.bcnt = argv[optind++];
			if (!args.bcnt)
				xtables_error(PARAMETER_PROBLEM,
					"-%c requires packet and byte counter",
					opt2char(OPT_COUNTERS));

			if (sscanf(args.pcnt, "%llu", &args.pcnt_cnt) != 1)
				xtables_error(PARAMETER_PROBLEM,
					"-%c packet counter not numeric",
					opt2char(OPT_COUNTERS));

			if (sscanf(args.bcnt, "%llu", &args.bcnt_cnt) != 1)
				xtables_error(PARAMETER_PROBLEM,
					"-%c byte counter not numeric",
					opt2char(OPT_COUNTERS));
			break;

		case '4':
			if (args.family != AF_INET)
				exit_tryhelp(2);

			h->ops = nft_family_ops_lookup(args.family);
			break;

		case '6':
			args.family = AF_INET6;
			xtables_set_nfproto(AF_INET6);

			h->ops = nft_family_ops_lookup(args.family);
			if (h->ops == NULL)
				xtables_error(PARAMETER_PROBLEM,
					      "Unknown family");
			break;

		case 1: /* non option */
			if (optarg[0] == '!' && optarg[1] == '\0') {
				if (cs.invert)
					xtables_error(PARAMETER_PROBLEM,
						   "multiple consecutive ! not"
						   " allowed");
				cs.invert = TRUE;
				optarg[0] = '\0';
				continue;
			}
			fprintf(stderr, "Bad argument `%s'\n", optarg);
			exit_tryhelp(2);

		default:
			if (command_default(&cs, &xtables_globals) == 1)
				/* cf. ip6tables.c */
				continue;
			break;
		}
		cs.invert = FALSE;
	}

	if (strcmp(*table, "nat") == 0 &&
	    ((policy != NULL && strcmp(policy, "DROP") == 0) ||
	    (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
		xtables_error(PARAMETER_PROBLEM,
			"\nThe \"nat\" table is not intended for filtering, "
			"the use of DROP is therefore inhibited.\n\n");

	for (matchp = cs.matches; matchp; matchp = matchp->next)
		xtables_option_mfcall(matchp->match);
	if (cs.target != NULL)
		xtables_option_tfcall(cs.target);

	/* Fix me: must put inverse options checking here --MN */

	if (optind < argc)
		xtables_error(PARAMETER_PROBLEM,
			   "unknown arguments found on commandline");
	if (!command)
		xtables_error(PARAMETER_PROBLEM, "no command specified");
	if (cs.invert)
		xtables_error(PARAMETER_PROBLEM,
			   "nothing appropriate following !");

	/* Set only if required, needed by xtables-restore */
	if (h->family == AF_UNSPEC)
		h->family = args.family;

	h->ops->post_parse(command, &cs, &args);

	if (command == CMD_REPLACE &&
	    (args.s.naddrs != 1 || args.d.naddrs != 1))
		xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
			   "specify a unique address");

	generic_opt_check(command, cs.options);

	if (chain != NULL && strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
		xtables_error(PARAMETER_PROBLEM,
			   "chain name `%s' too long (must be under %u chars)",
			   chain, XT_EXTENSION_MAXNAMELEN);

	if (command == CMD_APPEND
	    || command == CMD_DELETE
	    || command == CMD_CHECK
	    || command == CMD_INSERT
	    || command == CMD_REPLACE) {
		if (strcmp(chain, "PREROUTING") == 0
		    || strcmp(chain, "INPUT") == 0) {
			/* -o not valid with incoming packets. */
			if (cs.options & OPT_VIANAMEOUT)
				xtables_error(PARAMETER_PROBLEM,
					   "Can't use -%c with %s\n",
					   opt2char(OPT_VIANAMEOUT),
					   chain);
		}

		if (strcmp(chain, "POSTROUTING") == 0
		    || strcmp(chain, "OUTPUT") == 0) {
			/* -i not valid with outgoing packets */
			if (cs.options & OPT_VIANAMEIN)
				xtables_error(PARAMETER_PROBLEM,
					   "Can't use -%c with %s\n",
					   opt2char(OPT_VIANAMEIN),
					   chain);
		}

		/*
		 * Contrary to what iptables does, we assume that any jumpto
		 * is a custom chain jumps (if no target is found). Later on,
		 * nf_table will spot the error if the chain does not exists.
		 */
	}

	switch (command) {
	case CMD_APPEND:
		ret = add_entry(chain, *table, &cs, 0, h->family,
				args.s, args.d, cs.options&OPT_VERBOSE,
				h, true);
		break;
	case CMD_DELETE:
		ret = delete_entry(chain, *table, &cs, h->family,
				   args.s, args.d, cs.options&OPT_VERBOSE, h);
		break;
	case CMD_DELETE_NUM:
		ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
		break;
	case CMD_CHECK:
		ret = check_entry(chain, *table, &cs, h->family,
				   args.s, args.d, cs.options&OPT_VERBOSE, h);
		break;
	case CMD_REPLACE:
		ret = replace_entry(chain, *table, &cs, rulenum - 1,
				    h->family, args.s, args.d,
				    cs.options&OPT_VERBOSE, h);
		break;
	case CMD_INSERT:
		ret = add_entry(chain, *table, &cs, rulenum - 1, h->family,
				args.s, args.d, cs.options&OPT_VERBOSE, h,
				false);
		break;
	case CMD_FLUSH:
		ret = nft_rule_flush(h, chain, *table);
		break;
	case CMD_ZERO:
		ret = nft_chain_zero_counters(h, chain, *table);
		break;
	case CMD_ZERO_NUM:
		ret = nft_rule_zero_counters(h, chain, *table, rulenum - 1);
		break;
	case CMD_LIST:
	case CMD_LIST|CMD_ZERO:
	case CMD_LIST|CMD_ZERO_NUM:
		ret = list_entries(h, chain, *table,
				   rulenum,
				   cs.options&OPT_VERBOSE,
				   cs.options&OPT_NUMERIC,
				   cs.options&OPT_EXPANDED,
				   cs.options&OPT_LINENUMBERS);
		if (ret && (command & CMD_ZERO))
			ret = nft_chain_zero_counters(h, chain, *table);
		if (ret && (command & CMD_ZERO_NUM))
			ret = nft_rule_zero_counters(h, chain, *table,
						     rulenum - 1);
		break;
	case CMD_LIST_RULES:
	case CMD_LIST_RULES|CMD_ZERO:
	case CMD_LIST_RULES|CMD_ZERO_NUM:
		ret = list_rules(h, chain, *table, rulenum, cs.options&OPT_VERBOSE);
		if (ret && (command & CMD_ZERO))
			ret = nft_chain_zero_counters(h, chain, *table);
		if (ret && (command & CMD_ZERO_NUM))
			ret = nft_rule_zero_counters(h, chain, *table,
						     rulenum - 1);
		break;
	case CMD_NEW_CHAIN:
		ret = nft_chain_user_add(h, chain, *table);
		break;
	case CMD_DELETE_CHAIN:
		ret = nft_chain_user_del(h, chain, *table);
		break;
	case CMD_RENAME_CHAIN:
		ret = nft_chain_user_rename(h, chain, *table, newname);
		break;
	case CMD_SET_POLICY:
		ret = nft_chain_set(h, *table, chain, policy, NULL);
		if (ret < 0)
			xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
				      policy);
		break;
	default:
		/* We should never reach this... */
		exit_tryhelp(2);
	}

/*	if (verbose > 1)
		dump_entries(*handle); */

	xtables_rule_matches_free(&cs.matches);

	if (h->family == AF_INET) {
		free(args.s.addr.v4);
		free(args.s.mask.v4);
		free(args.d.addr.v4);
		free(args.d.mask.v4);
	} else if (h->family == AF_INET6) {
		free(args.s.addr.v6);
		free(args.s.mask.v6);
		free(args.d.addr.v6);
		free(args.d.mask.v6);
	}
	xtables_free_opts(1);

	return ret;
}
Beispiel #12
0
int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table)
{
	struct arptables_command_state cs;
	int invert = 0;
	unsigned int nsaddrs = 0, ndaddrs = 0;
	struct in_addr *saddrs = NULL, *daddrs = NULL;

	int c, verbose = 0;
	const char *chain = NULL;
	const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
	const char *policy = NULL, *newname = NULL;
	unsigned int rulenum = 0, options = 0, command = 0;
	const char *pcnt = NULL, *bcnt = NULL;
	int ret = 1;
	struct xtables_target *t;

	memset(&cs, 0, sizeof(cs));
	cs.jumpto = "";

	opts = original_opts;
	global_option_offset = 0;

	xtables_globals.orig_opts = original_opts;

	/* re-set optind to 0 in case do_command gets called
	 * a second time */
	optind = 0;

	for (t = xtables_targets; t; t = t->next) {
		t->tflags = 0;
		t->used = 0;
	}

	/* Suppress error messages: we may add new options if we
	    demand-load a protocol. */
	opterr = 0;

	while ((c = getopt_long(argc, argv,
	   "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:l:i:vnt:m:c:",
					   opts, NULL)) != -1) {
		switch (c) {
			/*
			 * Command selection
			 */
		case 'A':
			add_command(&command, CMD_APPEND, CMD_NONE,
				    invert);
			chain = optarg;
			break;

		case 'D':
			add_command(&command, CMD_DELETE, CMD_NONE,
				    invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!') {
				rulenum = parse_rulenumber(argv[optind++]);
				command = CMD_DELETE_NUM;
			}
			break;

		case 'R':
			add_command(&command, CMD_REPLACE, CMD_NONE,
				    invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				rulenum = parse_rulenumber(argv[optind++]);
			else
				xtables_error(PARAMETER_PROBLEM,
					      "-%c requires a rule number",
					      cmd2char(CMD_REPLACE));
			break;

		case 'I':
			add_command(&command, CMD_INSERT, CMD_NONE,
				    invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				rulenum = parse_rulenumber(argv[optind++]);
			else rulenum = 1;
			break;

		case 'L':
			add_command(&command, CMD_LIST, CMD_ZERO,
				    invert);
			if (optarg) chain = optarg;
			else if (optind < argc && argv[optind][0] != '-'
				 && argv[optind][0] != '!')
				chain = argv[optind++];
			break;

		case 'F':
			add_command(&command, CMD_FLUSH, CMD_NONE,
				    invert);
			if (optarg) chain = optarg;
			else if (optind < argc && argv[optind][0] != '-'
				 && argv[optind][0] != '!')
				chain = argv[optind++];
			break;

		case 'Z':
			add_command(&command, CMD_ZERO, CMD_LIST,
				    invert);
			if (optarg) chain = optarg;
			else if (optind < argc && argv[optind][0] != '-'
				&& argv[optind][0] != '!')
				chain = argv[optind++];
			break;

		case 'N':
			if (optarg && *optarg == '-')
				xtables_error(PARAMETER_PROBLEM,
					      "chain name not allowed to start "
					      "with `-'\n");
			if (xtables_find_target(optarg, XTF_TRY_LOAD))
				xtables_error(PARAMETER_PROBLEM,
						"chain name may not clash "
						"with target name\n");
			add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
				    invert);
			chain = optarg;
			break;

		case 'X':
			add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
				    invert);
			if (optarg) chain = optarg;
			else if (optind < argc && argv[optind][0] != '-'
				 && argv[optind][0] != '!')
				chain = argv[optind++];
			break;

		case 'E':
			add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
				    invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				newname = argv[optind++];
			else
				xtables_error(PARAMETER_PROBLEM,
					      "-%c requires old-chain-name and "
					      "new-chain-name",
					      cmd2char(CMD_RENAME_CHAIN));
			break;

		case 'P':
			add_command(&command, CMD_SET_POLICY, CMD_NONE,
				    invert);
			chain = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				policy = argv[optind++];
			else
				xtables_error(PARAMETER_PROBLEM,
					      "-%c requires a chain and a policy",
					      cmd2char(CMD_SET_POLICY));
			break;

		case 'h':
			if (!optarg)
				optarg = argv[optind];

			exit_printhelp();
			break;
		case 's':
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_S_IP, &cs.fw.arp.invflags,
				   invert);
			shostnetworkmask = argv[optind-1];
			break;

		case 'd':
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_D_IP, &cs.fw.arp.invflags,
				   invert);
			dhostnetworkmask = argv[optind-1];
			break;

		case 2:/* src-mac */
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_S_MAC, &cs.fw.arp.invflags,
				   invert);
			if (getmac_and_mask(argv[optind - 1],
			    cs.fw.arp.src_devaddr.addr, cs.fw.arp.src_devaddr.mask))
				xtables_error(PARAMETER_PROBLEM, "Problem with specified "
						"source mac");
			break;

		case 3:/* dst-mac */
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_D_MAC, &cs.fw.arp.invflags,
				   invert);

			if (getmac_and_mask(argv[optind - 1],
			    cs.fw.arp.tgt_devaddr.addr, cs.fw.arp.tgt_devaddr.mask))
				xtables_error(PARAMETER_PROBLEM, "Problem with specified "
						"destination mac");
			break;

		case 'l':/* hardware length */
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_H_LENGTH, &cs.fw.arp.invflags,
				   invert);
			getlength_and_mask(argv[optind - 1], &cs.fw.arp.arhln,
					   &cs.fw.arp.arhln_mask);

			if (cs.fw.arp.arhln != 6) {
				xtables_error(PARAMETER_PROBLEM,
					      "Only harware address length of"
					      " 6 is supported currently.");
			}

			break;

		case 8:/* protocol length */
			xtables_error(PARAMETER_PROBLEM, "not supported");
/*
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_P_LENGTH, &cs.fw.arp.invflags,
				   invert);

			getlength_and_mask(argv[optind - 1], &cs.fw.arp.arpln,
					   &cs.fw.arp.arpln_mask);
			break;
*/

		case 4:/* opcode */
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_OPCODE, &cs.fw.arp.invflags,
				   invert);
			if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpop,
					   &cs.fw.arp.arpop_mask, 10)) {
				int i;

				for (i = 0; i < NUMOPCODES; i++)
					if (!strcasecmp(opcodes[i], optarg))
						break;
				if (i == NUMOPCODES)
					xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode");
				cs.fw.arp.arpop = htons(i+1);
			}
			break;

		case 5:/* h-type */
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_H_TYPE, &cs.fw.arp.invflags,
				   invert);
			if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arhrd,
					   &cs.fw.arp.arhrd_mask, 16)) {
				if (strcasecmp(argv[optind-1], "Ethernet"))
					xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type");
				cs.fw.arp.arhrd = htons(1);
			}
			break;

		case 6:/* proto-type */
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_P_TYPE, &cs.fw.arp.invflags,
				   invert);
			if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpro,
					   &cs.fw.arp.arpro_mask, 0)) {
				if (strcasecmp(argv[optind-1], "ipv4"))
					xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type");
				cs.fw.arp.arpro = htons(0x800);
			}
			break;

		case 'j':
			set_option(&options, OPT_JUMP, &cs.fw.arp.invflags,
				   invert);
			cs.jumpto = parse_target(optarg);
			cs.target = command_jump(&cs.fw, cs.jumpto);
			break;

		case 'i':
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_VIANAMEIN, &cs.fw.arp.invflags,
				   invert);
			parse_interface(argv[optind-1],
					cs.fw.arp.iniface,
					cs.fw.arp.iniface_mask);
/*			cs.fw.nfcache |= NFC_IP_IF_IN; */
			break;

		case 'o':
			check_inverse(optarg, &invert, &optind, argc);
			set_option(&options, OPT_VIANAMEOUT, &cs.fw.arp.invflags,
				   invert);
			parse_interface(argv[optind-1],
					cs.fw.arp.outiface,
					cs.fw.arp.outiface_mask);
			/* cs.fw.nfcache |= NFC_IP_IF_OUT; */
			break;

		case 'v':
			if (!verbose)
				set_option(&options, OPT_VERBOSE,
					   &cs.fw.arp.invflags, invert);
			verbose++;
			break;

		case 'm': /*{
			size_t size;

			if (invert)
				exit_error(PARAMETER_PROBLEM,
					   "unexpected ! flag before --match");

			m = find_match(optarg, LOAD_MUST_SUCCEED);
			size = ARPT_ALIGN(sizeof(struct arpt_entry_match))
					 + m->size;
			m->m = fw_calloc(1, size);
			m->m->u.match_size = size;
			strcpy(m->m->u.user.name, m->name);
			m->init(m->m, &fw.nfcache);
			opts = merge_options(opts, m->extra_opts, &m->option_offset);
		}*/
		break;

		case 'n':
			set_option(&options, OPT_NUMERIC, &cs.fw.arp.invflags,
				   invert);
			break;

		case 't':
			if (invert)
				xtables_error(PARAMETER_PROBLEM,
					      "unexpected ! flag before --table");
			*table = argv[optind-1];
			break;

		case 'V':
			if (invert)
				printf("Not %s ;-)\n", program_version);
			else
				printf("%s v%s\n",
				       program_name, program_version);
			exit(0);

		case '0':
			set_option(&options, OPT_LINENUMBERS, &cs.fw.arp.invflags,
				   invert);
			break;

		case 'M':
			//modprobe = optarg;
			break;

		case 'c':

			set_option(&options, OPT_COUNTERS, &cs.fw.arp.invflags,
				   invert);
			pcnt = optarg;
			if (optind < argc && argv[optind][0] != '-'
			    && argv[optind][0] != '!')
				bcnt = argv[optind++];
			else
				xtables_error(PARAMETER_PROBLEM,
					      "-%c requires packet and byte counter",
					      opt2char(OPT_COUNTERS));

			if (sscanf(pcnt, "%llu", &cs.fw.counters.pcnt) != 1)
			xtables_error(PARAMETER_PROBLEM,
				"-%c packet counter not numeric",
				opt2char(OPT_COUNTERS));

			if (sscanf(bcnt, "%llu", &cs.fw.counters.bcnt) != 1)
				xtables_error(PARAMETER_PROBLEM,
					      "-%c byte counter not numeric",
					      opt2char(OPT_COUNTERS));

			break;


		case 1: /* non option */
			if (optarg[0] == '!' && optarg[1] == '\0') {
				if (invert)
					xtables_error(PARAMETER_PROBLEM,
						      "multiple consecutive ! not"
						      " allowed");
				invert = TRUE;
				optarg[0] = '\0';
				continue;
			}
			printf("Bad argument `%s'\n", optarg);
			exit_tryhelp(2);

		default:
			if (cs.target) {
				xtables_option_tpcall(c, argv,
						      invert, cs.target, &cs.fw);
			}
			break;
		}
		invert = FALSE;
	}

	if (cs.target)
		xtables_option_tfcall(cs.target);

	if (optind < argc)
		xtables_error(PARAMETER_PROBLEM,
			      "unknown arguments found on commandline");
	if (!command)
		xtables_error(PARAMETER_PROBLEM, "no command specified");
	if (invert)
		xtables_error(PARAMETER_PROBLEM,
			      "nothing appropriate following !");

	if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
		if (!(options & OPT_D_IP))
			dhostnetworkmask = "0.0.0.0/0";
		if (!(options & OPT_S_IP))
			shostnetworkmask = "0.0.0.0/0";
	}

	if (shostnetworkmask)
		parse_hostnetworkmask(shostnetworkmask, &saddrs,
				      &(cs.fw.arp.smsk), &nsaddrs);

	if (dhostnetworkmask)
		parse_hostnetworkmask(dhostnetworkmask, &daddrs,
				      &(cs.fw.arp.tmsk), &ndaddrs);

	if ((nsaddrs > 1 || ndaddrs > 1) &&
	    (cs.fw.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
		xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
				" source or destination IP addresses");

	if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
		xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
						 "specify a unique address");

	generic_opt_check(command, options);

	if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN)
		xtables_error(PARAMETER_PROBLEM,
				"chain name `%s' too long (must be under %i chars)",
				chain, ARPT_FUNCTION_MAXNAMELEN);

	if (nft_init(h, xtables_arp) < 0)
		xtables_error(OTHER_PROBLEM,
			      "Could not initialize nftables layer.");

	h->ops = nft_family_ops_lookup(h->family);
	if (h->ops == NULL)
		xtables_error(PARAMETER_PROBLEM, "Unknown family");

	if (command == CMD_APPEND
	    || command == CMD_DELETE
	    || command == CMD_INSERT
	    || command == CMD_REPLACE) {
		if (strcmp(chain, "PREROUTING") == 0
		    || strcmp(chain, "INPUT") == 0) {
			/* -o not valid with incoming packets. */
			if (options & OPT_VIANAMEOUT)
				xtables_error(PARAMETER_PROBLEM,
					      "Can't use -%c with %s\n",
					      opt2char(OPT_VIANAMEOUT),
					      chain);
		}

		if (strcmp(chain, "POSTROUTING") == 0
		    || strcmp(chain, "OUTPUT") == 0) {
			/* -i not valid with outgoing packets */
			if (options & OPT_VIANAMEIN)
				xtables_error(PARAMETER_PROBLEM,
						"Can't use -%c with %s\n",
						opt2char(OPT_VIANAMEIN),
						chain);
		}

		if (!cs.target && strlen(cs.jumpto) != 0) {
			size_t size;

			cs.target = xtables_find_target(XT_STANDARD_TARGET,
							XTF_LOAD_MUST_SUCCEED);
			size = sizeof(struct arpt_entry_target) + cs.target->size;
			cs.target->t = xtables_calloc(1, size);
			cs.target->t->u.target_size = size;
			strcpy(cs.target->t->u.user.name, cs.jumpto);
		}
	}

	switch (command) {
	case CMD_APPEND:
		ret = append_entry(h, chain, *table, &cs, 0,
				   nsaddrs, saddrs, ndaddrs, daddrs,
				   options&OPT_VERBOSE, true);
		break;
	case CMD_DELETE:
		ret = delete_entry(chain, *table, &cs,
				   nsaddrs, saddrs, ndaddrs, daddrs,
				   options&OPT_VERBOSE, h);
		break;
	case CMD_DELETE_NUM:
		ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
		break;
	case CMD_REPLACE:
		ret = replace_entry(chain, *table, &cs, rulenum - 1,
				    saddrs, daddrs, options&OPT_VERBOSE, h);
		break;
	case CMD_INSERT:
		ret = append_entry(h, chain, *table, &cs, rulenum - 1,
				   nsaddrs, saddrs, ndaddrs, daddrs,
				   options&OPT_VERBOSE, false);
		break;
	case CMD_LIST:
		ret = list_entries(h, chain, *table,
				   rulenum,
				   options&OPT_VERBOSE,
				   options&OPT_NUMERIC,
				   /*options&OPT_EXPANDED*/0,
				   options&OPT_LINENUMBERS);
		break;
	case CMD_FLUSH:
		ret = nft_rule_flush(h, chain, *table);
		break;
	case CMD_ZERO:
		ret = nft_chain_zero_counters(h, chain, *table);
		break;
	case CMD_LIST|CMD_ZERO:
		ret = list_entries(h, chain, *table, rulenum,
				   options&OPT_VERBOSE,
				   options&OPT_NUMERIC,
				   /*options&OPT_EXPANDED*/0,
				   options&OPT_LINENUMBERS);
		if (ret)
			ret = nft_chain_zero_counters(h, chain, *table);
		break;
	case CMD_NEW_CHAIN:
		ret = nft_chain_user_add(h, chain, *table);
		break;
	case CMD_DELETE_CHAIN:
		ret = nft_chain_user_del(h, chain, *table);
		break;
	case CMD_RENAME_CHAIN:
		ret = nft_chain_user_rename(h, chain, *table, newname);
		break;
	case CMD_SET_POLICY:
		ret = nft_chain_set(h, *table, chain, policy, NULL);
		if (ret < 0)
			xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
				      policy);
		break;
	default:
		/* We should never reach this... */
		exit_tryhelp(2);
	}

/*	if (verbose > 1)
		dump_entries(*handle);*/

	return ret;
}