void
ipfw_nat64clat_handler(int ac, char *av[])
{
	const char *name;
	int tcmd;
	uint8_t set;

	if (co.use_set != 0)
		set = co.use_set - 1;
	else
		set = 0;
	ac--; av++;

	NEED1("nat64clat needs instance name");
	name = *av;
	if (nat64clat_check_name(name) != 0) {
		if (strcmp(name, "all") == 0)
			name = NULL;
		else
			errx(EX_USAGE, "nat64clat instance name %s is invalid",
			    name);
	}
	ac--; av++;
	NEED1("nat64clat needs command");

	tcmd = get_token(nat64cmds, *av, "nat64clat command");
	if (name == NULL && tcmd != TOK_DESTROY && tcmd != TOK_LIST)
		errx(EX_USAGE, "nat64clat instance name required");
	switch (tcmd) {
	case TOK_CREATE:
		ac--; av++;
		nat64clat_create(name, set, ac, av);
		break;
	case TOK_CONFIG:
		ac--; av++;
		nat64clat_config(name, set, ac, av);
		break;
	case TOK_LIST:
		nat64clat_foreach(nat64clat_show_cb, name, set, 1);
		break;
	case TOK_DESTROY:
		if (name == NULL)
			nat64clat_foreach(nat64clat_destroy_cb, NULL, set, 0);
		else
			nat64clat_destroy(name, set);
		break;
	case TOK_STATS:
		ac--; av++;
		if (ac == 0) {
			nat64clat_stats(name, set);
			break;
		}
		tcmd = get_token(nat64statscmds, *av, "stats command");
		if (tcmd == TOK_RESET)
			nat64clat_reset_stats(name, set);
	}
}
Exemple #2
0
/*
 * Modifies existing table
 *
 * ipfw table NAME modify [ limit number ]
 */
static void
table_modify(ipfw_obj_header *oh, int ac, char *av[])
{
	ipfw_xtable_info xi;
	int tcmd;

	memset(&xi, 0, sizeof(xi));

	while (ac > 0) {
		tcmd = get_token(tablenewcmds, *av, "option");
		ac--; av++;

		switch (tcmd) {
		case TOK_LIMIT:
			NEED1("limit value required");
			xi.limit = strtol(*av, NULL, 10);
			xi.mflags |= IPFW_TMFLAGS_LIMIT;
			ac--; av++;
			break;
		default:
			errx(EX_USAGE, "cmd is not supported for modificatiob");
		}
	}

	if (table_do_modify(oh, &xi) != 0)
		err(EX_OSERR, "Table modification failed");
}
Exemple #3
0
static void
ipfw_nat64lsn_stats_handler(const char *name, uint8_t set, int ac, char *av[])
{
	int tcmd;

	if (ac == 0) {
		nat64lsn_stats(name, set);
		return;
	}
	NEED1("nat64lsn stats needs command");
	tcmd = get_token(nat64statscmds, *av, "nat64lsn stats command");
	switch (tcmd) {
	case TOK_RESET:
		nat64lsn_reset_stats(name, set);
	}
}
Exemple #4
0
static void
ipfw_nat64lsn_list_handler(const char *name, uint8_t set, int ac, char *av[])
{
	int tcmd;

	if (ac == 0) {
		nat64lsn_foreach(nat64lsn_show_cb, name, set, 1);
		return;
	}
	NEED1("nat64lsn list needs command");
	tcmd = get_token(nat64listcmds, *av, "nat64lsn list command");
	switch (tcmd) {
	case TOK_STATES:
		nat64lsn_foreach(nat64lsn_states_cb, name, set, 1);
		break;
	case TOK_CONFIG:
		nat64lsn_foreach(nat64lsn_show_cb, name, set, 1);
	}
}
Exemple #5
0
/*
 * Called with the arguments, including program name because getopt
 * wants it to be present.
 * Returns 0 if successful, 1 if empty command, errx() in case of errors.
 * First thing we do is process parameters creating an argv[] array
 * which includes the program name and a NULL entry at the end.
 * If we are called with a single string, we split it on whitespace.
 * Also, arguments with a trailing ',' are joined to the next one.
 * The pointers (av[]) and data are in a single chunk of memory.
 * av[0] points to the original program name, all other entries
 * point into the allocated chunk.
 */
static int
ipfw_main(int oldac, char **oldav)
{
	int ch, ac;
	const char *errstr;
	char **av, **save_av;
	int do_acct = 0;		/* Show packet/byte count */
	int try_next = 0;		/* set if pipe cmd not found */
	int av_size;			/* compute the av size */
	char *av_p;			/* used to build the av list */

#define WHITESP		" \t\f\v\n\r"
	if (oldac < 2)
		return 1;	/* need at least one argument */

	if (oldac == 2) {
		/*
		 * If we are called with one argument, try to split it into
		 * words for subsequent parsing. Spaces after a ',' are
		 * removed by copying the string in-place.
		 */
		char *arg = oldav[1];	/* The string is the first arg. */
		int l = strlen(arg);
		int copy = 0;		/* 1 if we need to copy, 0 otherwise */
		int i, j;

		for (i = j = 0; i < l; i++) {
			if (arg[i] == '#')	/* comment marker */
				break;
			if (copy) {
				arg[j++] = arg[i];
				copy = !strchr("," WHITESP, arg[i]);
			} else {
				copy = !strchr(WHITESP, arg[i]);
				if (copy)
					arg[j++] = arg[i];
			}
		}
		if (!copy && j > 0)	/* last char was a 'blank', remove it */
			j--;
		l = j;			/* the new argument length */
		arg[j++] = '\0';
		if (l == 0)		/* empty string! */
			return 1;

		/*
		 * First, count number of arguments. Because of the previous
		 * processing, this is just the number of blanks plus 1.
		 */
		for (i = 0, ac = 1; i < l; i++)
			if (strchr(WHITESP, arg[i]) != NULL)
				ac++;

		/*
		 * Allocate the argument list structure as a single block
		 * of memory, containing pointers and the argument
		 * strings. We include one entry for the program name
		 * because getopt expects it, and a NULL at the end
		 * to simplify further parsing.
		 */
		ac++;		/* add 1 for the program name */
		av_size = (ac+1) * sizeof(char *) + l + 1;
		av = safe_calloc(av_size, 1);

		/*
		 * Init the argument pointer to the end of the array
		 * and copy arguments from arg[] to av[]. For each one,
		 * j is the initial character, i is the one past the end.
		 */
		av_p = (char *)&av[ac+1];
		for (ac = 1, i = j = 0; i < l; i++) {
			if (strchr(WHITESP, arg[i]) != NULL || i == l-1) {
				if (i == l-1)
					i++;
				bcopy(arg+j, av_p, i-j);
				av[ac] = av_p;
				av_p += i-j;	/* the length of the string */
				*av_p++ = '\0';
				ac++;
				j = i + 1;
			}
		}
	} else {
		/*
		 * If an argument ends with ',' join with the next one.
		 */
		int first, i, l=0;

		/*
		 * Allocate the argument list structure as a single block
		 * of memory, containing both pointers and the argument
		 * strings. We include some space for the program name
		 * because getopt expects it.
		 * We add an extra pointer to the end of the array,
		 * to make simpler further parsing.
		 */
		for (i=0; i<oldac; i++)
			l += strlen(oldav[i]);

		av_size = (oldac+1) * sizeof(char *) + l + oldac;
		av = safe_calloc(av_size, 1);

		/*
		 * Init the argument pointer to the end of the array
		 * and copy arguments from arg[] to av[]
		 */
		av_p = (char *)&av[oldac+1];
		for (first = i = ac = 1, l = 0; i < oldac; i++) {
			char *arg = oldav[i];
			int k = strlen(arg);

			l += k;
			if (arg[k-1] != ',' || i == oldac-1) {
				/* Time to copy. */
				av[ac] = av_p;
				for (l=0; first <= i; first++) {
					strcat(av_p, oldav[first]);
					av_p += strlen(oldav[first]);
				}
				*av_p++ = '\0';
				ac++;
				l = 0;
				first = i+1;
			}
		}
	}

	/*
	 * set the progname pointer to the original string
	 * and terminate the array with null
	 */
	av[0] = oldav[0];
	av[ac] = NULL;

	/* Set the force flag for non-interactive processes */
	if (!co.do_force)
		co.do_force = !isatty(STDIN_FILENO);

#ifdef EMULATE_SYSCTL /* sysctl emulation */
	if ( ac >= 2 && !strcmp(av[1], "sysctl")) {
		char *s;
		int i;

		if (ac != 3) {
			printf(	"sysctl emulation usage:\n"
				"	ipfw sysctl name[=value]\n"
				"	ipfw sysctl -a\n");
			return 0;
		}
		s = strchr(av[2], '=');
		if (s == NULL) {
			s = !strcmp(av[2], "-a") ? NULL : av[2];
			sysctlbyname(s, NULL, NULL, NULL, 0);
		} else {	/* ipfw sysctl x.y.z=value */
			/* assume an INT value, will extend later */
			if (s[1] == '\0') {
				printf("ipfw sysctl: missing value\n\n");
				return 0;
			}
			*s = '\0';
			i = strtol(s+1, NULL, 0);
			sysctlbyname(av[2], NULL, NULL, &i, sizeof(int));
		}
		return 0;
	}
#endif

	/* Save arguments for final freeing of memory. */
	save_av = av;

	optind = optreset = 1;	/* restart getopt() */
	while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtv")) != -1)
		switch (ch) {
		case 'a':
			do_acct = 1;
			break;

		case 'b':
			co.comment_only = 1;
			co.do_compact = 1;
			break;

		case 'c':
			co.do_compact = 1;
			break;

		case 'd':
			co.do_dynamic = 1;
			break;

		case 'e':
			co.do_expired = 1;
			break;

		case 'f':
			co.do_force = 1;
			break;

		case 'h': /* help */
			free(save_av);
			help();
			break;	/* NOTREACHED */

		case 'i':
			co.do_value_as_ip = 1;
			break;

		case 'n':
			co.test_only = 1;
			break;

		case 'N':
			co.do_resolv = 1;
			break;

		case 'p':
			errx(EX_USAGE, "An absolute pathname must be used "
			    "with -p option.");
			/* NOTREACHED */

		case 'q':
			co.do_quiet = 1;
			break;

		case 's': /* sort */
			co.do_sort = atoi(optarg);
			break;

		case 'S':
			co.show_sets = 1;
			break;

		case 't':
			co.do_time = 1;
			break;

		case 'T':
			co.do_time = 2;	/* numeric timestamp */
			break;

		case 'v': /* verbose */
			co.verbose = 1;
			break;

		default:
			free(save_av);
			return 1;
		}

	ac -= optind;
	av += optind;
	NEED1("bad arguments, for usage summary ``ipfw''");

	/*
	 * An undocumented behaviour of ipfw1 was to allow rule numbers first,
	 * e.g. "100 add allow ..." instead of "add 100 allow ...".
	 * In case, swap first and second argument to get the normal form.
	 */
	if (ac > 1 && isdigit(*av[0])) {
		char *p = av[0];

		av[0] = av[1];
		av[1] = p;
	}

	/*
	 * Optional: pipe, queue or nat.
	 */
	co.do_nat = 0;
	co.do_pipe = 0;
	co.use_set = 0;
	if (!strncmp(*av, "nat", strlen(*av)))
 		co.do_nat = 1;
 	else if (!strncmp(*av, "pipe", strlen(*av)))
		co.do_pipe = 1;
	else if (_substrcmp(*av, "queue") == 0)
		co.do_pipe = 2;
	else if (_substrcmp(*av, "flowset") == 0)
		co.do_pipe = 2;
	else if (_substrcmp(*av, "sched") == 0)
		co.do_pipe = 3;
	else if (!strncmp(*av, "set", strlen(*av))) {
		if (ac > 1 && isdigit(av[1][0])) {
			co.use_set = strtonum(av[1], 0, resvd_set_number,
					&errstr);
			if (errstr)
				errx(EX_DATAERR,
				    "invalid set number %s\n", av[1]);
			ac -= 2; av += 2; co.use_set++;
		}
	}

	if (co.do_pipe || co.do_nat) {
		ac--;
		av++;
	}
	NEED1("missing command");

	/*
	 * For pipes, queues and nats we normally say 'nat|pipe NN config'
	 * but the code is easier to parse as 'nat|pipe config NN'
	 * so we swap the two arguments.
	 */
	if ((co.do_pipe || co.do_nat) && ac > 1 && isdigit(*av[0])) {
		char *p = av[0];

		av[0] = av[1];
		av[1] = p;
	}

	if (co.use_set == 0) {
		if (_substrcmp(*av, "add") == 0)
			ipfw_add(av);
		else if (co.do_nat && _substrcmp(*av, "show") == 0)
 			ipfw_show_nat(ac, av);
		else if (co.do_pipe && _substrcmp(*av, "config") == 0)
			ipfw_config_pipe(ac, av);
		else if (co.do_nat && _substrcmp(*av, "config") == 0)
 			ipfw_config_nat(ac, av);
		else if (_substrcmp(*av, "set") == 0)
			ipfw_sets_handler(av);
		else if (_substrcmp(*av, "table") == 0)
			ipfw_table_handler(ac, av);
		else if (_substrcmp(*av, "enable") == 0)
			ipfw_sysctl_handler(av, 1);
		else if (_substrcmp(*av, "disable") == 0)
			ipfw_sysctl_handler(av, 0);
		else
			try_next = 1;
	}

	if (co.use_set || try_next) {
		if (_substrcmp(*av, "delete") == 0)
			ipfw_delete(av);
		else if (!strncmp(*av, "nptv6", strlen(*av)))
			ipfw_nptv6_handler(ac, av);
		else if (_substrcmp(*av, "flush") == 0)
			ipfw_flush(co.do_force);
		else if (_substrcmp(*av, "zero") == 0)
			ipfw_zero(ac, av, 0 /* IP_FW_ZERO */);
		else if (_substrcmp(*av, "resetlog") == 0)
			ipfw_zero(ac, av, 1 /* IP_FW_RESETLOG */);
		else if (_substrcmp(*av, "print") == 0 ||
			 _substrcmp(*av, "list") == 0)
			ipfw_list(ac, av, do_acct);
		else if (_substrcmp(*av, "show") == 0)
			ipfw_list(ac, av, 1 /* show counters */);
		else if (_substrcmp(*av, "table") == 0)
			ipfw_table_handler(ac, av);
		else if (_substrcmp(*av, "internal") == 0)
			ipfw_internal_handler(ac, av);
		else
			errx(EX_USAGE, "bad command `%s'", *av);
	}

	/* Free memory allocated in the argument parsing. */
	free(save_av);
	return 0;
}
Exemple #6
0
/*
 * configuration of pipes, schedulers, flowsets.
 * When we configure a new scheduler, an empty pipe is created, so:
 * 
 * do_pipe = 1 -> "pipe N config ..." only for backward compatibility
 *	sched N+Delta type fifo sched_mask ...
 *	pipe N+Delta <parameters>
 *	flowset N+Delta pipe N+Delta (no parameters)
 *	sched N type wf2q+ sched_mask ...
 *	pipe N <parameters>
 *
 * do_pipe = 2 -> flowset N config
 *	flowset N parameters
 *
 * do_pipe = 3 -> sched N config
 *	sched N parameters (default no pipe)
 *	optional Pipe N config ...
 * pipe ==>
 */
int
ipfw_config_pipe(int ac, char **av, int do_pipe)
{
	int i, j;
	char *end;
	void *par = NULL;
	struct dn_id *buf, *base;
	struct dn_sch *sch = NULL;
	struct dn_link *p = NULL;
	struct dn_fs *fs = NULL;
	struct ipfw_flow_id *mask = NULL;
	int lmax;
	uint32_t _foo = 0, *flags = &_foo , *buckets = &_foo;

	/*
	 * allocate space for 1 header,
	 * 1 scheduler, 1 link, 1 flowset, 1 profile
	 */
	lmax = sizeof(struct dn_id);	/* command header */
	lmax += sizeof(struct dn_sch) + sizeof(struct dn_link) +
		sizeof(struct dn_fs) + sizeof(struct dn_profile);

	av++; ac--;
	/* Pipe number */
	if (ac && isdigit(**av)) {
		i = atoi(*av); av++; ac--;
	} else
		i = -1;
	if (i <= 0) {
		php_printf("need a pipe/flowset/sched number");
		return (-1);
	}
	base = buf = calloc(1, lmax);
	if (base == NULL)
		return (-1);
	/* all commands start with a 'CONFIGURE' and a version */
	o_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG);
	base->id = DN_API_VERSION;

	switch (do_pipe) {
	case 1: /* "pipe N config ..." */
		/* Allocate space for the WF2Q+ scheduler, its link
		 * and the FIFO flowset. Set the number, but leave
		 * the scheduler subtype and other parameters to 0
		 * so the kernel will use appropriate defaults.
		 * XXX todo: add a flag to record if a parameter
		 * is actually configured.
		 * If we do a 'pipe config' mask -> sched_mask.
		 * The FIFO scheduler and link are derived from the
		 * WF2Q+ one in the kernel.
		 */
		sch = o_next(&buf, sizeof(*sch), DN_SCH);
		p = o_next(&buf, sizeof(*p), DN_LINK);
		fs = o_next(&buf, sizeof(*fs), DN_FS);

		sch->sched_nr = i;
		sch->oid.subtype = 0;	/* defaults to WF2Q+ */
		mask = &sch->sched_mask;
		flags = &sch->flags;
		buckets = &sch->buckets;
		*flags |= DN_PIPE_CMD;

		p->link_nr = i;

		/* This flowset is only for the FIFO scheduler */
		fs->fs_nr = i + 2*DN_MAX_ID;
		fs->sched_nr = i + DN_MAX_ID;
		break;

	case 2: /* "queue N config ... " */
		fs = o_next(&buf, sizeof(*fs), DN_FS);
		fs->fs_nr = i;
		mask = &fs->flow_mask;
		flags = &fs->flags;
		buckets = &fs->buckets;
		break;

	case 3: /* "sched N config ..." */
		sch = o_next(&buf, sizeof(*sch), DN_SCH);
		fs = o_next(&buf, sizeof(*fs), DN_FS);
		sch->sched_nr = i;
		mask = &sch->sched_mask;
		flags = &sch->flags;
		buckets = &sch->buckets;
		/* fs is used only with !MULTIQUEUE schedulers */
		fs->fs_nr = i + DN_MAX_ID;
		fs->sched_nr = i;
		break;
	}
	/* set to -1 those fields for which we want to reuse existing
	 * values from the kernel.
	 * Also, *_nr and subtype = 0 mean reuse the value from the kernel.
	 * XXX todo: support reuse of the mask.
	 */
	if (p)
		p->bandwidth = -1;
	for (j = 0; j < sizeof(fs->par)/sizeof(fs->par[0]); j++)
		fs->par[j] = -1;
	while (ac > 0) {
		double d;
		int tok = match_token(dummynet_params, *av);
		ac--; av++;

		switch(tok) {
		case TOK_NOERROR:
			NEED(fs, "noerror is only for pipes");
			fs->flags |= DN_NOERROR;
			break;

		case TOK_PLR:
			NEED(fs, "plr is only for pipes");
			NEED1("plr needs argument 0..1\n");
			d = strtod(av[0], NULL);
			if (d > 1)
				d = 1;
			else if (d < 0)
				d = 0;
			fs->plr = (int)(d*0x7fffffff);
			ac--; av++;
			break;

		case TOK_QUEUE:
			NEED(fs, "queue is only for pipes or flowsets");
			NEED1("queue needs queue size\n");
			end = NULL;
			fs->qsize = strtoul(av[0], &end, 0);
			if (*end == 'K' || *end == 'k') {
				fs->flags |= DN_QSIZE_BYTES;
				fs->qsize *= 1024;
			} else if (*end == 'B' ||
			    _substrcmp2(end, "by", "bytes") == 0) {
				fs->flags |= DN_QSIZE_BYTES;
			}
			ac--; av++;
			break;

		case TOK_BUCKETS:
			NEED(fs, "buckets is only for pipes or flowsets");
			NEED1("buckets needs argument\n");
			*buckets = strtoul(av[0], NULL, 0);
			ac--; av++;
			break;

		case TOK_FLOW_MASK:
		case TOK_SCHED_MASK:
		case TOK_MASK:
			NEED(mask, "tok_mask");
			NEED1("mask needs mask specifier\n");
			/*
			 * per-flow queue, mask is dst_ip, dst_port,
			 * src_ip, src_port, proto measured in bits
			 */
			par = NULL;

			bzero(mask, sizeof(*mask));
			end = NULL;

			while (ac >= 1) {
			    uint32_t *p32 = NULL;
			    uint16_t *p16 = NULL;
			    uint32_t *p20 = NULL;
			    struct in6_addr *pa6 = NULL;
			    uint32_t a;

			    tok = match_token(dummynet_params, *av);
			    ac--; av++;
			    switch(tok) {
			    case TOK_ALL:
				    /*
				     * special case, all bits significant
				     * except 'extra' (the queue number)
				     */
				    mask->dst_ip = ~0;
				    mask->src_ip = ~0;
				    mask->dst_port = ~0;
				    mask->src_port = ~0;
				    mask->proto = ~0;
				    n2mask(&mask->dst_ip6, 128);
				    n2mask(&mask->src_ip6, 128);
				    mask->flow_id6 = ~0;
				    *flags |= DN_HAVE_MASK;
				    goto end_mask;

			    case TOK_QUEUE:
				    mask->extra = ~0;
				    *flags |= DN_HAVE_MASK;
				    goto end_mask;

			    case TOK_DSTIP:
				    mask->addr_type = 4;
				    p32 = &mask->dst_ip;
				    break;

			    case TOK_SRCIP:
				    mask->addr_type = 4;
				    p32 = &mask->src_ip;
				    break;

			    case TOK_DSTIP6:
				    mask->addr_type = 6;
				    pa6 = &mask->dst_ip6;
				    break;
			    
			    case TOK_SRCIP6:
				    mask->addr_type = 6;
				    pa6 = &mask->src_ip6;
				    break;

			    case TOK_FLOWID:
				    mask->addr_type = 6;
				    p20 = &mask->flow_id6;
				    break;

			    case TOK_DSTPORT:
				    p16 = &mask->dst_port;
				    break;

			    case TOK_SRCPORT:
				    p16 = &mask->src_port;
				    break;

			    case TOK_PROTO:
				    break;

			    default:
				    ac++; av--; /* backtrack */
				    goto end_mask;
			    }
			    if (ac < 1) {
				    php_printf("mask: value missing");
				    goto end;
			    }
			    if (*av[0] == '/') {
				    a = strtoul(av[0]+1, &end, 0);
				    if (pa6 == NULL)
					    a = (a == 32) ? ~0 : (1 << a) - 1;
			    } else
				    a = strtoul(av[0], &end, 0);
			    if (p32 != NULL)
				    *p32 = a;
			    else if (p16 != NULL) {
				    if (a > 0xFFFF) {
					php_printf("port mask must be 16 bit");
					goto end;
				    }
				    *p16 = (uint16_t)a;
			    } else if (p20 != NULL) {
				    if (a > 0xfffff) {
					 php_printf("flow_id mask must be 20 bit");
					 goto end;
				    }
				    *p20 = (uint32_t)a;
			    } else if (pa6 != NULL) {
				    if (a > 128) {
					    php_printf("in6addr invalid mask len");
					   goto end;
				    }
				    else
					n2mask(pa6, a);
			    } else {
				    if (a > 0xFF) {
					php_printf("proto mask must be 8 bit");
					goto end;
				    }
				    mask->proto = (uint8_t)a;
			    }
			    if (a != 0)
				    *flags |= DN_HAVE_MASK;
			    ac--; av++;
			} /* end while, config masks */
end_mask:
			break;

		case TOK_DROPTAIL:
			NEED(fs, "droptail is only for flowsets");
			fs->flags &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
			break;

		case TOK_BW:
			NEED(p, "bw is only for links");
			NEED1("bw needs bandwidth or interface\n");
			if (read_bandwidth(av[0], &p->bandwidth, NULL, 0) < 0)
				goto end;
			ac--; av++;
			break;

		case TOK_DELAY:
			NEED(p, "delay is only for links");
			NEED1("delay needs argument 0..10000ms\n");
			p->delay = strtoul(av[0], NULL, 0);
			ac--; av++;
			break;

		case TOK_TYPE: {
			int l;
			NEED(sch, "type is only for schedulers");
			NEED1("type needs a string");
			l = strlen(av[0]);
			if (l == 0 || l > 15) {
				php_printf("type %s too long\n", av[0]);
				goto end;
			}
			strcpy(sch->name, av[0]);
			sch->oid.subtype = 0; /* use string */
			ac--; av++;
			break;
		    }

		case TOK_WEIGHT:
			NEED(fs, "weight is only for flowsets");
			NEED1("weight needs argument\n");
			fs->par[0] = strtol(av[0], &end, 0);
			ac--; av++;
			break;

		case TOK_LMAX:
			NEED(fs, "lmax is only for flowsets");
			NEED1("lmax needs argument\n");
			fs->par[1] = strtol(av[0], &end, 0);
			ac--; av++;
			break;

		case TOK_PRI:
			NEED(fs, "priority is only for flowsets");
			NEED1("priority needs argument\n");
			fs->par[2] = strtol(av[0], &end, 0);
			ac--; av++;
			break;

		case TOK_SCHED:
		case TOK_PIPE:
			NEED(fs, "pipe/sched");
			NEED1("pipe/link/sched needs number\n");
			fs->sched_nr = strtoul(av[0], &end, 0);
			ac--; av++;
			break;

		default:
			php_printf("unrecognised option ``%s''", av[-1]);
			goto end;
		}
	}

	/* check validity of parameters */
	if (p) {
		if (p->delay > 10000) {
			php_printf("delay must be < 10000");
			goto end;
		}
		if (p->bandwidth == -1)
			p->bandwidth = 0;
	}
	if (fs) {
		/* XXX accept a 0 scheduler to keep the default */
	    if (fs->flags & DN_QSIZE_BYTES) {
		size_t len;
		long limit;

		len = sizeof(limit);
		if (sysctlbyname("net.inet.ip.dummynet.pipe_byte_limit",
			&limit, &len, NULL, 0) == -1)
			limit = 1024*1024;
		if (fs->qsize > limit) {
			php_printf("queue size must be < %ldB", limit);
			goto end;
		}
	    } else {
		size_t len;
		long limit;

		len = sizeof(limit);
		if (sysctlbyname("net.inet.ip.dummynet.pipe_slot_limit",
			&limit, &len, NULL, 0) == -1)
			limit = 100;
		if (fs->qsize > limit) {
			php_printf("2 <= queue size <= %ld", limit);
			goto end;
		}
	    }

	    if (fs->flags & DN_IS_RED) {
		size_t len;
		int lookup_depth, avg_pkt_size;
		double w_q;

		if (fs->min_th >= fs->max_th) {
		    php_printf("min_th %d must be < than max_th %d",
			fs->min_th, fs->max_th);
			goto end;
		}
		if (fs->max_th == 0) {
			php_printf("max_th must be > 0");
			goto end;
		}

		len = sizeof(int);
		if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
			&lookup_depth, &len, NULL, 0) == -1)
			lookup_depth = 256;
		if (lookup_depth == 0) {
		    php_printf("net.inet.ip.dummynet.red_lookup_depth"
			" must be greater than zero");
			goto end;
		}

		len = sizeof(int);
		if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
			&avg_pkt_size, &len, NULL, 0) == -1)
			avg_pkt_size = 512;

		if (avg_pkt_size == 0) {
			    php_printf("net.inet.ip.dummynet.red_avg_pkt_size must"
			    " be greater than zero");
			goto end;
		}

		/*
		 * Ticks needed for sending a medium-sized packet.
		 * Unfortunately, when we are configuring a WF2Q+ queue, we
		 * do not have bandwidth information, because that is stored
		 * in the parent pipe, and also we have multiple queues
		 * competing for it. So we set s=0, which is not very
		 * correct. But on the other hand, why do we want RED with
		 * WF2Q+ ?
		 */
#if 0
		if (p.bandwidth==0) /* this is a WF2Q+ queue */
			s = 0;
		else
			s = (double)ck.hz * avg_pkt_size * 8 / p.bandwidth;
#endif
		/*
		 * max idle time (in ticks) before avg queue size becomes 0.
		 * NOTA:  (3/w_q) is approx the value x so that
		 * (1-w_q)^x < 10^-3.
		 */
		w_q = ((double)fs->w_q) / (1 << SCALE_RED);
#if 0 // go in kernel
		idle = s * 3. / w_q;
		fs->lookup_step = (int)idle / lookup_depth;
		if (!fs->lookup_step)
			fs->lookup_step = 1;
		weight = 1 - w_q;
		for (t = fs->lookup_step; t > 1; --t)
			weight *= 1 - w_q;
		fs->lookup_weight = (int)(weight * (1 << SCALE_RED));
#endif
	    }
	}

	i = do_cmd(IP_DUMMYNET3, base, (char *)buf - (char *)base);

	if (i)
		php_printf("setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");

	free(base);

	return (0); /* XXX: i? */
end:
	if (base != NULL)
		free(base);
	return (-1);
}
Exemple #7
0
static void
nptv6_create(const char *name, uint8_t set, int ac, char *av[])
{
	char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nptv6_cfg)];
	struct in6_addr mask;
	ipfw_nptv6_cfg *cfg;
	ipfw_obj_lheader *olh;
	int tcmd, flags, plen;
	char *p = "\0";

	plen = 0;
	memset(buf, 0, sizeof(buf));
	olh = (ipfw_obj_lheader *)buf;
	cfg = (ipfw_nptv6_cfg *)(olh + 1);
	cfg->set = set;
	flags = 0;
	while (ac > 0) {
		tcmd = get_token(nptv6newcmds, *av, "option");
		ac--; av++;

		switch (tcmd) {
		case TOK_INTPREFIX:
			NEED1("IPv6 prefix required");
			nptv6_parse_prefix(*av, &cfg->internal, &plen);
			flags |= NPTV6_HAS_INTPREFIX;
			if (plen > 0)
				goto check_prefix;
			ac--; av++;
			break;
		case TOK_EXTPREFIX:
			if (flags & NPTV6_HAS_EXTPREFIX)
				errx(EX_USAGE,
				    "Only one ext_prefix or ext_if allowed");
			NEED1("IPv6 prefix required");
			nptv6_parse_prefix(*av, &cfg->external, &plen);
			flags |= NPTV6_HAS_EXTPREFIX;
			if (plen > 0)
				goto check_prefix;
			ac--; av++;
			break;
		case TOK_EXTIF:
			if (flags & NPTV6_HAS_EXTPREFIX)
				errx(EX_USAGE,
				    "Only one ext_prefix or ext_if allowed");
			NEED1("Interface name required");
			if (strlen(*av) >= sizeof(cfg->if_name))
				errx(EX_USAGE, "Invalid interface name");
			flags |= NPTV6_HAS_EXTPREFIX;
			cfg->flags |= NPTV6_DYNAMIC_PREFIX;
			strncpy(cfg->if_name, *av, sizeof(cfg->if_name));
			ac--; av++;
			break;
		case TOK_PREFIXLEN:
			NEED1("IPv6 prefix length required");
			plen = strtol(*av, &p, 10);
check_prefix:
			if (*p != '\0' || plen < 8 || plen > 64)
				errx(EX_USAGE, "wrong prefix length: %s", *av);
			/* RFC 6296 Sec. 3.1 */
			if (cfg->plen > 0 && cfg->plen != plen) {
				warnx("Prefix length mismatch (%d vs %d).  "
				    "It was extended up to %d",
				    cfg->plen, plen, MAX(plen, cfg->plen));
				plen = MAX(plen, cfg->plen);
			}
			cfg->plen = plen;
			flags |= NPTV6_HAS_PREFIXLEN;
			ac--; av++;
			break;
		}
	}

	/* Check validness */
	if ((flags & NPTV6_HAS_INTPREFIX) != NPTV6_HAS_INTPREFIX)
		errx(EX_USAGE, "int_prefix required");
	if ((flags & NPTV6_HAS_EXTPREFIX) != NPTV6_HAS_EXTPREFIX)
		errx(EX_USAGE, "ext_prefix or ext_if required");
	if ((flags & NPTV6_HAS_PREFIXLEN) != NPTV6_HAS_PREFIXLEN)
		errx(EX_USAGE, "prefixlen required");

	n2mask(&mask, cfg->plen);
	APPLY_MASK(&cfg->internal, &mask);
	if ((cfg->flags & NPTV6_DYNAMIC_PREFIX) == 0)
		APPLY_MASK(&cfg->external, &mask);

	olh->count = 1;
	olh->objsize = sizeof(*cfg);
	olh->size = sizeof(buf);
	strlcpy(cfg->name, name, sizeof(cfg->name));
	if (do_set3(IP_FW_NPTV6_CREATE, &olh->opheader, sizeof(buf)) != 0)
		err(EX_OSERR, "nptv6 instance creation failed");
}
/*
 * Configures existing nat64clat instance
 * ipfw nat64clat <NAME> config <options>
 * Request: [ ipfw_obj_header ipfw_nat64clat_cfg ]
 */
static void
nat64clat_config(const char *name, uint8_t set, int ac, char **av)
{
	char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64clat_cfg)];
	ipfw_nat64clat_cfg *cfg;
	ipfw_obj_header *oh;
	char *opt;
	char *p;
	size_t sz;
	int tcmd;
	struct in6_addr prefix;
	uint8_t plen;

	if (ac == 0)
		errx(EX_USAGE, "config options required");
	memset(&buf, 0, sizeof(buf));
	oh = (ipfw_obj_header *)buf;
	cfg = (ipfw_nat64clat_cfg *)(oh + 1);
	sz = sizeof(buf);

	nat64clat_fill_ntlv(&oh->ntlv, name, set);
	if (do_get3(IP_FW_NAT64CLAT_CONFIG, &oh->opheader, &sz) != 0)
		err(EX_OSERR, "failed to get config for instance %s", name);

	while (ac > 0) {
		tcmd = get_token(nat64newcmds, *av, "option");
		opt = *av;
		ac--; av++;

		switch (tcmd) {
		case TOK_PLAT_PREFIX:
		case TOK_CLAT_PREFIX:
			if (tcmd == TOK_PLAT_PREFIX) {
				NEED1("IPv6 plat_prefix required");
			} else {
				NEED1("IPv6 clat_prefix required");
			}

			if ((p = strchr(*av, '/')) != NULL)
				*p++ = '\0';
			if (inet_pton(AF_INET6, *av, &prefix) != 1)
				errx(EX_USAGE,
				    "Bad prefix: %s", *av);
			plen = strtol(p, NULL, 10);
			if (ipfw_check_nat64prefix(&prefix, plen) != 0)
				errx(EX_USAGE,
				    "Bad prefix length: %s", p);
			if (tcmd == TOK_PLAT_PREFIX) {
				cfg->plat_prefix = prefix;
				cfg->plat_plen = plen;
			} else {
				cfg->clat_prefix = prefix;
				cfg->clat_plen = plen;
			}
			ac--; av++;
			break;
		case TOK_LOG:
			cfg->flags |= NAT64_LOG;
			break;
		case TOK_LOGOFF:
			cfg->flags &= ~NAT64_LOG;
			break;
		case TOK_PRIVATE:
			cfg->flags |= NAT64_ALLOW_PRIVATE;
			break;
		case TOK_PRIVATEOFF:
			cfg->flags &= ~NAT64_ALLOW_PRIVATE;
			break;
		default:
			errx(EX_USAGE, "Can't change %s option", opt);
		}
	}

	if (do_set3(IP_FW_NAT64CLAT_CONFIG, &oh->opheader, sizeof(buf)) != 0)
		err(EX_OSERR, "nat64clat instance configuration failed");
}
static void
nat64clat_create(const char *name, uint8_t set, int ac, char *av[])
{
	char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nat64clat_cfg)];
	ipfw_nat64clat_cfg *cfg;
	ipfw_obj_lheader *olh;
	int tcmd, flags;
	char *p;
	struct in6_addr prefix;
	uint8_t plen;

	memset(buf, 0, sizeof(buf));
	olh = (ipfw_obj_lheader *)buf;
	cfg = (ipfw_nat64clat_cfg *)(olh + 1);

	/* Some reasonable defaults */
	inet_pton(AF_INET6, "64:ff9b::", &cfg->plat_prefix);
	cfg->plat_plen = 96;
	cfg->set = set;
	flags = NAT64CLAT_HAS_PLAT_PREFIX;
	while (ac > 0) {
		tcmd = get_token(nat64newcmds, *av, "option");
		ac--; av++;

		switch (tcmd) {
		case TOK_PLAT_PREFIX:
		case TOK_CLAT_PREFIX:
			if (tcmd == TOK_PLAT_PREFIX) {
				NEED1("IPv6 plat_prefix required");
			} else {
				NEED1("IPv6 clat_prefix required");
			}

			if ((p = strchr(*av, '/')) != NULL)
				*p++ = '\0';
			if (inet_pton(AF_INET6, *av, &prefix) != 1)
				errx(EX_USAGE,
				    "Bad prefix: %s", *av);
			plen = strtol(p, NULL, 10);
			if (ipfw_check_nat64prefix(&prefix, plen) != 0)
				errx(EX_USAGE,
				    "Bad prefix length: %s", p);
			if (tcmd == TOK_PLAT_PREFIX) {
				flags |= NAT64CLAT_HAS_PLAT_PREFIX;
				cfg->plat_prefix = prefix;
				cfg->plat_plen = plen;
			} else {
				flags |= NAT64CLAT_HAS_CLAT_PREFIX;
				cfg->clat_prefix = prefix;
				cfg->clat_plen = plen;
			}
			ac--; av++;
			break;
		case TOK_LOG:
			cfg->flags |= NAT64_LOG;
			break;
		case TOK_LOGOFF:
			cfg->flags &= ~NAT64_LOG;
			break;
		case TOK_PRIVATE:
			cfg->flags |= NAT64_ALLOW_PRIVATE;
			break;
		case TOK_PRIVATEOFF:
			cfg->flags &= ~NAT64_ALLOW_PRIVATE;
			break;
		}
	}

	/* Check validness */
	if ((flags & NAT64CLAT_HAS_PLAT_PREFIX) != NAT64CLAT_HAS_PLAT_PREFIX)
		errx(EX_USAGE, "plat_prefix required");
	if ((flags & NAT64CLAT_HAS_CLAT_PREFIX) != NAT64CLAT_HAS_CLAT_PREFIX)
		errx(EX_USAGE, "clat_prefix required");

	olh->count = 1;
	olh->objsize = sizeof(*cfg);
	olh->size = sizeof(buf);
	strlcpy(cfg->name, name, sizeof(cfg->name));
	if (do_set3(IP_FW_NAT64CLAT_CREATE, &olh->opheader, sizeof(buf)) != 0)
		err(EX_OSERR, "nat64clat instance creation failed");
}
Exemple #10
0
/*
 * Creates new table
 *
 * ipfw table NAME create [ type { addr | iface | number | flow } ]
 *     [ algo algoname ]
 */
static void
table_create(ipfw_obj_header *oh, int ac, char *av[])
{
	ipfw_xtable_info xi;
	int error, tcmd, val;
	uint32_t fset, fclear;
	char *e, *p;
	char tbuf[128];

	memset(&xi, 0, sizeof(xi));

	while (ac > 0) {
		tcmd = get_token(tablenewcmds, *av, "option");
		ac--; av++;

		switch (tcmd) {
		case TOK_LIMIT:
			NEED1("limit value required");
			xi.limit = strtol(*av, NULL, 10);
			ac--; av++;
			break;
		case TOK_TYPE:
			NEED1("table type required");
			/* Type may have suboptions after ':' */
			if ((p = strchr(*av, ':')) != NULL)
				*p++ = '\0';
			val = match_token(tabletypes, *av);
			if (val == -1) {
				concat_tokens(tbuf, sizeof(tbuf), tabletypes,
				    ", ");
				errx(EX_USAGE,
				    "Unknown tabletype: %s. Supported: %s",
				    *av, tbuf);
			}
			xi.type = val;
			if (p != NULL) {
				error = table_parse_type(val, p, &xi.tflags);
				if (error != 0)
					errx(EX_USAGE,
					    "Unsupported suboptions: %s", p);
			}
			ac--; av++;
			break;
		case TOK_VALTYPE:
			NEED1("table value type required");
			fset = fclear = 0;
			val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear);
			if (val != -1) {
				xi.vmask = fset;
				ac--; av++;
				break;
			}
			concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
			errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
			    e, tbuf);
			break;
		case TOK_ALGO:
			NEED1("table algorithm name required");
			if (strlen(*av) > sizeof(xi.algoname))
				errx(EX_USAGE, "algorithm name too long");
			strlcpy(xi.algoname, *av, sizeof(xi.algoname));
			ac--; av++;
			break;
		case TOK_LOCK:
			xi.flags |= IPFW_TGFLAGS_LOCKED;
			break;
		}
	}

	/* Set some defaults to preserve compatibility. */
	if (xi.algoname[0] == '\0' && xi.type == 0)
		xi.type = IPFW_TABLE_ADDR;
	if (xi.vmask == 0)
		xi.vmask = IPFW_VTYPE_LEGACY;

	if ((error = table_do_create(oh, &xi)) != 0)
		err(EX_OSERR, "Table creation failed");
}
Exemple #11
0
/*
 * This one handles all table-related commands
 * 	ipfw table NAME create ...
 * 	ipfw table NAME modify ...
 * 	ipfw table NAME destroy
 * 	ipfw table NAME swap NAME
 * 	ipfw table NAME lock
 * 	ipfw table NAME unlock
 * 	ipfw table NAME add addr[/masklen] [value] 
 * 	ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] ..
 * 	ipfw table NAME delete addr[/masklen] [addr[/masklen]] ..
 * 	ipfw table NAME lookup addr
 * 	ipfw table {NAME | all} flush
 * 	ipfw table {NAME | all} list
 * 	ipfw table {NAME | all} info
 * 	ipfw table {NAME | all} detail
 */
void
ipfw_table_handler(int ac, char *av[])
{
	int do_add, is_all;
	int atomic, error, tcmd;
	ipfw_xtable_info i;
	ipfw_obj_header oh;
	char *tablename;
	uint32_t set;
	void *arg;

	memset(&oh, 0, sizeof(oh));
	is_all = 0;
	if (co.use_set != 0)
		set = co.use_set - 1;
	else
		set = 0;

	ac--; av++;
	NEED1("table needs name");
	tablename = *av;

	if (table_check_name(tablename) == 0) {
		table_fill_ntlv(&oh.ntlv, *av, set, 1);
		oh.idx = 1;
	} else {
		if (strcmp(tablename, "all") == 0)
			is_all = 1;
		else
			errx(EX_USAGE, "table name %s is invalid", tablename);
	}
	ac--; av++;
	NEED1("table needs command");

	tcmd = get_token(tablecmds, *av, "table command");
	/* Check if atomic operation was requested */
	atomic = 0;
	if (tcmd == TOK_ATOMIC) {
		ac--; av++;
		NEED1("atomic needs command");
		tcmd = get_token(tablecmds, *av, "table command");
		switch (tcmd) {
		case TOK_ADD:
			break;
		default:
			errx(EX_USAGE, "atomic is not compatible with %s", *av);
		}
		atomic = 1;
	}

	switch (tcmd) {
	case TOK_LIST:
	case TOK_INFO:
	case TOK_DETAIL:
	case TOK_FLUSH:
		break;
	default:
		if (is_all != 0)
			errx(EX_USAGE, "table name required");
	}

	switch (tcmd) {
	case TOK_ADD:
	case TOK_DEL:
		do_add = **av == 'a';
		ac--; av++;
		table_modify_record(&oh, ac, av, do_add, co.do_quiet,
		    co.do_quiet, atomic);
		break;
	case TOK_CREATE:
		ac--; av++;
		table_create(&oh, ac, av);
		break;
	case TOK_MODIFY:
		ac--; av++;
		table_modify(&oh, ac, av);
		break;
	case TOK_DESTROY:
		if (table_destroy(&oh) != 0)
			err(EX_OSERR, "failed to destroy table %s", tablename);
		break;
	case TOK_FLUSH:
		if (is_all == 0) {
			if ((error = table_flush(&oh)) != 0)
				err(EX_OSERR, "failed to flush table %s info",
				    tablename);
		} else {
			error = tables_foreach(table_flush_one, &oh, 1);
			if (error != 0)
				err(EX_OSERR, "failed to flush tables list");
		}
		break;
	case TOK_SWAP:
		ac--; av++;
		NEED1("second table name required");
		table_swap(&oh, *av);
		break;
	case TOK_LOCK:
	case TOK_UNLOCK:
		table_lock(&oh, (tcmd == TOK_LOCK));
		break;
	case TOK_DETAIL:
	case TOK_INFO:
		arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL;
		if (is_all == 0) {
			if ((error = table_get_info(&oh, &i)) != 0)
				err(EX_OSERR, "failed to request table info");
			table_show_info(&i, arg);
		} else {
			error = tables_foreach(table_show_info, arg, 1);
			if (error != 0)
				err(EX_OSERR, "failed to request tables list");
		}
		break;
	case TOK_LIST:
		if (is_all == 0) {
			ipfw_xtable_info i;
			if ((error = table_get_info(&oh, &i)) != 0)
				err(EX_OSERR, "failed to request table info");
			table_show_one(&i, NULL);
		} else {
			error = tables_foreach(table_show_one, NULL, 1);
			if (error != 0)
				err(EX_OSERR, "failed to request tables list");
		}
		break;
	case TOK_LOOKUP:
		ac--; av++;
		table_lookup(&oh, ac, av);
		break;
	}
}
Exemple #12
0
/*
 * Configures existing nat64lsn instance
 * ipfw nat64lsn <NAME> config <options>
 * Request: [ ipfw_obj_header ipfw_nat64lsn_cfg ]
 */
static void
nat64lsn_config(const char *name, uint8_t set, int ac, char **av)
{
	char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64lsn_cfg)];
	ipfw_nat64lsn_cfg *cfg;
	ipfw_obj_header *oh;
	size_t sz;
	char *opt;
	int tcmd;

	if (ac == 0)
		errx(EX_USAGE, "config options required");
	memset(&buf, 0, sizeof(buf));
	oh = (ipfw_obj_header *)buf;
	cfg = (ipfw_nat64lsn_cfg *)(oh + 1);
	sz = sizeof(buf);

	nat64lsn_fill_ntlv(&oh->ntlv, name, set);
	if (do_get3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, &sz) != 0)
		err(EX_OSERR, "failed to get config for instance %s", name);

	while (ac > 0) {
		tcmd = get_token(nat64newcmds, *av, "option");
		opt = *av;
		ac--; av++;

		switch (tcmd) {
		case TOK_MAX_PORTS:
			NEED1("Max per-user ports required");
			cfg->max_ports = nat64lsn_parse_int(*av, opt);
			ac--; av++;
			break;
		case TOK_JMAXLEN:
			NEED1("job queue length required");
			cfg->jmaxlen = nat64lsn_parse_int(*av, opt);
			ac--; av++;
			break;
		case TOK_HOST_DEL_AGE:
			NEED1("host delete delay required");
			cfg->nh_delete_delay = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_PG_DEL_AGE:
			NEED1("portgroup delete delay required");
			cfg->pg_delete_delay = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_TCP_SYN_AGE:
			NEED1("tcp syn age required");
			cfg->st_syn_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_TCP_CLOSE_AGE:
			NEED1("tcp close age required");
			cfg->st_close_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_TCP_EST_AGE:
			NEED1("tcp est age required");
			cfg->st_estab_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_UDP_AGE:
			NEED1("udp age required");
			cfg->st_udp_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_ICMP_AGE:
			NEED1("icmp age required");
			cfg->st_icmp_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_LOG:
			cfg->flags |= NAT64_LOG;
			break;
		case TOK_LOGOFF:
			cfg->flags &= ~NAT64_LOG;
			break;
		default:
			errx(EX_USAGE, "Can't change %s option", opt);
		}
	}

	if (do_set3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, sizeof(buf)) != 0)
		err(EX_OSERR, "nat64lsn instance configuration failed");
}
Exemple #13
0
static void
nat64lsn_create(const char *name, uint8_t set, int ac, char **av)
{
	char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nat64lsn_cfg)];
	ipfw_nat64lsn_cfg *cfg;
	ipfw_obj_lheader *olh;
	int tcmd, flags;
	char *opt;

	memset(&buf, 0, sizeof(buf));
	olh = (ipfw_obj_lheader *)buf;
	cfg = (ipfw_nat64lsn_cfg *)(olh + 1);

	/* Some reasonable defaults */
	inet_pton(AF_INET6, "64:ff9b::", &cfg->prefix6);
	cfg->plen6 = 96;
	cfg->set = set;
	cfg->max_ports = NAT64LSN_MAX_PORTS;
	cfg->jmaxlen = NAT64LSN_JMAXLEN;
	cfg->nh_delete_delay = NAT64LSN_HOST_AGE;
	cfg->pg_delete_delay = NAT64LSN_PG_AGE;
	cfg->st_syn_ttl = NAT64LSN_TCP_SYN_AGE;
	cfg->st_estab_ttl = NAT64LSN_TCP_EST_AGE;
	cfg->st_close_ttl = NAT64LSN_TCP_FIN_AGE;
	cfg->st_udp_ttl = NAT64LSN_UDP_AGE;
	cfg->st_icmp_ttl = NAT64LSN_ICMP_AGE;
	flags = NAT64LSN_HAS_PREFIX6;
	while (ac > 0) {
		tcmd = get_token(nat64newcmds, *av, "option");
		opt = *av;
		ac--; av++;

		switch (tcmd) {
		case TOK_PREFIX4:
			NEED1("IPv4 prefix required");
			nat64lsn_parse_prefix(*av, AF_INET, &cfg->prefix4,
			    &cfg->plen4);
			flags |= NAT64LSN_HAS_PREFIX4;
			ac--; av++;
			break;
#if 0
		case TOK_PREFIX6:
			NEED1("IPv6 prefix required");
			nat64lsn_parse_prefix(*av, AF_INET6, &cfg->prefix6,
			    &cfg->plen6);
			ac--; av++;
			break;
		case TOK_AGG_LEN:
			NEED1("Aggregation prefix len required");
			cfg->agg_prefix_len = nat64lsn_parse_int(*av, opt);
			ac--; av++;
			break;
		case TOK_AGG_COUNT:
			NEED1("Max per-prefix count required");
			cfg->agg_prefix_max = nat64lsn_parse_int(*av, opt);
			ac--; av++;
			break;
		case TOK_PORT_RANGE:
			NEED1("port range x[:y] required");
			if ((p = strchr(*av, ':')) == NULL)
				cfg->min_port = (uint16_t)nat64lsn_parse_int(
				    *av, opt);
			else {
				*p++ = '\0';
				cfg->min_port = (uint16_t)nat64lsn_parse_int(
				    *av, opt);
				cfg->max_port = (uint16_t)nat64lsn_parse_int(
				    p, opt);
			}
			ac--; av++;
			break;
		case TOK_JMAXLEN:
			NEED1("job queue length required");
			cfg->jmaxlen = nat64lsn_parse_int(*av, opt);
			ac--; av++;
			break;
#endif
		case TOK_MAX_PORTS:
			NEED1("Max per-user ports required");
			cfg->max_ports = nat64lsn_parse_int(*av, opt);
			ac--; av++;
			break;
		case TOK_HOST_DEL_AGE:
			NEED1("host delete delay required");
			cfg->nh_delete_delay = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_PG_DEL_AGE:
			NEED1("portgroup delete delay required");
			cfg->pg_delete_delay = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_TCP_SYN_AGE:
			NEED1("tcp syn age required");
			cfg->st_syn_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_TCP_CLOSE_AGE:
			NEED1("tcp close age required");
			cfg->st_close_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_TCP_EST_AGE:
			NEED1("tcp est age required");
			cfg->st_estab_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_UDP_AGE:
			NEED1("udp age required");
			cfg->st_udp_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_ICMP_AGE:
			NEED1("icmp age required");
			cfg->st_icmp_ttl = (uint16_t)nat64lsn_parse_int(
			    *av, opt);
			ac--; av++;
			break;
		case TOK_LOG:
			cfg->flags |= NAT64_LOG;
			break;
		case TOK_LOGOFF:
			cfg->flags &= ~NAT64_LOG;
			break;
		}
	}

	/* Check validness */
	if ((flags & NAT64LSN_HAS_PREFIX4) != NAT64LSN_HAS_PREFIX4)
		errx(EX_USAGE, "prefix4 required");

	olh->count = 1;
	olh->objsize = sizeof(*cfg);
	olh->size = sizeof(buf);
	strlcpy(cfg->name, name, sizeof(cfg->name));
	if (do_set3(IP_FW_NAT64LSN_CREATE, &olh->opheader, sizeof(buf)) != 0)
		err(EX_OSERR, "nat64lsn instance creation failed");
}