OpenBSD-4.6/usr.sbin/bgpctl/irr_output.c

Compare this file to the similar file:
Show the results in this format:

/*	$OpenBSD: irr_output.c,v 1.13 2007/03/05 17:28:21 henning Exp $ */

/*
 * Copyright (c) 2007 Henning Brauer <henning@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "irrfilter.h"

int	 process_policies(FILE *, struct policy_head *);
void	 policy_prettyprint(FILE *, struct policy_item *);
void	 policy_torule(FILE *, struct policy_item *);
char	*action_torule(char *);
void	 print_rule(FILE *, struct policy_item *, char *, struct irr_prefix *);

#define allowed_in_address(x) \
	(isalnum(x) || x == '.' || x == ':' || x == '-')

int
write_filters(char *outpath)
{
	struct router	*r;
	char		*fn;
	int		 fd, ret = 0;
	u_int		 i;
	FILE		*fh;

	while ((r = TAILQ_FIRST(&router_head)) != NULL) {
		TAILQ_REMOVE(&router_head, r, entry);

		if (r->address != NULL && r->address[0] != '\0') {
			for (i = 0; i < strlen(r->address); i++)
				if (!allowed_in_address(r->address[i]))
					errx(1, "router address \"%s\" contains"
					    " illegal character \"%c\"",
					    r->address, r->address[i]);
			if (asprintf(&fn, "%s/bgpd-%s.filter",
			    outpath, r->address) == -1)
				err(1, "write_filters asprintf");
		} else
			if (asprintf(&fn, "%s/bgpd.filter",
			    outpath) == -1)
				err(1, "write_filters asprintf");

		fd = open(fn, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
		if (fd == -1)
			err(1, "error opening %s", fn);
		if ((fh = fdopen(fd, "w")) == NULL)
			err(1, "fdopen %s", fn);

		if (process_policies(fh, &r->policy_h) == -1)
			ret = -1;

		fclose(fh);
		close(fd);
		free(fn);
		free(r->address);
		free(r);
	}

	return (ret);
}

int
process_policies(FILE *fh, struct policy_head *head)
{
	struct policy_item	*pi;

	while ((pi = TAILQ_FIRST(head)) != NULL) {
		TAILQ_REMOVE(head, pi, entry);

		policy_prettyprint(fh, pi);
		policy_torule(fh, pi);

		free(pi->peer_addr);
		free(pi->action);
		free(pi->filter);
		free(pi);
	}

	return (0);
}

void
policy_prettyprint(FILE *fh, struct policy_item *pi)
{
	if (pi->dir == IMPORT)
		fprintf(fh, "# import: from ");
	else
		fprintf(fh, "# export: to ");
	fprintf(fh, "AS%u ", pi->peer_as);
	if (pi->peer_addr)
		fprintf(fh, "%s ", pi->peer_addr);
	if (pi->action)
		fprintf(fh, "action %s ", pi->action);
	fprintf(fh, "%s %s\n", pi->dir == IMPORT ? "accept" : "announce",
	    pi->filter);
}

void
policy_torule(FILE *fh, struct policy_item *pi)
{
	struct as_set		*ass;
	struct prefix_set	*pfxs;
	char			*srcas;
	u_int			 i, j;

	if (pi->filter == NULL || !strcasecmp(pi->filter, "any"))
		print_rule(fh, pi, NULL, NULL);
	else {
		ass = asset_expand(pi->filter);

		for (i = 0; i < ass->n_as; i++) {
			pfxs = prefixset_get(ass->as[i]);

			/* ass->as[i] format and len have been checked before */
			if (strlen(ass->as[i]) < 3)
				errx(1, "%s not AS...", ass->as[i]);
			srcas = ass->as[i] + 2;
			for (j = 0; j < pfxs->prefixcnt; j++)
				print_rule(fh, pi, srcas, pfxs->prefix[j]);
		}
	}
}

/* XXX should really be parsed earlier! */
char *
action_torule(char *s)
{
	int		 cnt = 0;
	char		*key, *val, *pre, *tmp;
	static char	 abuf[8192];
	char		 ebuf[2048];

	if ((tmp = strdup(s)) == NULL)
		err(1, "foo");
	abuf[0] = '\0';
	while ((val = strsep(&tmp, ";")) != NULL && *val) {
		key = strsep(&val, "=");
		if (key == NULL || val == NULL)
			err(1, "format error in action spec\n");

		EATWS(key);
		EATWS(val);

		if (cnt++ == 0)
			pre = " set {";
		else
			pre = ",";

		if (!strcmp(key, "pref"))
			snprintf(ebuf, sizeof(ebuf),
			    "%s localpref %s", pre, val);
		else if (!strcmp(key, "med"))
			snprintf(ebuf, sizeof(ebuf),
			    "%s med %s", pre, val);
		else
			warnx("unknown action key \"%s\"", key);

		strlcat(abuf, ebuf, sizeof(abuf));
	}
	if (cnt > 0)
		strlcat(abuf, " }", sizeof(abuf));

	free(tmp);
	return (abuf);
}

void
print_rule(FILE *fh, struct policy_item *pi, char *sourceas,
    struct irr_prefix *prefix)
{
	char	*fmt = "allow quick %s %s%s%s%s%s\n";
	char	*peer = "any";
	char	*action = "";
	char	*dir;
	char	*srcas[2] = { "", "" };
	char	 pbuf[8 + NI_MAXHOST + 4 + 14 + 3];
	size_t	 offset;

	if (pi->dir == IMPORT)
		dir = "from";
	else
		dir = "to";

	if (pi->peer_addr)
		peer = pi->peer_addr;

	if (pi->action)
		action = action_torule(pi->action);

	pbuf[0] = '\0';
	if (prefix != NULL) {
		strlcpy(pbuf, " prefix ", sizeof(pbuf));
		offset = strlen(pbuf);
		if (inet_ntop(prefix->af, &prefix->addr, pbuf + offset,
		    sizeof(pbuf) - offset) == NULL)
			err(1, "print_rule inet_ntop");
		offset = strlen(pbuf);
		if (snprintf(pbuf + offset, sizeof(pbuf) - offset,
		    "/%u", prefix->len) == -1)
			err(1, "print_rule snprintf");

		if (prefix->maxlen > prefix->len) {
			offset = strlen(pbuf);
			if (snprintf(pbuf + offset, sizeof(pbuf) - offset,
			    " prefixlen <= %u", prefix->maxlen) == -1)
				err(1, "print_rule snprintf");
		}

		if (pi->dir == IMPORT) {
			srcas[0] = " source-as ";
			srcas[1] = sourceas;
		}
	}

	fprintf(fh, fmt, dir, peer, srcas[0], srcas[1], pbuf, action);
}