Module Name:    src
Committed By:   christos
Date:           Sat Dec 12 23:35:56 UTC 2015

Added Files:
        src/usr.sbin/ip6addrctl: Makefile ip6addrctl.8 ip6addrctl.c
            ip6addrctl.conf.sample

Log Message:
Add ip6addrctl from FreeBSD


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/usr.sbin/ip6addrctl/Makefile \
    src/usr.sbin/ip6addrctl/ip6addrctl.8 src/usr.sbin/ip6addrctl/ip6addrctl.c \
    src/usr.sbin/ip6addrctl/ip6addrctl.conf.sample

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/usr.sbin/ip6addrctl/Makefile
diff -u /dev/null src/usr.sbin/ip6addrctl/Makefile:1.1
--- /dev/null	Sat Dec 12 18:35:56 2015
+++ src/usr.sbin/ip6addrctl/Makefile	Sat Dec 12 18:35:56 2015
@@ -0,0 +1,7 @@
+#	$NetBSD: Makefile,v 1.1 2015/12/12 23:35:56 christos Exp $
+# $FreeBSD: head/usr.sbin/ip6addrctl/Makefile 241134 2012-10-02 14:48:03Z eadler $
+
+PROG=	ip6addrctl
+MAN=	ip6addrctl.8
+
+.include <bsd.prog.mk>
Index: src/usr.sbin/ip6addrctl/ip6addrctl.8
diff -u /dev/null src/usr.sbin/ip6addrctl/ip6addrctl.8:1.1
--- /dev/null	Sat Dec 12 18:35:56 2015
+++ src/usr.sbin/ip6addrctl/ip6addrctl.8	Sat Dec 12 18:35:56 2015
@@ -0,0 +1,127 @@
+.\"	$NetBSD: ip6addrctl.8,v 1.1 2015/12/12 23:35:56 christos Exp $
+.\"	$KAME: ip6addrctl.8,v 1.3 2003/03/22 05:56:41 jinmei Exp $
+.\"
+.\" Copyright (C) 2001 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: head/usr.sbin/ip6addrctl/ip6addrctl.8 140368 2005-01-17 07:44:44Z ru $
+.\"
+.Dd September 25, 2001
+.Dt IP6ADDRCTL 8
+.Os
+.\"
+.Sh NAME
+.Nm ip6addrctl
+.Nd configure address selection policy for IPv6 and IPv4
+.\"
+.Sh SYNOPSIS
+.Nm
+.Op Cm show
+.Nm
+.Cm add
+.Ar prefix precedence label
+.Nm
+.Cm delete
+.Ar prefix
+.Nm
+.Cm flush
+.Nm
+.Cm install
+.Ar configfile
+.\"
+.Sh DESCRIPTION
+The
+.Nm
+utility manages the policy table of source and destination address
+selection for outgoing IPv4 and IPv6 packets.
+When
+.Nm
+is invoked without an argument or with a single argument
+.Cm show ,
+it prints the content of the policy table currently installed in the
+kernel.
+.Pp
+To modify the table, the following operations are available:
+.Bl -tag -width indent
+.It Cm add Ar prefix precedence label
+Add a policy entry.
+The
+.Ar prefix
+argument
+is an IPv6 prefix, which is a key for the entry.
+An IPv4 prefix should be specified with an IPv6 prefix using an
+IPv4-mapped IPv6 address.
+The
+.Ar precedence
+and
+.Ar label
+arguments
+are decimal numbers, which specify the precedence and label values
+for the entry, respectively.
+This operation should be performed without an existing entry for the
+prefix.
+.It Cm delete Ar prefix
+Delete a policy entry specified by
+.Ar prefix ,
+which should be an IPv6 prefix.
+A corresponding entry for the prefix should have already been
+installed.
+.It Cm flush
+Delete all existing policy entries in the kernel.
+.It Cm install Ar configfile
+Install policy entries from a configuration file named
+.Ar configfile .
+The configuration file should contain a set of policy entries.
+Each entry is specified in a single line which contains an IPv6 prefix,
+a decimal precedence value, and a decimal label value, separated with
+white space or tab characters.
+In the configuration file, lines beginning with the pound-sign
+.Pq Ql #
+are
+comments and are ignored.
+.El
+.\"
+.Sh EXIT STATUS
+.Ex -std
+.\"
+.Sh SEE ALSO
+.Rs
+.%A "Richard Draves"
+.%T "Default Address Selection for IPv6"
+.%N RFC 3484
+.Re
+.\"
+.Sh HISTORY
+The
+.Nm
+utility first appeared in the KAME IPv6 protocol stack kit.
+The original command name was
+.Nm addrselect ,
+but it was then renamed to the current one so that the name would
+describe its function well.
+.\" .Sh BUGS
+.\" (to be written)
Index: src/usr.sbin/ip6addrctl/ip6addrctl.c
diff -u /dev/null src/usr.sbin/ip6addrctl/ip6addrctl.c:1.1
--- /dev/null	Sat Dec 12 18:35:56 2015
+++ src/usr.sbin/ip6addrctl/ip6addrctl.c	Sat Dec 12 18:35:56 2015
@@ -0,0 +1,458 @@
+/*	$KAME: ip6addrctl.c,v 1.3 2003/12/16 08:14:28 suz Exp $	*/
+
+/*
+ * Copyright (C) 2001 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/usr.sbin/ip6addrctl/ip6addrctl.c 281143 2015-04-06 09:42:23Z glebius $
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: ip6addrctl.c,v 1.1 2015/12/12 23:35:56 christos Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+
+#include <stdlib.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <err.h>
+
+static char *configfile;
+
+struct policyqueue {
+	TAILQ_ENTRY(policyqueue) pc_entry;
+	struct in6_addrpolicy pc_policy;
+};
+TAILQ_HEAD(policyhead, policyqueue);
+static struct policyhead policyhead;
+
+static void usage(void);
+static void get_policy(void);
+static void dump_policy(void);
+static int mask2plen(struct sockaddr_in6 *);
+static int parse_prefix(const char *, struct in6_addrpolicy *);
+static void make_policy_fromfile(char *);
+static void plen2mask(struct sockaddr_in6 *, int);
+static void set_policy(void);
+static void add_policy(char *, char *, char *);
+static void delete_policy(char *);
+static void flush_policy(void);
+
+int
+main(int argc, char *argv[])
+{
+	TAILQ_INIT(&policyhead);
+
+	if (argc == 1 || strcasecmp(argv[1], "show") == 0) {
+		get_policy();
+		dump_policy();
+	} else if (strcasecmp(argv[1], "add") == 0) {
+		if (argc < 5)
+			usage();
+		add_policy(argv[2], argv[3], argv[4]);
+	} else if (strcasecmp(argv[1], "delete") == 0) {
+		if (argc < 3)
+			usage();
+		delete_policy(argv[2]);
+	} else if (strcasecmp(argv[1], "flush") == 0) {
+		get_policy();
+		flush_policy();
+	} else if (strcasecmp(argv[1], "install") == 0) {
+		if (argc < 3)
+			usage();
+		configfile = argv[2];
+		make_policy_fromfile(configfile);
+		set_policy();
+	} else
+		usage();
+
+	exit(0);
+}
+
+static void
+get_policy(void)
+{
+	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
+	size_t l;
+	struct in6_addrpolicy *buf;
+	struct in6_addrpolicy *pol, *ep;
+
+	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
+		err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
+		/* NOTREACHED */
+	}
+	if (l == 0) {
+		printf("no source-address-selection policy is installed\n");
+		return;
+	}
+	if ((buf = malloc(l)) == NULL) {
+		errx(1, "malloc failed");
+		/* NOTREACHED */
+	}
+	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
+		err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
+		/* NOTREACHED */
+	}
+
+	ep = buf + l/sizeof(*buf);
+	for (pol = buf; pol + 1 <= ep; pol++) {
+		struct policyqueue *new;
+
+		if ((new = malloc(sizeof(*new))) == NULL)
+			errx(1, "malloc failed\n");
+		new->pc_policy = *pol;
+		TAILQ_INSERT_TAIL(&policyhead, new, pc_entry);
+	}
+
+	free(buf);
+}
+
+static void
+dump_policy(void)
+{
+	size_t addrlen;
+	char addrbuf[NI_MAXHOST];
+	struct in6_addrpolicy *pol;
+	struct policyqueue *ent;
+	int plen, first = 1;
+
+	for (ent = TAILQ_FIRST(&policyhead); ent;
+	     ent = TAILQ_NEXT(ent, pc_entry)) {
+		pol = &ent->pc_policy;
+		if (first) {
+			printf("%-30s %5s %5s %8s\n",
+			       "Prefix", "Prec", "Label", "Use");
+			first = 0;
+		}
+
+		if ((getnameinfo((struct sockaddr *)&pol->addr,
+				 sizeof(pol->addr), addrbuf, sizeof(addrbuf),
+				 NULL, 0, NI_NUMERICHOST))) {
+			warnx("getnameinfo for prefix address failed");
+			continue;
+		}
+		if ((plen = mask2plen(&pol->addrmask)) < 0) {
+			warnx("invalid address mask");
+			continue;
+		}
+		addrlen = strlen(addrbuf);
+		if (addrlen + sizeof("/128") < sizeof(addrbuf)) {
+			snprintf(&addrbuf[addrlen],
+				 sizeof(addrbuf) - addrlen - 1,
+				 "/%d", plen);
+			printf("%-30s", addrbuf);
+		} else		/* XXX */
+			printf("%s/%d", addrbuf, plen);
+		printf(" %5d %5d %8llu\n", pol->preced, pol->label,
+		    (unsigned long long)pol->use);
+	}
+}
+
+#define SKIP_WHITE(p, emptyok) \
+	do { \
+		while((*(p) == ' ' || *(p) == '\t')) \
+			(p)++; \
+ 		if ((*(p) == '\0' || (*(p) == '\n')) && !(emptyok)) \
+			goto bad; \
+	} while (0);
+#define SKIP_WORD(p) \
+	do { \
+		while(*(p) != ' ' && *(p) != '\t') \
+			(p)++; \
+ 		if (*(p) == '\0' || *(p) == '\n') \
+			goto bad; \
+	} while (0);
+
+static void
+make_policy_fromfile(char *conf)
+{
+	char line[_POSIX2_LINE_MAX], *cp;
+	char *addrstr;
+	FILE *fp;
+	int count = 0;
+	struct in6_addrpolicy pol0;
+	struct policyqueue *new;
+
+	if ((fp = fopen(conf, "r")) == NULL)
+		err(1, "fopen: %s", conf);
+
+	while(fgets(line, sizeof(line), fp)) {
+		count++;
+		cp = line;
+
+		memset(&pol0, 0, sizeof(pol0));
+
+		/* get prefix */
+		SKIP_WHITE(cp, 1);
+		if (*cp == '\n') /* empty line */
+			continue;
+		if (*cp == '#')
+			continue;
+		addrstr = cp;
+		if (parse_prefix((const char *)addrstr, &pol0))
+			goto bad;
+
+		/* get precedence value */
+		SKIP_WORD(cp);
+		SKIP_WHITE(cp, 0);
+		pol0.preced = atoi(cp);
+
+		/* get label */
+		SKIP_WORD(cp);
+		SKIP_WHITE(cp, 0);
+		pol0.label = atoi(cp);
+
+		/* parse succeeded.  make a control buffer entry. */
+		if ((new = malloc(sizeof(*new))) == NULL)
+			errx(1, "malloc failed\n");
+		memset(new, 0, sizeof(*new));
+		new->pc_policy = pol0;
+		TAILQ_INSERT_TAIL(&policyhead, new, pc_entry);
+	}
+
+	fclose(fp);
+	return;
+
+  bad:
+	errx(1, "parse failed at line %d", count);
+	/* NOTREACHED */
+}
+
+static int
+parse_prefix(const char *prefix0, struct in6_addrpolicy *pol)
+{
+	int e = 0, plen;
+	char *prefix, *plenstr;
+	struct addrinfo hints, *res;
+
+	if ((prefix = strdup(prefix0)) == NULL)
+		errx(1, "strdup failed");
+
+	if ((plenstr = strchr(prefix, '/')) == NULL) {
+		e = -1;
+		goto end;
+	}
+	*plenstr = '\0';
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_NUMERICHOST;
+	hints.ai_family = AF_INET6;
+
+	if ((e = getaddrinfo(prefix, NULL, &hints, &res)) != 0) {
+		warnx("getaddrinfo failed for %s: %s", prefix,
+		      gai_strerror(e));
+		goto end;
+	}
+	memcpy(&pol->addr, res->ai_addr, res->ai_addrlen);
+	freeaddrinfo(res);
+	plen = atoi(plenstr + 1);
+	if (plen < 0 || plen > 128) {
+		warnx("invalid prefix length: %d", plen);
+		e = -1;
+		goto end;
+	}
+	plen2mask(&pol->addrmask, plen);
+
+  end:
+	free(prefix);
+	return(e);
+}
+
+static void
+plen2mask(struct sockaddr_in6 *mask, int plen)
+{
+	u_char *cp = (unsigned char *)&mask->sin6_addr;
+
+	memset(mask, 0, sizeof(*mask));
+	mask->sin6_family = AF_INET6; /* just in case */
+	mask->sin6_len = sizeof(*mask);
+
+	for(; plen >= 8; plen -= 8)
+		*cp++ = 0xff;
+	if (plen > 0)
+		*cp = (0xff << (8 - plen));
+}
+
+static void
+set_policy(void)
+{
+	struct policyqueue *ent;
+	int s;
+
+	if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+		err(1, "socket(UDP)");
+
+	for (ent = TAILQ_FIRST(&policyhead); ent;
+	     ent = TAILQ_NEXT(ent, pc_entry)) {
+		if (ioctl(s, SIOCAADDRCTL_POLICY, &ent->pc_policy))
+			warn("ioctl(SIOCAADDRCTL_POLICY)");
+	}
+
+	close(s);
+}
+
+static int
+mask2plen(struct sockaddr_in6 *mask)
+{
+	int masklen, final = 0;
+	u_char *p, *lim;
+
+	masklen = 0;
+	lim = (u_char *)(mask + 1);
+	for (p = (u_char *)(&mask->sin6_addr); p < lim; p++) {
+		if (final && *p) {
+			goto bad;
+		}
+
+		switch (*p & 0xff) {
+		case 0xff:
+			masklen += 8;
+			break;
+		case 0xfe:
+			masklen += 7;
+			final++;
+			break;
+		case 0xfc:
+			masklen += 6;
+			final++;
+			break;
+		case 0xf8:
+			masklen += 5;
+			final++;
+			break;
+		case 0xf0:
+			masklen += 4;
+			final++;
+			break;
+		case 0xe0:
+			masklen += 3;
+			final++;
+			break;
+		case 0xc0:
+			masklen += 2;
+			final++;
+			break;
+		case 0x80:
+			masklen += 1;
+			final++;
+			break;
+		case 0x00:
+			final++;
+			break;
+		default:
+			goto bad;
+			break;
+		}
+	}
+	return(masklen);
+
+  bad:
+	return(-1);
+}
+
+static void
+add_policy(char *prefix, char *prec, char *label)
+{
+	struct in6_addrpolicy p;
+	int s;
+
+	memset(&p, 0, sizeof(p));
+
+	if (parse_prefix((const char *)prefix, &p))
+		errx(1, "bad prefix: %s", prefix);
+	p.preced = atoi(prec);
+	p.label = atoi(label);
+
+	if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+		err(1, "socket(UDP)");
+	if (ioctl(s, SIOCAADDRCTL_POLICY, &p))
+		err(1, "ioctl(SIOCAADDRCTL_POLICY)");
+
+	close(s);
+}
+
+static void
+delete_policy(char *prefix)
+{
+	struct in6_addrpolicy p;
+	int s;
+
+	memset(&p, 0, sizeof(p));
+
+	if (parse_prefix((const char *)prefix, &p))
+		errx(1, "bad prefix: %s", prefix);
+
+	if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+		err(1, "socket(UDP)");
+	if (ioctl(s, SIOCDADDRCTL_POLICY, &p))
+		err(1, "ioctl(SIOCDADDRCTL_POLICY)");
+
+	close(s);
+}
+
+static void
+flush_policy(void)
+{
+	struct policyqueue *ent;
+	int s;
+
+	if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+		err(1, "socket(UDP)");
+
+	for (ent = TAILQ_FIRST(&policyhead); ent;
+	     ent = TAILQ_NEXT(ent, pc_entry)) {
+		if (ioctl(s, SIOCDADDRCTL_POLICY, &ent->pc_policy))
+			warn("ioctl(SIOCDADDRCTL_POLICY)");
+	}
+
+	close(s);
+}
+
+static void
+usage(void)
+{
+	fprintf(stderr, "usage: ip6addrctl [show]\n");
+	fprintf(stderr, "       ip6addrctl add "
+		"<prefix> <precedence> <label>\n");
+	fprintf(stderr, "       ip6addrctl delete <prefix>\n");
+	fprintf(stderr, "       ip6addrctl flush\n");
+	fprintf(stderr, "       ip6addrctl install <configfile>\n");
+
+	exit(1);
+}
Index: src/usr.sbin/ip6addrctl/ip6addrctl.conf.sample
diff -u /dev/null src/usr.sbin/ip6addrctl/ip6addrctl.conf.sample:1.1
--- /dev/null	Sat Dec 12 18:35:56 2015
+++ src/usr.sbin/ip6addrctl/ip6addrctl.conf.sample	Sat Dec 12 18:35:56 2015
@@ -0,0 +1,12 @@
+# default policy table based on RFC 3484.
+# usage: ip6addrctl install path_to_this_file
+#
+# $FreeBSD: head/usr.sbin/ip6addrctl/ip6addrctl.conf.sample 123872 2003-12-26 17:10:58Z ume $
+#
+#Format:
+#Prefix       Precedence Label
+::1/128               50     0 
+::/0                  40     1 
+2002::/16             30     2 
+::/96                 20     3 
+::ffff:0:0/96         10     4 

Reply via email to