Commit 60c412b9 authored by Ondrej Filip's avatar Ondrej Filip
Browse files

Merge branch 'master' of ssh://git.nic.cz/bird

parents 3fe1d9e4 94e2f1c1
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
Version 1.3.8 (2012-08-07)
  o Generalized import and export route limits.
  o RDNSS and DNSSL support for RAdv.
  o Include in config file support wildcards.
  o History deduplication in BIRD client.
  o New route attributes krt_source, krt_metric.
  o Different instance ID support for OSPFv3.
  o Real broadcast mode for OSPFv2.
  o Several minor bugfixes.

Version 1.3.7 (2012-03-22)
  o Route Origin Authorization basics.
+166 −61
Original line number Diff line number Diff line
@@ -31,6 +31,12 @@
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <libgen.h>
#include <glob.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>

#define PARSER 1

@@ -64,27 +70,23 @@ struct sym_scope {
};
static struct sym_scope *conf_this_scope;

#define MAX_INCLUDE_DEPTH 5

static struct include_file_stack *ifs_head;
static int ifs_depth;

static int cf_hash(byte *c);
static struct symbol *cf_find_sym(byte *c, unsigned int h0);

linpool *cfg_mem;

int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
int (*cf_open_hook)(char *filename);
struct include_file_stack *ifs;
static struct include_file_stack *ifs_head;

#define MAX_INCLUDE_DEPTH 8

#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->conf_fd);
#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->fd);
#define YY_NO_UNPUT
#define YY_FATAL_ERROR(msg) cf_error(msg)

static void new_include(void);
static void cf_include(char *arg, int alen);
static int check_eof(void);
static struct include_file_stack *new_stack(struct include_file_stack *old);

%}

@@ -103,7 +105,23 @@ WHITE [ \t]
include   ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;

%%
{include} { if(cf_open_hook) new_include(); }
{include} {
  char *start, *end;

  if (!ifs->depth)
    cf_error("Include not allowed in CLI");

  start = strchr(yytext, '"');
  start++;

  end = strchr(start, '"');
  *end = 0;

  if (start == end)
    cf_error("Include with empty argument");

  cf_include(start, end-start);
}

{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
#ifdef IPV6
@@ -204,7 +222,7 @@ else: {

{WHITE}+

\n	ifs->conf_lino++;
\n	ifs->lino++;

#	BEGIN(COMMENT);

@@ -213,14 +231,14 @@ else: {
.	cf_error("Unknown character");

<COMMENT>\n {
  ifs->conf_lino++;
  ifs->lino++;
  BEGIN(INITIAL);
}

<COMMENT>.

<CCOMM>\*\/	BEGIN(INITIAL);
<CCOMM>\n	ifs->conf_lino++;
<CCOMM>\n	ifs->lino++;
<CCOMM>\/\*	cf_error("Comment nesting not supported");
<CCOMM><<EOF>>	cf_error("Unterminated comment");
<CCOMM>.
@@ -246,47 +264,140 @@ cf_hash(byte *c)
  return h;
}

/* Open included file with properly swapped buffers */

/*
 * IFS stack - it contains structures needed for recursive processing
 * of include in config files. On the top of the stack is a structure
 * for currently processed file. Other structures are either for
 * active files interrupted because of include directive (these have
 * fd and flex buffer) or for inactive files scheduled to be processed
 * later (when parent requested including of several files by wildcard
 * match - these do not have fd and flex buffer yet).
 *
 * FIXME: Most of these ifs and include functions are really sysdep/unix.
 *
 * FIXME: Resources (fd, flex buffers and glob data) in IFS stack
 * are not freed when cf_error() is called.
 */

static struct include_file_stack *
push_ifs(struct include_file_stack *old)
{
  struct include_file_stack *ret;
  ret = cfg_allocz(sizeof(struct include_file_stack));
  ret->lino = 1;
  ret->prev = old;
  return ret;
}

static struct include_file_stack *
pop_ifs(struct include_file_stack *old)
{
 yy_delete_buffer(old->buffer);
 close(old->fd);
 return old->prev;
}

static void
enter_ifs(struct include_file_stack *new)
{
  if (!new->buffer)
    {
      new->fd = open(new->file_name, O_RDONLY);
      if (new->fd < 0)
        {
          ifs = ifs->up;
	  cf_error("Unable to open included file %s: %m", new->file_name);
        }

      new->buffer = yy_create_buffer(NULL, YY_BUF_SIZE);
    }

  yy_switch_to_buffer(new->buffer);
}

static void
new_include(void)
cf_include(char *arg, int alen)
{
  char *fname, *p = NULL;
  struct include_file_stack *base_ifs = ifs;
  int new_depth, rv, i;
  char *patt;
  glob_t g;

  if ((fname = strchr(yytext, '"')) != NULL) {
  new_depth = ifs->depth + 1;
  if (new_depth > MAX_INCLUDE_DEPTH)
    cf_error("Max include depth reached");

    if ((p = strchr(++fname, '"')) != NULL) *p = '\0';
  /* expand arg to properly handle relative filenames */
  if (*arg != '/')
    {
      int dlen = strlen(ifs->file_name);
      char *dir = alloca(dlen + 1);
      patt = alloca(dlen + alen + 2);
      memcpy(dir, ifs->file_name, dlen + 1);
      sprintf(patt, "%s/%s", dirname(dir), arg);
    }
  else
    patt = arg;

  /* Skip globbing if there are no wildcards, mainly to get proper
     response when the included config file is missing */
  if (!strpbrk(arg, "?*["))
    {
      ifs = push_ifs(ifs);
      ifs->file_name = cfg_strdup(patt);
      ifs->depth = new_depth;
      ifs->up = base_ifs;
      enter_ifs(ifs);
      return;
    }

  /* Expand the pattern */
  rv = glob(patt, GLOB_ERR | GLOB_NOESCAPE, NULL, &g);
  if (rv == GLOB_ABORTED)
    cf_error("Unable to match pattern %s: %m", patt);
  if ((rv != 0) || (g.gl_pathc <= 0))
    return;

  /*
   * Now we put all found files to ifs stack in reverse order, they
   * will be activated and processed in order as ifs stack is popped
   * by pop_ifs() and enter_ifs() in check_eof().
   */
  for(i = g.gl_pathc - 1; i >= 0; i--)
    {
      char *fname = g.gl_pathv[i];
      struct stat fs;

    if (ifs_depth >= MAX_INCLUDE_DEPTH)
      cf_error("Max include depth reached.");
      if (stat(fname, &fs) < 0)
        cf_error("Unable to stat included file %s: %m", fname);

    /* Save current stack */
    ifs->stack = YY_CURRENT_BUFFER;
    /* Prepare new stack */
    ifs->next = new_stack(ifs);
    ifs = ifs->next;
    strcpy(ifs->conf_fname, fname); /* XXX: strlcpy should be here */
    ifs->conf_fd = cf_open_hook(fname);
      if (fs.st_mode & S_IFDIR)
        continue;

    yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
      /* Prepare new stack item */
      ifs = push_ifs(ifs);
      ifs->file_name = cfg_strdup(fname);
      ifs->depth = new_depth;
      ifs->up = base_ifs;
    }

  globfree(&g);
  enter_ifs(ifs);
}

static int
check_eof(void)
{
	if (ifs == ifs_head) {
  if (ifs == ifs_head)
    {
      /* EOF in main config file */
		ifs->conf_lino = 1;
      ifs->lino = 1; /* Why this? */
      return 1;
    }

	ifs_depth--;
	close(ifs->conf_fd);
	ifs = ifs->prev;
	ifs->next = NULL;
	
	yy_delete_buffer(YY_CURRENT_BUFFER);
	yy_switch_to_buffer(ifs->stack);
  ifs = pop_ifs(ifs);
  enter_ifs(ifs);
  return 0;
}

@@ -415,16 +526,6 @@ cf_lex_init_kh(void)
  kw_hash_inited = 1;
}

static struct include_file_stack *
new_stack(struct include_file_stack *old)
{
  struct include_file_stack *ret;
  ret = cfg_allocz(sizeof(struct include_file_stack));
  ret->conf_lino = 1;
  ret->prev = old;
  return ret;
}

/**
 * cf_lex_init - initialize the lexer
 * @is_cli: true if we're going to parse CLI command, false for configuration
@@ -437,19 +538,23 @@ cf_lex_init(int is_cli, struct config *c)
{
  if (!kw_hash_inited)
    cf_lex_init_kh();
  ifs_head = new_stack(NULL);
  ifs = ifs_head;
  ifs_depth = 0;
  if (!is_cli) {
    ifs->conf_fd = c->file_fd;
    ifs_depth = 1;
    strcpy(ifs->conf_fname, c->file_name);

  ifs_head = ifs = push_ifs(NULL);
  if (!is_cli) 
    {
      ifs->file_name = c->file_name;
      ifs->fd = c->file_fd;
      ifs->depth = 1;
    }

  yyrestart(NULL);
  ifs->buffer = YY_CURRENT_BUFFER;

  if (is_cli)
    BEGIN(CLI);
  else
    BEGIN(INITIAL);

  conf_this_scope = cfg_allocz(sizeof(struct sym_scope));
  conf_this_scope->active = 1;
}
+2 −2
Original line number Diff line number Diff line
@@ -357,8 +357,8 @@ cf_error(char *msg, ...)
  if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
    strcpy(buf, "<bug: error message too long>");
  new_config->err_msg = cfg_strdup(buf);
  new_config->err_lino = ifs->conf_lino;
  new_config->err_file_name = ifs->conf_fname;
  new_config->err_lino = ifs->lino;
  new_config->err_file_name = ifs->file_name;
  longjmp(conf_jmpbuf, 1);
}

+8 −8
Original line number Diff line number Diff line
@@ -12,7 +12,6 @@
#include "lib/resource.h"
#include "lib/timer.h"

#define BIRD_FNAME_MAX 255	/* Would be better to use some UNIX define */

/* Configuration structure */

@@ -91,7 +90,6 @@ void cfg_copy_list(list *dest, list *src, unsigned node_size);
/* Lexer */

extern int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
extern int (*cf_open_hook)(char *filename);

struct symbol {
  struct symbol *next;
@@ -117,12 +115,14 @@ struct symbol {
#define SYM_VARIABLE 0x100	/* 0x100-0x1ff are variable types */

struct include_file_stack {
        void	*stack; /* Internal lexer state */
        unsigned int    conf_lino; /* Current file lineno (at include) */
        char            conf_fname[BIRD_FNAME_MAX]; /* Current file name */
        int             conf_fd; /* Current file descriptor */
        struct include_file_stack *prev;
        struct include_file_stack *next;
  void *buffer;				/* Internal lexer state */
  char *file_name;			/* File name */
  int fd;				/* File descriptor */
  int lino;				/* Current line num */
  int depth;				/* Include depth, 0 = cannot include */

  struct include_file_stack *prev;	/* Previous record in stack */
  struct include_file_stack *up;	/* Parent (who included this file) */
};

extern struct include_file_stack *ifs;
+136 −18
Original line number Diff line number Diff line
@@ -215,7 +215,27 @@ an <it/import/ filter checks routes in the opposite direction.
When the routing table gets a route from a protocol, it recalculates
the selected route and broadcasts it to all protocols connected to
the table. The protocols typically send the update to other routers
in the network.
in the network. Note that although most protocols are interested 
in receiving just selected routes, some protocols (e.g. the <cf/Pipe/
protocol) receive and process all entries in routing tables (accepted
by filters).

<p><label id="dsc-sorted">Usually, a routing table just chooses a
selected route from a list of entries for one network. But if the
<cf/sorted/ option is activated, these lists of entries are kept
completely sorted (according to preference or some protocol-dependent
metric).

This is needed for some features of some protocols
(e.g. <cf/secondary/ option of BGP protocol, which allows to accept
not just a selected route, but the first route (in the sorted list)
that is accepted by filters), but it is incompatible with some other
features (e.g. <cf/deterministic med/ option of BGP protocol, which
activates a way of choosing selected route that cannot be described
using comparison and ordering). Minor advantage is that routes are
shown sorted in <cf/show route/, minor disadvantage is that it is
slightly more computationally expensive.


<chapt>Configuration

@@ -354,11 +374,14 @@ protocol rip {
	defaults are here for a compatibility with older versions
	and might change in the future.

	<tag>table <m/name/</tag> Create a new routing table. The default
	routing table is created implicitly, other routing tables have
	to be added by this command.
	<tag>table <m/name/ [sorted]</tag>
	Create a new routing table. The default routing table is
	created implicitly, other routing tables have to be added by
	this command. Option <cf/sorted/ can be used to enable
	sorting of routes, see <ref id="dsc-sorted" name="sorted table">
	description for details.

	<tag>roa table [ { roa table options ... } ] <m/name/</tag>
	<tag>roa table <m/name/ [ { roa table options ... } ]</tag>
	Create a new ROA (Route Origin Authorization) table. ROA
	tables can be used to validate route origination of BGP
	routes. A ROA table contains ROA entries, each consist of a
@@ -454,7 +477,7 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
	problems in details of its behavior -- the number of exported
	routes can temporarily exceed the limit without triggering it
	during protocol reload, exported routes counter ignores route
	blocking and block action also blocks route updates of alread
	blocking and block action also blocks route updates of already
	accepted routes -- and these details will probably change in
	the future. Default: <cf/none/.

@@ -1270,8 +1293,10 @@ for each neighbor using the following configuration parameters:
	mode is the behavior specified by the BGP standard. Direct
	mode is simpler, does not require any routes in a routing
	table, and was used in older versions of BIRD, but does not
	handle well nontrivial iBGP setups and multihop. Default:
	<cf/direct/ for singlehop eBGP, <cf/recursive/ otherwise.
	handle well nontrivial iBGP setups and multihop.  Recursive
	mode is incompatible with <ref id="dsc-sorted" name="sorted
	tables">. Default: <cf/direct/ for singlehop eBGP,
	<cf/recursive/ otherwise.

	<tag>igp table <m/name/</tag> Specifies a table that is used
	as an IGP routing table. Default: the same as the table BGP is
@@ -1317,6 +1342,16 @@ for each neighbor using the following configuration parameters:
	attributes to be transparent (for example does not prepend its AS number to
	AS PATH attribute and keeps MED attribute). Default: disabled.

	<tag>secondary <m/switch/</tag> Usually, if an import filter
	rejects a selected route, no other route is propagated for
	that network. This option allows to try the next route in
	order until one that is accepted is found or all routes for
	that network are rejected. This can be used for route servers
	that need to propagate different tables to each client but do
	not want to have these tables explicitly (to conserve memory).
	This option requires that the connected routing table is
	<ref id="dsc-sorted" name="sorted">. Default: off.

	<tag>enable route refresh <m/switch/</tag> When BGP speaker
	changes its import filter, it has to re-examine all routes
	received from its neighbor against the new filter. As these
@@ -1422,7 +1457,9 @@ for each neighbor using the following configuration parameters:
	This option enables a different (and slower) algorithm
	implementing proper RFC 4271 route selection, which is
	deterministic. Alternative way how to get deterministic
	behavior is to use <cf/med metric/ option. Default: off.
	behavior is to use <cf/med metric/ option. This option is
	incompatible with <ref id="dsc-sorted" name="sorted tables">.
	Default: off.

	<tag>igp metric <m/switch/</tag> Enable comparison of internal
 	distances to boundary routers during best route selection. Default: on.
@@ -2321,12 +2358,15 @@ advertisement packets to connected networks. These packets contain
basic information about a local network (e.g. a list of network
prefixes), which allows network hosts to autoconfigure network
addresses and choose a default route. BIRD implements router behavior
as defined in RFC 4861<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4861.txt">.
as defined in
RFC 4861<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4861.txt">
and also the DNS extensions from
RFC 6106<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc6106.txt">.

<sect1>Configuration

<p>There are two classes of definitions in RAdv configuration --
interface definitions and prefix definitions:
<p>There are several classes of definitions in RAdv configuration --
interface definitions, prefix definitions and DNS definitions:

<descrip>
	<tag>interface <m/pattern [, ...]/  { <m/options/ }</tag>
@@ -2336,7 +2376,7 @@ interface definitions and prefix definitions:
	detailed description.

	<tag>prefix <m/prefix/ { <m/options/ }</tag>
	Prefix definitions allows to modify a list of advertised
	Prefix definitions allow to modify a list of advertised
	prefixes. By default, the advertised prefixes are the same as
	the network prefixes assigned to the interface. For each
	network prefix, the matching prefix definition is found and
@@ -2350,6 +2390,24 @@ interface definitions and prefix definitions:
	definitions. As expected, the prefix definition is matching if
	the network prefix is a subnet of the prefix in prefix
	definition.

	<tag>rdnss { <m/options/ }</tag>
	RDNSS definitions allow to specify a list of advertised
	recursive DNS servers together with their options. As options
	are seldom necessary, there is also a short variant <cf>rdnss
	<m/address/</cf> that just specifies one DNS server. Multiple
	definitions are cumulative. RDNSS definitions may also be
	interface-specific when used inside interface options. By
	default, interface uses both global and interface-specific
	options, but that can be changed by <cf/rdnss local/ option.

	<tag>dnssl { <m/options/ }</tag>
	DNSSL definitions allow to specify a list of advertised DNS
	search domains together with their options. Like <cf/rdnss/
	above, multiple definitions are cumulative, they can be used
	also as interface-specific options and there is a short
	variant <cf>dnssl <m/domain/</cf> that just specifies one DNS
        search domain.
</descrip>

<p>Interface specific options:
@@ -2362,8 +2420,8 @@ interface definitions and prefix definitions:

	<tag>min ra interval <m/expr/</tag>
	This option specifies the minimum length of that intervals, in
	seconds. Must be at least 3 and at most 3/4 * max ra interval.
	Default: about 1/3 * max ra interval.
	seconds. Must be at least 3 and at most 3/4 * <cf/max ra interval/.
	Default: about 1/3 * <cf/max ra interval/.

	<tag>min delay <m/expr/</tag>
	The minimum delay between two consecutive router advertisements,
@@ -2400,7 +2458,17 @@ interface definitions and prefix definitions:
	This option specifies the time (in seconds) how long (after
	the receipt of RA) hosts may use the router as a default
	router. 0 means do not use as a default router. Default: 3 *
	max ra interval.
	<cf/max ra interval/.

	<tag>rdnss local <m/bool/</tag>
	Use only local (interface-specific) RDNSS definitions for this
	interface. Otherwise, both global and local definitions are
	used. Could also be used to disable RDNSS for given interface
	if no local definitons are specified. Default: no.

	<tag>dnssl local <m/bool/</tag>
	Use only local DNSSL definitions for this interface. See
	<cf/rdnss local/ option above. Default: no.
</descrip>


@@ -2429,6 +2497,42 @@ interface definitions and prefix definitions:
	14400 (4 hours)
</descrip>


<p>RDNSS specific options:

<descrip>
	<tag>ns <m/address/</tag>
	This option specifies one recursive DNS server. Can be used
	multiple times for multiple servers. It is mandatory to have
	at least one <cf/ns/ option in <cf/rdnss/ definition.

	<tag>lifetime [mult] <m/expr/</tag>
	This option specifies the time how long the RDNSS information
        may be used by clients after the receipt of RA. It is
        expressed either in seconds or (when <cf/mult/ is used) in
        multiples of <cf/max ra interval/. Note that RDNSS information
        is also invalidated when <cf/default lifetime/ expires. 0
        means these addresses are no longer valid DNS servers.
	Default: 3 * <cf/max ra interval/.
</descrip>


<p>DNSSL specific options:

<descrip>
	<tag>domain <m/address/</tag>
	This option specifies one DNS search domain. Can be used
	multiple times for multiple domains. It is mandatory to have
	at least one <cf/domain/ option in <cf/dnssl/ definition.

	<tag>lifetime [mult] <m/expr/</tag>
	This option specifies the time how long the DNSSL information
        may be used by clients after the receipt of RA. Details are
	the same as for RDNSS <cf/lifetime/ option above.
	Default: 3 * <cf/max ra interval/.
</descrip>


<sect1>Example

<p><code>
@@ -2450,6 +2554,20 @@ protocol radv {
	prefix 2001:0DB8:2000::/48 {
		autonomous off;		# Do not autoconfigure
	};

	rdnss 2001:0DB8:1234::10;	# Short form of RDNSS

	rdnss {
		lifetime mult 10;
		ns 2001:0DB8:1234::11;
		ns 2001:0DB8:1234::12;
	};

	dnssl {
		lifetime 3600;
		domain "abc.com";
		domain "xyz.com";
	};
}
</code>

Loading