int main(int arc, char * * argv) { char buf[32]; char desc[64]; /*char rhost[32];*/ unsigned short iport; unsigned int timestamp; u_int64_t packets = 0; u_int64_t bytes = 0; openlog("testobsdrdr", LOG_PERROR, LOG_USER); if(init_redirect() < 0) { fprintf(stderr, "init_redirect() failed\n"); return 1; } //add_redirect_rule("ep0", 12123, "192.168.1.23", 1234); //add_redirect_rule2("ep0", 12155, "192.168.1.155", 1255, IPPROTO_TCP); add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234, IPPROTO_UDP, "test description", 0); //add_redirect_rule2("em0", 12123, "127.1.2.3", 1234, // IPPROTO_TCP, "test description tcp"); list_rules(); list_eports_tcp(); if(get_redirect_rule("xl1", 4662, IPPROTO_TCP, buf, sizeof(buf), &iport, desc, sizeof(desc), ×tamp, &packets, &bytes) < 0) printf("get_redirect_rule() failed\n"); else { printf("\n%s:%d '%s' packets=%llu bytes=%llu\n", buf, (int)iport, desc, packets, bytes); } #if 0 if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0) printf("delete_redirect_rule() failed\n"); else printf("delete_redirect_rule() succeded\n"); if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0) printf("delete_redirect_rule() failed\n"); else printf("delete_redirect_rule() succeded\n"); #endif //test_index(); //clear_redirect_rules(); //list_rules(); return 0; }
/* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ int do_command(int argc, char *argv[], struct ebt_u_replace *replace_) { char *buffer; int c, i; int policy = 0; int rule_nr = 0; int rule_nr_end = 0; struct ebt_u_target *t; struct ebt_u_match *m; struct ebt_u_match_list *m_l; struct ebt_u_entries *entries; opterr = 0; replace = replace_; replace->flags = 0; replace->selected_chain = -1; replace->command = 'h'; if (!new_entry) { new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry)); if (!new_entry) ebt_print_memory(); } /* Put some sane values in our new entry */ ebt_initialize_entry(new_entry); new_entry->replace = replace; /* The scenario induced by this loop makes that: * '-t' and '-M' (if specified) have to come * before '-A' and the like */ /* Getopt saves the day */ while ((c = getopt_long(argc, argv, "-A:D:I:N:E:X::L::F::P:Vhi:o:j:p:s:d:t:", ebt_options, NULL)) != -1) { switch (c) { case 'A': /* Add a rule */ case 'D': /* Delete a rule */ 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 */ if (replace->command == 'N' && c == 'P') { replace->command = c; optind--; /* No table specified */ goto handle_P; } if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->command = c; replace->flags |= OPT_COMMAND; ebt_get_kernel_table(replace); if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!"))) ebt_print_error2("No chain name specified"); if (c == 'N') { if (ebt_get_chainnr(replace, optarg) != -1) ebt_print_error2("Chain %s already exists", optarg); else if (ebt_find_target(optarg)) ebt_print_error2("Target with name %s exists", optarg); else if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) ebt_print_error2("Chain name length can't exceed %d", EBT_CHAIN_MAXNAMELEN - 1); else if (strchr(optarg, ' ') != NULL) ebt_print_error2("Use of ' ' not allowed in chain names"); ebt_new_chain(replace, optarg, EBT_ACCEPT); /* This is needed to get -N x -P y working */ replace->selected_chain = ebt_get_chainnr(replace, optarg); break; } else if (c == 'X') { if (optind >= argc) { replace->selected_chain = -1; ebt_delete_chain(replace); break; } if (optind < argc - 1) ebt_print_error2("No extra options allowed with -X"); if ((replace->selected_chain = ebt_get_chainnr(replace, argv[optind])) == -1) ebt_print_error2("Chain '%s' doesn't exist", argv[optind]); ebt_delete_chain(replace); optind++; break; } if ((replace->selected_chain = ebt_get_chainnr(replace, optarg)) == -1) ebt_print_error2("Chain '%s' doesn't exist", optarg); if (c == 'E') { if (optind >= argc) ebt_print_error2("No new chain name specified"); else if (optind < argc - 1) ebt_print_error2("No extra options allowed with -E"); else if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN) ebt_print_error2("Chain name length can't exceed %d characters", EBT_CHAIN_MAXNAMELEN - 1); else if (ebt_get_chainnr(replace, argv[optind]) != -1) ebt_print_error2("Chain '%s' already exists", argv[optind]); else if (ebt_find_target(argv[optind])) ebt_print_error2("Target with name '%s' exists", argv[optind]); else if (strchr(argv[optind], ' ') != NULL) ebt_print_error2("Use of ' ' not allowed in chain names"); ebt_rename_chain(replace, argv[optind]); optind++; break; } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) { if (optind != argc - 1) ebt_print_error2("No extra options allowed with -D start_nr[:end_nr]"); if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end)) ebt_print_error2("Problem with the specified rule number(s) '%s'", argv[optind]); optind++; } else if (c == 'I') { if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9'))) rule_nr = 1; else { rule_nr = strtol(argv[optind], &buffer, 10); if (*buffer != '\0') ebt_print_error2("Problem with the specified rule number '%s'", argv[optind]); optind++; } } else if (c == 'P') { handle_P: if (optind >= argc) ebt_print_error2("No policy specified"); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(argv[optind], ebt_standard_targets[i])) { policy = -i -1; if (policy == EBT_CONTINUE) ebt_print_error2("Wrong policy '%s'", argv[optind]); break; } if (i == NUM_STANDARD_TARGETS) ebt_print_error2("Unknown policy '%s'", argv[optind]); optind++; } break; case 'L': /* List */ case 'F': /* Flush */ if (replace->flags & OPT_COMMAND) ebt_print_error2("Multiple commands are not allowed"); replace->command = c; replace->flags |= OPT_COMMAND; ebt_get_kernel_table(replace); 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) replace->selected_chain = i; break; case 'V': /* Version */ if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->command = 'V'; PRINT_VERSION; exit(0); case 'h': /* Help */ if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->command = 'h'; /* All other arguments should be extension names */ while (optind < argc) { struct ebt_u_match *m; if (!strcasecmp("list_extensions", argv[optind])) { ebt_list_extensions(); exit(0); } if ((m = ebt_find_match(argv[optind]))) ebt_add_match(new_entry, m); else { if (!(t = ebt_find_target(argv[optind]))) ebt_print_error2("Extension '%s' not found", argv[optind]); if (replace->flags & OPT_JUMP) ebt_print_error2("Sorry, you can only see help for one target extension at a time"); replace->flags |= OPT_JUMP; new_entry->t = (struct ebt_entry_target *)t; } optind++; } break; case 't': /* Table */ if (OPT_COMMANDS) ebt_print_error2("Please put the -t option first"); ebt_check_option2(&(replace->flags), OPT_TABLE); if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1) ebt_print_error2("Table name length cannot exceed %d characters", EBT_TABLE_MAXNAMELEN - 1); strcpy(replace->name, 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 */ if (!OPT_COMMANDS) ebt_print_error2("No command specified"); if (replace->command != 'A' && replace->command != 'D' && replace->command != 'I') ebt_print_error2("Command and option do not match"); if (c == 'i') { ebt_check_option2(&(replace->flags), OPT_IN); if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING) ebt_print_error2("Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IIN; if (strlen(optarg) >= IFNAMSIZ) big_iface_length: ebt_print_error2("Interface name length cannot exceed %d characters", IFNAMSIZ - 1); strcpy(new_entry->in, optarg); if (parse_iface(new_entry->in, "-i")) return -1; break; } else if (c == 2) { ebt_check_option2(&(replace->flags), OPT_LOGICALIN); if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING) ebt_print_error2("Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ILOGICALIN; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; strcpy(new_entry->logical_in, optarg); if (parse_iface(new_entry->logical_in, "--logical-in")) return -1; break; } else if (c == 'o') { ebt_check_option2(&(replace->flags), OPT_OUT); if (replace->selected_chain < 2 || replace->selected_chain == NF_BR_BROUTING) ebt_print_error2("Use -o only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; strcpy(new_entry->out, optarg); if (parse_iface(new_entry->out, "-o")) return -1; break; } else if (c == 3) { ebt_check_option2(&(replace->flags), OPT_LOGICALOUT); if (replace->selected_chain < 2 || replace->selected_chain == NF_BR_BROUTING) ebt_print_error2("Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ILOGICALOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; strcpy(new_entry->logical_out, optarg); if (parse_iface(new_entry->logical_out, "--logical-out")) return -1; break; } else if (c == 'j') { ebt_check_option2(&(replace->flags), OPT_JUMP); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(optarg, ebt_standard_targets[i])) { t = ebt_find_target(EBT_STANDARD_TARGET); ((struct ebt_standard_target *) t->t)->verdict = -i - 1; break; } if (-i - 1 == EBT_RETURN && replace->selected_chain < NF_BR_NUMHOOKS) { ebt_print_error2("Return target only for user defined chains"); } else if (i != NUM_STANDARD_TARGETS) break; if ((i = ebt_get_chainnr(replace, optarg)) != -1) { if (i < NF_BR_NUMHOOKS) ebt_print_error2("Don't jump to a standard chain"); t = ebt_find_target(EBT_STANDARD_TARGET); ((struct ebt_standard_target *) t->t)->verdict = i - NF_BR_NUMHOOKS; break; } else { /* Must be an extension then */ struct ebt_u_target *t; t = ebt_find_target(optarg); /* -j standard not allowed either */ if (!t || t == (struct ebt_u_target *)new_entry->t) ebt_print_error2("Illegal target name '%s'", optarg); new_entry->t = (struct ebt_entry_target *)t; ebt_find_target(EBT_STANDARD_TARGET)->used = 0; t->used = 1; } break; } else if (c == 's') { ebt_check_option2(&(replace->flags), OPT_SOURCE); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ISOURCE; if (ebt_get_mac_and_mask(optarg, new_entry->sourcemac, new_entry->sourcemsk)) ebt_print_error2("Problem with specified source mac '%s'", optarg); new_entry->bitmask |= EBT_SOURCEMAC; break; } else if (c == 'd') { ebt_check_option2(&(replace->flags), OPT_DEST); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IDEST; if (ebt_get_mac_and_mask(optarg, new_entry->destmac, new_entry->destmsk)) ebt_print_error2("Problem with specified destination mac '%s'", optarg); new_entry->bitmask |= EBT_DESTMAC; break; } ebt_check_option2(&(replace->flags), OPT_PROTOCOL); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IPROTO; new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO); i = strtol(optarg, &buffer, 16); if (*buffer == '\0' && (i < 0 || i > 0xFFFF)) ebt_print_error2("Problem with the specified protocol"); if (*buffer != '\0') { const struct ethertypeent *ent; if (!strcasecmp(optarg, "LENGTH")) { new_entry->bitmask |= EBT_802_3; break; } ent = getethertypebyname(optarg); if (!ent) ebt_print_error2("Problem with the specified Ethernet protocol '%s'", optarg); new_entry->ethproto = ent->e_ethertype; } else new_entry->ethproto = i; if (new_entry->ethproto < 0x0600) ebt_print_error2("Sorry, protocols have values above or equal to 0x0600"); break; case 1 : if (!strcmp(optarg, "!")) ebt_check_inverse2(optarg); else ebt_print_error2("Bad argument : '%s'", optarg); /* ebt_check_inverse() did optind++ */ optind--; continue; default: /* Is it a target option? */ t = (struct ebt_u_target *)new_entry->t; if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t))) { goto check_extension; } /* Is it a match_option? */ for (m = ebt_matches; m; m = m->next) if (m->parse(c - m->option_offset, argv, argc, new_entry, &m->flags, &m->m)) break; if (m != NULL) { if (m->used == 0) { ebt_add_match(new_entry, m); m->used = 1; } goto check_extension; } if (c == '?') ebt_print_error2("Unknown argument: '%s'", argv[optind - 1], (char)optopt, (char)c); else { 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"); } check_extension: if (replace->command != 'A' && replace->command != 'I' && replace->command != 'D') ebt_print_error2("Extensions only for -A, -I and -D"); } ebt_invert = 0; } if (!(table = ebt_find_table(replace->name))) ebt_print_error2("Bad table name"); if (replace->command == 'h') { print_help(); exit(0); } /* Do the final checks */ if (replace->command == 'A' || replace->command == 'I' || replace->command == 'D') { /* This will put the hook_mask right for the chains */ ebt_check_for_loops(replace); entries = ebt_to_chain(replace); m_l = new_entry->m_list; t = (struct ebt_u_target *)new_entry->t; while (m_l) { m = (struct ebt_u_match *)(m_l->m); m->final_check(new_entry, m->m, replace->name, entries->hook_mask, 0); m_l = m_l->next; } t->final_check(new_entry, t->t, replace->name, entries->hook_mask, 0); } /* So, the extensions can work with the host endian. * The kernel does not have to do this of course */ new_entry->ethproto = htons(new_entry->ethproto); if (replace->command == 'P') { if (replace->selected_chain < NF_BR_NUMHOOKS && policy == EBT_RETURN) ebt_print_error2("Policy RETURN only allowed for user defined chains"); ebt_change_policy(replace, policy); } else if (replace->command == 'L') { list_rules(); exit(0); } if (replace->command == 'F') { ebt_flush_chains(replace); } else if (replace->command == 'A' || replace->command == 'I') { ebt_add_rule(replace, new_entry, rule_nr); if (rule_nr <= 0) rule_nr--; rule_nr_end = rule_nr; /* a jump to a udc requires checking for loops */ if (!strcmp(new_entry->t->u.name, EBT_STANDARD_TARGET) && ((struct ebt_standard_target *)(new_entry->t))->verdict >= 0) { /* FIXME: this can be done faster */ ebt_check_for_loops(replace); } /* Do the final_check(), for all entries. * This is needed when adding a rule that has a chain target */ i = -1; while (++i != replace->num_chains) { struct ebt_u_entry *e; entries = replace->chains[i]; if (!entries) { if (i < NF_BR_NUMHOOKS) continue; else ebt_print_bug("whoops\n"); } e = entries->entries->next; while (e != entries->entries) { /* Userspace extensions use host endian */ e->ethproto = ntohs(e->ethproto); ebt_do_final_checks(replace, e, entries); e->ethproto = htons(e->ethproto); e = e->next; } } /* Don't reuse the added rule */ new_entry = NULL; } else if (replace->command == 'D') { ebt_delete_rule(replace, new_entry, rule_nr, rule_nr_end); } /* Commands -N, -E, -X fall through */ if (table->check) table->check(replace); ebt_deliver_table(replace); if (replace->nentries) ebt_deliver_counters(replace); return 0; }
int main(int argc, char **argv) { int overwrite; int interactive; int remove; int have_colors; struct Colors colors, colors_tmp; struct Cell_stats statf; int have_stats = 0; struct FPRange range; DCELL min, max; char *name, *mapset; char *style, *cmap, *cmapset; char *rules; int fp; struct GModule *module; struct { struct Flag *r, *w, *l, *g, *a, *e, *i, *q, *n; } flag; struct { struct Option *map, *colr, *rast, *rules; } opt; G_gisinit(argv[0]); module = G_define_module(); module->keywords = _("raster, color table"); module->description = _("Creates/modifies the color table associated with a raster map layer."); opt.map = G_define_standard_option(G_OPT_R_MAP); opt.map->required = NO; opt.map->guisection = _("Required"); scan_rules(); opt.colr = G_define_option(); opt.colr->key = "color"; opt.colr->key_desc = "style"; opt.colr->type = TYPE_STRING; opt.colr->required = NO; opt.colr->options = rules_list(); opt.colr->description = _("Type of color table"); opt.colr->descriptions = rules_descriptions(); opt.colr->guisection = _("Colors"); opt.rast = G_define_option(); opt.rast->key = "raster"; opt.rast->type = TYPE_STRING; opt.rast->required = NO; opt.rast->gisprompt = "old,cell,raster"; opt.rast->description = _("Raster map name from which to copy color table"); opt.rules = G_define_standard_option(G_OPT_F_INPUT); opt.rules->key = "rules"; opt.rules->required = NO; opt.rules->description = _("Path to rules file (\"-\" to read rules from stdin)"); opt.rules->guisection = _("Colors"); flag.r = G_define_flag(); flag.r->key = 'r'; flag.r->description = _("Remove existing color table"); flag.w = G_define_flag(); flag.w->key = 'w'; flag.w->description = _("Only write new color table if one doesn't already exist"); flag.l = G_define_flag(); flag.l->key = 'l'; flag.l->description = _("List available rules then exit"); flag.n = G_define_flag(); flag.n->key = 'n'; flag.n->description = _("Invert colors"); flag.n->guisection = _("Colors"); flag.g = G_define_flag(); flag.g->key = 'g'; flag.g->description = _("Logarithmic scaling"); flag.g->guisection = _("Colors"); flag.a = G_define_flag(); flag.a->key = 'a'; flag.a->description = _("Logarithmic-absolute scaling"); flag.a->guisection = _("Colors"); flag.e = G_define_flag(); flag.e->key = 'e'; flag.e->description = _("Histogram equalization"); flag.e->guisection = _("Colors"); flag.i = G_define_flag(); flag.i->key = 'i'; flag.i->description = _("Enter rules interactively"); /* please, remove before GRASS 7 released */ flag.q = G_define_flag(); flag.q->key = 'q'; flag.q->description = _("Run quietly"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); /* please, remove before GRASS 7 released */ if (flag.q->answer) { G_putenv("GRASS_VERBOSE", "0"); G_warning(_("The '-q' flag is superseded and will be removed " "in future. Please use '--quiet' instead.")); } if (flag.l->answer) { list_rules(); return EXIT_SUCCESS; } overwrite = !flag.w->answer; interactive = flag.i->answer; remove = flag.r->answer; name = opt.map->answer; style = opt.colr->answer; cmap = opt.rast->answer; rules = opt.rules->answer; if (!name) G_fatal_error(_("No raster map specified")); if (!cmap && !style && !rules && !interactive && !remove) G_fatal_error(_("One of \"-i\" or \"-r\" or options \"color\", \"rast\" or \"rules\" must be specified!")); if (interactive && (style || rules || cmap)) G_fatal_error(_("Interactive mode is incompatible with \"color\", \"rules\", and \"raster\" options")); if ((style && (cmap || rules)) || (cmap && rules)) { if ((style && rules && !cmap) && strcmp(style, "rules") == 0) style = NULL; else G_fatal_error( _("\"color\", \"rules\", and \"raster\" options are mutually exclusive")); } /* handle rules="-" (from stdin) by translating that to colors=rules */ /* this method should not be ported to GRASS 7 verbatim, as color=rules DNE */ if (rules && strcmp(rules, "-") == 0) { style = G_store("rules"); rules = NULL; } if (flag.g->answer && flag.a->answer) G_fatal_error(_("-g and -a flags are mutually exclusive")); mapset = G_find_cell2(name, ""); if (mapset == NULL) G_fatal_error(_("Raster map <%s> not found"), name); if (remove) { int stat = G_remove_colors(name, mapset); if (stat < 0) G_fatal_error(_("Unable to remove color table of raster map <%s>"), name); if (stat == 0) G_warning(_("Color table of raster map <%s> not found"), name); return EXIT_SUCCESS; } G_suppress_warnings(1); have_colors = G_read_colors(name, mapset, &colors); /*if (have_colors >= 0) G_free_colors(&colors); */ if (have_colors > 0 && !overwrite) { G_warning(_("Color table exists. Exiting.")); exit(EXIT_FAILURE); } G_suppress_warnings(0); fp = G_raster_map_is_fp(name, mapset); G_read_fp_range(name, mapset, &range); G_get_fp_range_min_max(&range, &min, &max); if (interactive) { if (!read_color_rules(stdin, &colors, min, max, fp)) exit(EXIT_FAILURE); } else if (style) { /* * here the predefined color-table color-styles are created by GRASS library calls. */ if (strcmp(style, "random") == 0) { if (fp) G_fatal_error(_("Color table 'random' is not supported for floating point raster map")); G_make_random_colors(&colors, (CELL) min, (CELL) max); } else if (strcmp(style, "grey.eq") == 0) { if (fp) G_fatal_error(_("Color table 'grey.eq' is not supported for floating point raster map")); if (!have_stats) have_stats = get_stats(name, mapset, &statf); G_make_histogram_eq_colors(&colors, &statf); } else if (strcmp(style, "grey.log") == 0) { if (fp) G_fatal_error(_("Color table 'grey.log' is not supported for floating point raster map")); if (!have_stats) have_stats = get_stats(name, mapset, &statf); G_make_histogram_log_colors(&colors, &statf, (CELL) min, (CELL) max); } else if (strcmp(style, "rules") == 0) { if (!read_color_rules(stdin, &colors, min, max, fp)) exit(EXIT_FAILURE); } else if (find_rule(style)) G_make_fp_colors(&colors, style, min, max); else G_fatal_error(_("Unknown color request '%s'"), style); } else if (rules) { if (!G_load_fp_colors(&colors, rules, min, max)) { /* for backwards compatibility try as std name; remove for GRASS 7 */ char path[GPATH_MAX]; /* don't bother with native dirsep as not needed for backwards compatibility */ sprintf(path, "%s/etc/colors/%s", G_gisbase(), rules); if (!G_load_fp_colors(&colors, path, min, max)) G_fatal_error(_("Unable to load rules file <%s>"), rules); } } else { /* use color from another map (cmap) */ cmapset = G_find_cell2(cmap, ""); if (cmapset == NULL) G_fatal_error(_("Raster map <%s> not found"), cmap); if (G_read_colors(cmap, cmapset, &colors) < 0) G_fatal_error(_("Unable to read color table for raster map <%s>"), cmap); } if (fp) G_mark_colors_as_fp(&colors); if (flag.n->answer) G_invert_colors(&colors); if (flag.e->answer) { if (fp) { struct FP_stats fpstats; get_fp_stats(name, mapset, &fpstats, min, max, flag.g->answer, flag.a->answer); G_histogram_eq_colors_fp(&colors_tmp, &colors, &fpstats); } else { if (!have_stats) have_stats = get_stats(name, mapset, &statf); G_histogram_eq_colors(&colors_tmp, &colors, &statf); } colors = colors_tmp; } if (flag.g->answer) { G_log_colors(&colors_tmp, &colors, 100); colors = colors_tmp; } if (flag.a->answer) { G_abs_log_colors(&colors_tmp, &colors, 100); colors = colors_tmp; } if (fp) G_mark_colors_as_fp(&colors); if (G_write_colors(name, mapset, &colors) >= 0) G_message(_("Color table for raster map <%s> set to '%s'"), name, interactive ? "rules" : style ? style : rules ? rules : cmap); exit(EXIT_SUCCESS); }
/* 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; }
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; }
/* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ int do_command(int argc, char *argv[], int exec_style, struct ebt_u_replace *replace_) { char *buffer; int c, i; int zerochain = -1; /* Needed for the -Z option (we can have -Z <this> -L <that>) */ int chcounter; /* Needed for -C */ int policy = 0; int rule_nr = 0; int rule_nr_end = 0; struct ebt_u_target *t; struct ebt_u_match *m; struct ebt_u_watcher *w; struct ebt_u_match_list *m_l; struct ebt_u_watcher_list *w_l; struct ebt_u_entries *entries; opterr = 0; ebt_modprobe = NULL; replace = replace_; /* The daemon doesn't use the environment variable */ if (exec_style == EXEC_STYLE_PRG) { buffer = getenv(ATOMIC_ENV_VARIABLE); if (buffer) { replace->filename = malloc(strlen(buffer) + 1); if (!replace->filename) ebt_print_memory(); strcpy(replace->filename, buffer); buffer = NULL; } } replace->flags &= OPT_KERNELDATA; /* ebtablesd needs OPT_KERNELDATA */ replace->selected_chain = -1; replace->command = 'h'; if (!new_entry) { new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry)); if (!new_entry) ebt_print_memory(); } /* Put some sane values in our new entry */ ebt_initialize_entry(new_entry); new_entry->replace = replace; /* The scenario induced by this loop makes that: * '-t' ,'-M' and --atomic (if specified) have to come * before '-A' and the like */ /* 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:", ebt_options, NULL)) != -1) { 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 */ if (replace->command == 'N' && c == 'P') { replace->command = c; optind--; /* No table specified */ goto handle_P; } if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->command = c; replace->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') { if (ebt_get_chainnr(replace, optarg) != -1) ebt_print_error2("Chain %s already exists", optarg); else if (ebt_find_target(optarg)) ebt_print_error2("Target with name %s exists", optarg); else if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) ebt_print_error2("Chain name length can't exceed %d", EBT_CHAIN_MAXNAMELEN - 1); else if (strchr(optarg, ' ') != NULL) ebt_print_error2("Use of ' ' not allowed in chain names"); ebt_new_chain(replace, optarg, EBT_ACCEPT); /* This is needed to get -N x -P y working */ replace->selected_chain = ebt_get_chainnr(replace, optarg); break; } else if (c == 'X') { if (optind >= argc) { replace->selected_chain = -1; ebt_delete_chain(replace); break; } if (optind < argc - 1) ebt_print_error2("No extra options allowed with -X"); if ((replace->selected_chain = ebt_get_chainnr(replace, argv[optind])) == -1) ebt_print_error2("Chain '%s' doesn't exist", argv[optind]); ebt_delete_chain(replace); if (ebt_errormsg[0] != '\0') return -1; optind++; break; } if ((replace->selected_chain = ebt_get_chainnr(replace, optarg)) == -1) ebt_print_error2("Chain '%s' doesn't exist", optarg); if (c == 'E') { if (optind >= argc) ebt_print_error2("No new chain name specified"); else if (optind < argc - 1) ebt_print_error2("No extra options allowed with -E"); else if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN) ebt_print_error2("Chain name length can't exceed %d characters", EBT_CHAIN_MAXNAMELEN - 1); else if (ebt_get_chainnr(replace, argv[optind]) != -1) ebt_print_error2("Chain '%s' already exists", argv[optind]); else if (ebt_find_target(argv[optind])) ebt_print_error2("Target with name '%s' exists", argv[optind]); else if (strchr(argv[optind], ' ') != NULL) ebt_print_error2("Use of ' ' not allowed in chain names"); ebt_rename_chain(replace, argv[optind]); optind++; break; } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) { if (optind != argc - 1) ebt_print_error2("No extra options allowed with -D start_nr[:end_nr]"); if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end)) ebt_print_error2("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)) == -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 = strtol(argv[optind], &buffer, 10); if (*buffer != '\0') ebt_print_error2("Problem with the specified rule number '%s'", argv[optind]); optind++; } } else if (c == 'P') { handle_P: if (optind >= argc) ebt_print_error2("No policy specified"); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(argv[optind], ebt_standard_targets[i])) { policy = -i -1; if (policy == EBT_CONTINUE) ebt_print_error2("Wrong policy '%s'", argv[optind]); break; } if (i == NUM_STANDARD_TARGETS) ebt_print_error2("Unknown policy '%s'", argv[optind]); optind++; } break; case 'L': /* List */ case 'F': /* Flush */ case 'Z': /* Zero counters */ if (c == 'Z') { if ((replace->flags & OPT_ZERO) || (replace->flags & OPT_COMMAND && replace->command != 'L')) print_zero: ebt_print_error2("Command -Z only allowed together with command -L"); replace->flags |= OPT_ZERO; } else { if (replace->flags & OPT_COMMAND) ebt_print_error2("Multiple commands are not allowed"); replace->command = c; replace->flags |= OPT_COMMAND; if (replace->flags & OPT_ZERO && c != 'L') goto print_zero; } #ifdef SILENT_DAEMON if (c== 'L' && exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("-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) ebt_print_error2("Multiple commands are not allowed"); replace->command = 'V'; if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"); PRINT_VERSION; exit(0); case 'M': /* Modprobe */ if (OPT_COMMANDS) ebt_print_error2("Please put the -M option earlier"); free(ebt_modprobe); ebt_modprobe = optarg; break; case 'h': /* Help */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("-h not supported in daemon mode"); #endif if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->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(); 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 = ebt_find_target(argv[optind]))) ebt_print_error2("Extension '%s' not found", argv[optind]); if (replace->flags & OPT_JUMP) ebt_print_error2("Sorry, you can only see help for one target extension at a time"); replace->flags |= OPT_JUMP; new_entry->t = (struct ebt_entry_target *)t; } optind++; } break; case 't': /* Table */ if (OPT_COMMANDS) ebt_print_error2("Please put the -t option first"); ebt_check_option2(&(replace->flags), OPT_TABLE); if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1) ebt_print_error2("Table name length cannot exceed %d characters", EBT_TABLE_MAXNAMELEN - 1); strcpy(replace->name, 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) ebt_print_error2("No command specified"); if (replace->command != 'A' && replace->command != 'D' && replace->command != 'I' && replace->command != 'C') ebt_print_error2("Command and option do not match"); if (c == 'i') { ebt_check_option2(&(replace->flags), OPT_IN); if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING) ebt_print_error2("Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IIN; if (strlen(optarg) >= IFNAMSIZ) big_iface_length: ebt_print_error2("Interface name length cannot exceed %d characters", IFNAMSIZ - 1); strcpy(new_entry->in, optarg); if (parse_iface(new_entry->in, "-i")) return -1; break; } else if (c == 2) { ebt_check_option2(&(replace->flags), OPT_LOGICALIN); if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING) ebt_print_error2("Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ILOGICALIN; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; strcpy(new_entry->logical_in, optarg); if (parse_iface(new_entry->logical_in, "--logical-in")) return -1; break; } else if (c == 'o') { ebt_check_option2(&(replace->flags), OPT_OUT); if (replace->selected_chain < 2 )//|| replace->selected_chain == NF_BR_BROUTING) ebt_print_error2("Use -o only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; strcpy(new_entry->out, optarg); if (parse_iface(new_entry->out, "-o")) return -1; break; } else if (c == 3) { ebt_check_option2(&(replace->flags), OPT_LOGICALOUT); if (replace->selected_chain < 2 || replace->selected_chain == NF_BR_BROUTING) ebt_print_error2("Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ILOGICALOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; strcpy(new_entry->logical_out, optarg); if (parse_iface(new_entry->logical_out, "--logical-out")) return -1; break; } else if (c == 'j') { ebt_check_option2(&(replace->flags), OPT_JUMP); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(optarg, ebt_standard_targets[i])) { t = ebt_find_target(EBT_STANDARD_TARGET); ((struct ebt_standard_target *) t->t)->verdict = -i - 1; break; } if (-i - 1 == EBT_RETURN && replace->selected_chain < NF_BR_NUMHOOKS) { ebt_print_error2("Return target only for user defined chains"); } else if (i != NUM_STANDARD_TARGETS) break; if ((i = ebt_get_chainnr(replace, optarg)) != -1) { if (i < NF_BR_NUMHOOKS) ebt_print_error2("Don't jump to a standard chain"); t = ebt_find_target(EBT_STANDARD_TARGET); ((struct ebt_standard_target *) t->t)->verdict = i - NF_BR_NUMHOOKS; break; } else { /* Must be an extension then */ struct ebt_u_target *t; t = ebt_find_target(optarg); /* -j standard not allowed either */ if (!t || t == (struct ebt_u_target *)new_entry->t) ebt_print_error2("Illegal target name '%s'", optarg); new_entry->t = (struct ebt_entry_target *)t; ebt_find_target(EBT_STANDARD_TARGET)->used = 0; t->used = 1; } break; } else if (c == 's') { ebt_check_option2(&(replace->flags), OPT_SOURCE); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ISOURCE; if (ebt_get_mac_and_mask(optarg, new_entry->sourcemac, new_entry->sourcemsk)) ebt_print_error2("Problem with specified source mac '%s'", optarg); new_entry->bitmask |= EBT_SOURCEMAC; break; } else if (c == 'd') { ebt_check_option2(&(replace->flags), OPT_DEST); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IDEST; if (ebt_get_mac_and_mask(optarg, new_entry->destmac, new_entry->destmsk)) ebt_print_error2("Problem with specified destination mac '%s'", optarg); new_entry->bitmask |= EBT_DESTMAC; break; } else if (c == 'c') { ebt_check_option2(&(replace->flags), OPT_COUNT); if (ebt_check_inverse2(optarg)) ebt_print_error2("Unexpected '!' after -c"); if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-') ebt_print_error2("Option -c needs 2 arguments"); new_entry->cnt.pcnt = strtoull(optarg, &buffer, 10); if (*buffer != '\0') ebt_print_error2("Packet counter '%s' invalid", optarg); new_entry->cnt.bcnt = strtoull(argv[optind], &buffer, 10); if (*buffer != '\0') ebt_print_error2("Packet counter '%s' invalid", argv[optind]); optind++; break; } ebt_check_option2(&(replace->flags), OPT_PROTOCOL); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IPROTO; new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO); i = strtol(optarg, &buffer, 16); if (*buffer == '\0' && (i < 0 || i > 0xFFFF)) ebt_print_error2("Problem with the specified protocol"); if (*buffer != '\0') { struct ethertypeent *ent; if (!strcasecmp(optarg, "LENGTH")) { new_entry->bitmask |= EBT_802_3; break; } ent = getethertypebyname(optarg); if (!ent) ebt_print_error2("Problem with the specified Ethernet protocol '%s', perhaps "_PATH_ETHERTYPES " is missing", optarg); new_entry->ethproto = ent->e_ethertype; } else new_entry->ethproto = i; if (new_entry->ethproto < 0x0600) ebt_print_error2("Sorry, protocols have values above or equal to 0x0600"); break; case 4 : /* Lc */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--Lc is not supported in daemon mode"); #endif ebt_check_option2(&(replace->flags), LIST_C); if (replace->command != 'L') ebt_print_error("Use --Lc with -L"); replace->flags |= LIST_C; break; case 5 : /* Ln */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--Ln is not supported in daemon mode"); #endif ebt_check_option2(&(replace->flags), LIST_N); if (replace->command != 'L') ebt_print_error2("Use --Ln with -L"); if (replace->flags & LIST_X) ebt_print_error2("--Lx is not compatible with --Ln"); replace->flags |= LIST_N; break; case 6 : /* Lx */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--Lx is not supported in daemon mode"); #endif ebt_check_option2(&(replace->flags), LIST_X); if (replace->command != 'L') ebt_print_error2("Use --Lx with -L"); if (replace->flags & LIST_N) ebt_print_error2("--Lx is not compatible with --Ln"); replace->flags |= LIST_X; break; case 12 : /* Lmac2 */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error("--Lmac2 is not supported in daemon mode"); #endif ebt_check_option2(&(replace->flags), LIST_MAC2); if (replace->command != 'L') ebt_print_error2("Use --Lmac2 with -L"); replace->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); else ebt_print_error2("Bad argument : '%s'", optarg); /* ebt_check_inverse() did optind++ */ optind--; continue; default: /* Is it a target option? */ t = (struct ebt_u_target *)new_entry->t; if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t))) { if (ebt_errormsg[0] != '\0') return -1; goto check_extension; } /* Is it a match_option? */ for (m = ebt_matches; m; m = m->next) if (m->parse(c - m->option_offset, argv, argc, new_entry, &m->flags, &m->m)) break; if (m != NULL) { if (ebt_errormsg[0] != '\0') return -1; if (m->used == 0) { ebt_add_match(new_entry, m); m->used = 1; } goto check_extension; } /* Is it a watcher option? */ for (w = ebt_watchers; w; w = w->next) if (w->parse(c - w->option_offset, argv, argc, new_entry, &w->flags, &w->w)) break; 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 (replace->command != 'A' && replace->command != 'I' && replace->command != 'D' && replace->command != 'C') ebt_print_error2("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 (replace->command == 'h' && !(replace->flags & OPT_ZERO)) { print_help(); if (exec_style == EXEC_STYLE_PRG) exit(0); } /* Do the final checks */ if (replace->command == 'A' || replace->command == 'I' || replace->command == 'D' || replace->command == 'C') { /* This will put the hook_mask right for the chains */ ebt_check_for_loops(replace); if (ebt_errormsg[0] != '\0') return -1; entries = ebt_to_chain(replace); m_l = new_entry->m_list; w_l = new_entry->w_list; t = (struct ebt_u_target *)new_entry->t; while (m_l) { m = (struct ebt_u_match *)(m_l->m); m->final_check(new_entry, m->m, replace->name, entries->hook_mask, 0); if (ebt_errormsg[0] != '\0') return -1; m_l = m_l->next; } while (w_l) { w = (struct ebt_u_watcher *)(w_l->w); w->final_check(new_entry, w->w, replace->name, entries->hook_mask, 0); if (ebt_errormsg[0] != '\0') return -1; w_l = w_l->next; } t->final_check(new_entry, t->t, replace->name, entries->hook_mask, 0); if (ebt_errormsg[0] != '\0') return -1; } /* So, the extensions can work with the host endian. * The kernel does not have to do this of course */ new_entry->ethproto = htons(new_entry->ethproto); if (replace->command == 'P') { if (replace->selected_chain < NF_BR_NUMHOOKS && policy == EBT_RETURN) ebt_print_error2("Policy RETURN only allowed for user defined chains"); ebt_change_policy(replace, policy); if (ebt_errormsg[0] != '\0') return -1; } else if (replace->command == 'L') { list_rules(); if (!(replace->flags & OPT_ZERO) && exec_style == EXEC_STYLE_PRG) exit(0); } if (replace->flags & OPT_ZERO) { replace->selected_chain = zerochain; ebt_zero_counters(replace); } else if (replace->command == 'F') { ebt_flush_chains(replace); } else if (replace->command == 'A' || replace->command == 'I') { ebt_add_rule(replace, new_entry, rule_nr); if (ebt_errormsg[0] != '\0') return -1; /* Makes undoing the add easier (jumps to delete_the_rule) */ if (rule_nr <= 0) rule_nr--; rule_nr_end = rule_nr; /* a jump to a udc requires checking for loops */ if (!strcmp(new_entry->t->u.name, EBT_STANDARD_TARGET) && ((struct ebt_standard_target *)(new_entry->t))->verdict >= 0) { /* FIXME: this can be done faster */ ebt_check_for_loops(replace); if (ebt_errormsg[0] != '\0') goto delete_the_rule; } /* Do the final_check(), for all entries. * This is needed when adding a rule that has a chain target */ i = -1; while (++i != replace->num_chains) { struct ebt_u_entry *e; entries = replace->chains[i]; if (!entries) { if (i < NF_BR_NUMHOOKS) continue; else ebt_print_bug("whoops\n"); } e = entries->entries->next; while (e != entries->entries) { /* Userspace extensions use host endian */ e->ethproto = ntohs(e->ethproto); ebt_do_final_checks(replace, e, entries); if (ebt_errormsg[0] != '\0') goto delete_the_rule; e->ethproto = htons(e->ethproto); e = e->next; } } /* Don't reuse the added rule */ new_entry = NULL; } else if (replace->command == 'D') { delete_the_rule: ebt_delete_rule(replace, new_entry, rule_nr, rule_nr_end); if (ebt_errormsg[0] != '\0') return -1; } 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); } return 0; }