OpenBSD src changes summary for 2017-08-21 ==========================================
distrib/sets distrib/syspatch etc/mtree/4.4BSD.dist etc/rc etc/signify/openbsd-59-base.pub etc/signify/openbsd-59-fw.pub etc/signify/openbsd-59-pkg.pub etc/signify/openbsd-63-base.pub gnu/usr.bin/cvs lib/libfuse lib/libssl libexec/reorder_kernel sbin/slaacd share/man sys/arch/armv7/stand/efiboot sys/arch/i386/i386 sys/arch/i386/include sys/dev/fdt sys/dev/ic sys/dev/usb sys/kern usr.bin/calendar usr.bin/cvs usr.bin/m4 usr.bin/mandoc usr.bin/passwd usr.bin/sendbug usr.bin/time usr.bin/tmux usr.bin/tput usr.bin/xinstall usr.sbin/bgpd usr.sbin/ifstated usr.sbin/radiusd == distrib =========================================================== 01/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/distrib sets ~ lists/comp/mi > sync (jsg@) ~ lists/base/mi ~ lists/comp/mi > sync (deraadt@) ~ lists/base/mi > Move the kernel relinking code from /etc/rc into a seperate script > /usr/libexec/reorder_kernel. Requested by ajacoutot@ to be able to > relink the kernel from within syspatch(8). > OK deraadt@ tb@ (rpe@) syspatch + README > The syspatch(8) build system will eventually be properly documented in its > own > man(1) page but until things settle and the framework is robust, this file > will > be used as a quick reminder. > ok robert@ (ajacoutot@) ~ diff.sh > Catch non existent files (in case a syspatch would _add_ a new file). > (ajacoutot@) ~ bsd.syspatch.mk > Kernel syspatches will now only contain the differing object files. > The syspatch(8) utility will be modified accordingly to relink the kernel > at the > end of its run (not done yet, still WIP). That will give us KARL and much > smaller patches. > Idea from deraadt@ > OK robert@ (ajacoutot@) ~ bsd.syspatch.mk > No need to explicitely add patch.sig to the plist, diff.sh will now pick it > up properly. (ajacoutot@) ~ diff.sh > Add a comment about why we need to ignore the timestamps on perl man pages > (Pod::Man adds the current date to the manuals). > ok robert@ (ajacoutot@) == etc =============================================================== 02/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/etc mtree/4.4BSD.dist ~ mtree/4.4BSD.dist > add basedir of the kernel link-kit > requested by ajacoutot@ > OK tb@ (rpe@) rc ~ rc > Move the kernel relinking code from /etc/rc into a seperate script > /usr/libexec/reorder_kernel. Requested by ajacoutot@ to be able to > relink the kernel from within syspatch(8). > OK deraadt@ tb@ (rpe@) signify/openbsd-59-base.pub - signify/openbsd-59-base.pub > 5.9 pubkeys no longer needed (deraadt@) signify/openbsd-59-fw.pub - signify/openbsd-59-fw.pub > 5.9 pubkeys no longer needed (deraadt@) signify/openbsd-59-pkg.pub - signify/openbsd-59-pkg.pub > 5.9 pubkeys no longer needed (deraadt@) signify/openbsd-63-base.pub + signify/openbsd-63-base.pub > add 6.3 base key (deraadt@) == gnu =============================================================== 03/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/gnu usr.bin/cvs ~ src/client.c > When executing ssh, use "--" to indicate end of arguments before the > host name. Adapted from a MirBSD diff by Thorsten Glaser. (millert@) == lib =============================================================== 04/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib libfuse ~ fuse.c > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(), > in case the parent process was started with a dangling child. This style > ensures any potential parent:child interlock isn't disrupted due to the > "wrong" child being waited on first. Then the other other childs can > safely > zombie. > ok millert jca brynet (deraadt@) libssl ~ man/SSL_CTX_add_session.3 > Delete non-existent functions SSL_add_session() and SSL_remove_session() > and > clarify that SSL_CTX_remove_session(3) marks the session as non-resumable. > From Rich Salz <rsalz at openssl dot org> > via OpenSSL commit 1722496f Jun 8 15:18:38 2017 -0400 > and from Matt Caswell <matt at openssl dot org> > via OpenSSL commit b8964668 Apr 26 15:16:18 2017 +0100. (schwarze@) ~ man/SSL_CTX_flush_sessions.3 > Delete non-existent function SSL_flush_sessions(); > from Rich Salz <rsalz at openssl dot org> > via OpenSSL commit 1722496f Jun 8 15:18:38 2017 -0400. (schwarze@) ~ man/SSL_CTX_set_alpn_select_cb.3 > Mention three functions related to protocol selection by the client > that are deprecated no-ops in LibreSSL, but that OpenSSL explicitly > documented on April 19, 2017, without deprecating them. (schwarze@) ~ man/SSL_CTX_set_msg_callback.3 > Selectively merge OpenSSL commit e091367d May 5 11:56:45 2017 +0100 > from Matt Caswell <matt at openssl dot org>. > In particular, stop talking about SSL 2.0 and SSL 3.0, > but do not start talking about TLS 1.3 just yet. (schwarze@) ~ man/SSL_CTX_set_tlsext_servername_callback.3 > merge the applicable parts of SSL_set_tlsext_host_name(3) documentation; > from Paul Yang <yang dot yang at baishancloud dot com> > via OpenSSL commit 190b9a03 Jun 28 15:46:13 2017 +0800 (schwarze@) ~ man/Makefile ~ man/ssl.3 + man/SSL_export_keying_material.3 > import SSL_export_keying_material(3) from OpenSSL (schwarze@) == libexec =========================================================== 05/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/libexec reorder_kernel + Makefile + reorder_kernel.sh > Move the kernel relinking code from /etc/rc into a seperate script > /usr/libexec/reorder_kernel. Requested by ajacoutot@ to be able to > relink the kernel from within syspatch(8). > OK deraadt@ tb@ (rpe@) == sbin ============================================================== 06/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sbin slaacd ~ engine.c ~ slaacd.c ~ slaacd.h > Move sin6_to_str() to slaacd.c so that it can be used in more > places. While here do not compile it for the ramdisk. (florian@) ~ frontend.c > s/xflagssock/ioctlsock/ since the socket is (going to be) used for > more. (florian@) == share ============================================================= 07/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/share man ~ man9/rasops.9 > Document the newly introduced RI_ROTATE_CCW flag. > OK kettenis@ (fcambus@) == sys =============================================================== 08/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys arch/armv7/stand/efiboot ~ conf.c ~ efiboot.c > Pass the address of the EFI system table and the EFI memory map through > properties in the /chosen node of the FDT. The properties match the ones > used by Linux (see Documentation/arm/uefi.txt in the Linux kernel source > tree) but with the "linux," prefix replaced by "openbsd,". > While there, reduce the diffs to the arm64 efiboot. > ok tom@, jsg@ (kettenis@) arch/i386/i386 ~ vmm.c > vmm (i386): Move CPUID masks to vmmvar.h > My previous commit to restrict vm migration broke vmd for i386. This fixes > it. > ok mlarkin@ (pd@) arch/i386/include ~ vmmvar.h > vmm (i386): Move CPUID masks to vmmvar.h > My previous commit to restrict vm migration broke vmd for i386. This fixes > it. > ok mlarkin@ (pd@) dev/fdt ~ rkclock.c ~ rkclock_clocks.h > Add RK3399 CPU core related clocks. Fix RK3399 SD/MMC controller clock. > For now, expose the clock speed of the Cortex-A53 cores through the > hw.cupseed sysctl. (kettenis@) dev/ic ~ rtwn.c > Fix the build when RTWN_DEBUG is defined. > ok kettenis@ stsp@ (jsg@) ~ ahci.c ~ ahcivar.h > Split up ahci_port_portreset into a few smaller bits, and also slightly > adjust port multiplier detection so it doesn't call ahci_port_portreset > again directly, but instead restarts the loop for the current call. > During attach, poll for device detection across all ports until either all > ports have detected a device, or one second has passed, rather than doing > them sequentially. Devices are still attached in order of port number, > so disk unit numbers won't change. > ok visa@ (jmatthew@) dev/usb ~ uvideo.c > Fix off by one in array bounds tests when parsing descriptors. > Coverity CIDs 1452970 1453305. (jsg@) kern ~ kern_pledge.c > Allow SIOCGIFAFLAG_IN6 and SIOCGIFALIFETIME_IN6 ioctls with > pledge("route"). These are read only and expose only minimal kernel > code. > slaacd(8) needs this on startup and when an interface gains the > autoconf6 flag to get lifetime and autoconf information about already > configured addresses. > OK deraadt (florian@) == usr.bin =========================================================== 09/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin calendar ~ io.c > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(), > in case the parent process was started with a dangling child. This style > ensures any potential parent:child interlock isn't disrupted due to the > "wrong" child being waited on first. Then the other other childs can > safely > zombie. > ok millert jca brynet (deraadt@) cvs ~ client.c > When executing ssh, use "--" to indicate end of arguments before the > host name. Adapted from a MirBSD diff by Thorsten Glaser. (millert@) m4 ~ gnum4.c > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(), > in case the parent process was started with a dangling child. This style > ensures any potential parent:child interlock isn't disrupted due to the > "wrong" child being waited on first. Then the other other childs can > safely > zombie. > ok millert jca brynet (deraadt@) mandoc ~ main.c > When the stdout stream gets broken, there is no point in reading > any more input files, and it would be misleading to start a parser, > because that would show randomly truncated text. > Instead, print an error message and exit the program. > Issue found by Leah Neukirchen <leah at vuxu dot org>, who was > surprised to see half a manpage when her /tmp/ overflew. (schwarze@) passwd ~ pwd_check.c > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(), > in case the parent process was started with a dangling child. This style > ensures any potential parent:child interlock isn't disrupted due to the > "wrong" child being waited on first. Then the other other childs can > safely > zombie. > ok millert jca brynet (deraadt@) sendbug ~ sendbug.c > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(), > in case the parent process was started with a dangling child. This style > ensures any potential parent:child interlock isn't disrupted due to the > "wrong" child being waited on first. Then the other other childs can > safely > zombie. > ok millert jca brynet (deraadt@) time ~ time.c > Minor cleanup, joint work with Scott Cheloha <scottcheloha at gmail dot > com>: > * Delete bogus error message and correct exit status when dying from > SIGKILL. > * Prefer warn(3) over perror(3) for clarity. > * Return from main() rather than exit(3). > * Simplify kill(getpid(), ...) to raise(...). > * Drop obvious /* NOTREACHED */. > No objections raised when shown on tech@. (schwarze@) tmux ~ tty.c > Do not emit \r\n to move to column 0 if there are margins, because it > will instead move to the margin left. (nicm@) ~ tty.c > Same as previous for \r alone. (nicm@) tput ~ tput.c > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(), > in case the parent process was started with a dangling child. This style > ensures any potential parent:child interlock isn't disrupted due to the > "wrong" child being waited on first. Then the other other childs can > safely > zombie. > ok millert jca brynet (deraadt@) xinstall ~ xinstall.c > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(), > in case the parent process was started with a dangling child. This style > ensures any potential parent:child interlock isn't disrupted due to the > "wrong" child being waited on first. Then the other other childs can > safely > zombie. > ok millert jca brynet (deraadt@) == usr.sbin ========================================================== 10/10 == http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.sbin bgpd ~ Makefile ~ parse.y ~ pfkey.c > /* $OpenBSD: parse.y,v 1.314 2017/08/12 16:47:50 phessler Exp $ */ > /* > * Copyright (c) 2002, 2003, 2004 Henning Brauer <[email protected]> > * Copyright (c) 2001 Markus Friedl. All rights reserved. > * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. > * Copyright (c) 2001 Theo de Raadt. All rights reserved. > * Copyright (c) 2016 Job Snijders <[email protected]> > * Copyright (c) 2016 Peter Hessler <[email protected]> > * > * 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 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/socket.h> > #include <sys/stat.h> > #include <sys/un.h> > #include <netinet/in.h> > #include <netinet/ip_ipsp.h> > #include <arpa/inet.h> > #include <netmpls/mpls.h> > #include <ctype.h> > #include <err.h> > #include <unistd.h> > #include <errno.h> > #include <limits.h> > #include <stdarg.h> > #include <stdio.h> > #include <string.h> > #include <syslog.h> > #include "bgpd.h" > #include "mrt.h" > #include "session.h" > #include "rde.h" > #include "log.h" > TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); > static struct file { > TAILQ_ENTRY(file) entry; > FILE *stream; > char *name; > int lineno; > int errors; > } *file, *topfile; > struct file *pushfile(const char *, int); > int popfile(void); > int check_file_secrecy(int, const char *); > int yyparse(void); > int yylex(void); > int yyerror(const char *, ...) > __attribute__((__format__ (printf, 1, 2))) > __attribute__((__nonnull__ (1))); > int kw_cmp(const void *, const void *); > int lookup(char *); > int lgetc(int); > int lungetc(int); > int findeol(void); > TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); > struct sym { > TAILQ_ENTRY(sym) entry; > int used; > int persist; > char *nam; > char *val; > }; > int symset(const char *, const char *, int); > char *symget(const char *); > static struct bgpd_config *conf; > static struct network_head *netconf; > static struct peer *peer_l, *peer_l_old; > static struct peer *curpeer; > static struct peer *curgroup; > static struct rdomain *currdom; > static struct filter_head *filter_l; > static struct filter_head *peerfilter_l; > static struct filter_head *groupfilter_l; > static struct filter_rule *curpeer_filter[2]; > static struct filter_rule *curgroup_filter[2]; > static u_int32_t id; > struct filter_rib_l { > struct filter_rib_l *next; > char name[PEER_DESCR_LEN]; > }; > struct filter_peers_l { > struct filter_peers_l *next; > struct filter_peers p; > }; > struct filter_prefix_l { > struct filter_prefix_l *next; > struct filter_prefix p; > }; > struct filter_prefixlen { > enum comp_ops op; > int len_min; > int len_max; > }; > struct filter_as_l { > struct filter_as_l *next; > struct filter_as a; > }; > struct filter_match_l { > struct filter_match m; > struct filter_prefix_l *prefix_l; > struct filter_as_l *as_l; > } fmopts; > struct peer *alloc_peer(void); > struct peer *new_peer(void); > struct peer *new_group(void); > int add_mrtconfig(enum mrt_type, char *, int, struct peer *, > char *); > int add_rib(char *, u_int, u_int16_t); > struct rde_rib *find_rib(char *); > int get_id(struct peer *); > int merge_prefixspec(struct filter_prefix_l *, > struct filter_prefixlen *); > int expand_rule(struct filter_rule *, struct filter_rib_l *, > struct filter_peers_l *, struct filter_match_l *, > struct filter_set_head *); > int str2key(char *, char *, size_t); > int neighbor_consistent(struct peer *); > int merge_filterset(struct filter_set_head *, struct > filter_set *); > void copy_filterset(struct filter_set_head *, > struct filter_set_head *); > void merge_filter_lists(struct filter_head *, struct > filter_head *); > struct filter_rule *get_rule(enum action_types); > int getcommunity(char *); > int parsecommunity(struct filter_community *, char *); > int64_t getlargecommunity(char *); > int parselargecommunity(struct filter_largecommunity *, char > *); > int parsesubtype(char *, int *, int *); > int parseextvalue(char *, u_int32_t *); > int parseextcommunity(struct filter_extcommunity *, char *, > char *); > typedef struct { > union { > int64_t number; > char *string; > struct bgpd_addr addr; > u_int8_t u8; > struct filter_rib_l *filter_rib; > struct filter_peers_l *filter_peers; > struct filter_match_l filter_match; > struct filter_prefix_l *filter_prefix; > struct filter_as_l *filter_as; > struct filter_set *filter_set; > struct filter_set_head *filter_set_head; > struct { > struct bgpd_addr prefix; > u_int8_t len; > } prefix; > struct filter_prefixlen prefixlen; > struct { > u_int8_t enc_alg; > char enc_key[IPSEC_ENC_KEY_LEN]; > u_int8_t enc_key_len; > } encspec; > } v; > int lineno; > } YYSTYPE; > %} > %token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE > %token RDOMAIN RD EXPORTTRGT IMPORTTRGT > %token RDE RIB EVALUATE IGNORE COMPARE > %token GROUP NEIGHBOR NETWORK > %token EBGP IBGP > %token LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART > %token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY > %token DEMOTE ENFORCE NEIGHBORAS REFLECTOR DEPEND DOWN > %token DUMP IN OUT SOCKET RESTRICTED > %token LOG ROUTECOLL TRANSPARENT > %token TCP MD5SIG PASSWORD KEY TTLSECURITY > %token ALLOW DENY MATCH > %token QUICK > %token FROM TO ANY > %token CONNECTED STATIC > %token COMMUNITY EXTCOMMUNITY LARGECOMMUNITY > %token PREFIX PREFIXLEN SOURCEAS TRANSITAS PEERAS DELETE MAXASLEN MAXASSEQ > %token SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF > %token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN > %token ERROR INCLUDE > %token IPSEC ESP AH SPI IKE > %token IPV4 IPV6 > %token QUALIFY VIA > %token NE LE GE XRANGE LONGER > %token <v.string> STRING > %token <v.number> NUMBER > %type <v.number> asnumber as4number as4number_any optnumber > %type <v.number> espah family restart origincode nettype > %type <v.number> yesno inout restricted > %type <v.string> string > %type <v.addr> address > %type <v.prefix> prefix addrspec > %type <v.u8> action quick direction delete > %type <v.filter_rib> filter_rib_h filter_rib_l filter_rib > %type <v.filter_peers> filter_peer filter_peer_l filter_peer_h > %type <v.filter_match> filter_match filter_elm filter_match_h > %type <v.filter_as> filter_as filter_as_l filter_as_h > %type <v.filter_as> filter_as_t filter_as_t_l filter_as_l_h > %type <v.prefixlen> prefixlenop > %type <v.filter_set> filter_set_opt > %type <v.filter_set_head> filter_set filter_set_l > %type <v.filter_prefix> filter_prefix filter_prefix_l > filter_prefix_h > %type <v.filter_prefix> filter_prefix_m > %type <v.u8> unaryop equalityop binaryop filter_as_type > %type <v.encspec> encspec > %% > grammar : /* empty */ > | grammar '\n' > | grammar include '\n' > | grammar conf_main '\n' > | grammar varset '\n' > | grammar rdomain '\n' > | grammar neighbor '\n' > | grammar group '\n' > | grammar filterrule '\n' > | grammar error '\n' { file->errors++; } > ; > asnumber : NUMBER { > /* > * According to iana 65535 and 4294967295 are reserved > * but enforcing this is not duty of the parser. > */ > if ($1 < 0 || $1 > UINT_MAX) { > yyerror("AS too big: max %u", UINT_MAX); > YYERROR; > } > } > as4number : STRING { > const char *errstr; > char *dot; > u_int32_t uvalh = 0, uval; > if ((dot = strchr($1,'.')) != NULL) { > *dot++ = '\0'; > uvalh = strtonum($1, 0, USHRT_MAX, &errstr); > if (errstr) { > yyerror("number %s is %s", $1, errstr); > free($1); > YYERROR; > } > uval = strtonum(dot, 0, USHRT_MAX, &errstr); > if (errstr) { > yyerror("number %s is %s", dot, errstr); > free($1); > YYERROR; > } > free($1); > } else { > yyerror("AS %s is bad", $1); > free($1); > YYERROR; > } > if (uvalh == 0 && uval == AS_TRANS) { > yyerror("AS %u is reserved and may not be used", > AS_TRANS); > YYERROR; > } > $$ = uval | (uvalh << 16); > } > | asnumber { > if ($1 == AS_TRANS) { > yyerror("AS %u is reserved and may not be used", > AS_TRANS); > YYERROR; > } > $$ = $1; > } > ; > as4number_any : STRING { > const char *errstr; > char *dot; > u_int32_t uvalh = 0, uval; > if ((dot = strchr($1,'.')) != NULL) { > *dot++ = '\0'; > uvalh = strtonum($1, 0, USHRT_MAX, &errstr); > if (errstr) { > yyerror("number %s is %s", $1, errstr); > free($1); > YYERROR; > } > uval = strtonum(dot, 0, USHRT_MAX, &errstr); > if (errstr) { > yyerror("number %s is %s", dot, errstr); > free($1); > YYERROR; > } > free($1); > } else { > yyerror("AS %s is bad", $1); > free($1); > YYERROR; > } > $$ = uval | (uvalh << 16); > } > | asnumber { > $$ = $1; > } > ; > string : string STRING { > if (asprintf(&$$, "%s %s", $1, $2) == -1) > fatal("string: asprintf"); > free($1); > free($2); > } > | STRING > ; > yesno : STRING { > if (!strcmp($1, "yes")) > $$ = 1; > else if (!strcmp($1, "no")) > $$ = 0; > else { > yyerror("syntax error, " > "either yes or no expected"); > free($1); > YYERROR; > } > free($1); > } > ; > varset : STRING '=' string { > char *s = $1; > if (cmd_opts & BGPD_OPT_VERBOSE) > printf("%s = \"%s\"\n", $1, $3); > while (*s++) { > if (isspace((unsigned char)*s)) { > yyerror("macro name cannot contain " > "whitespace"); > YYERROR; > } > } > if (symset($1, $3, 0) == -1) > fatal("cannot store variable"); > free($1); > free($3); > } > ; > include : INCLUDE STRING { > struct file *nfile; > if ((nfile = pushfile($2, 1)) == NULL) { > yyerror("failed to include file %s", $2); > free($2); > YYERROR; > } > free($2); > file = nfile; > lungetc('\n'); > } > ; > conf_main : AS as4number { > conf->as = $2; > if ($2 > USHRT_MAX) > conf->short_as = AS_TRANS; > else > conf->short_as = $2; > } > | AS as4number asnumber { > conf->as = $2; > conf->short_as = $3; > } > | ROUTERID address { > if ($2.aid != AID_INET) { > yyerror("router-id must be an IPv4 address"); > YYERROR; > } > conf->bgpid = $2.v4.s_addr; > } > | HOLDTIME NUMBER { > if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) { > yyerror("holdtime must be between %u and %u", > MIN_HOLDTIME, USHRT_MAX); > YYERROR; > } > conf->holdtime = $2; > } > | HOLDTIME YMIN NUMBER { > if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) { > yyerror("holdtime must be between %u and %u", > MIN_HOLDTIME, USHRT_MAX); > YYERROR; > } > conf->min_holdtime = $3; > } > | LISTEN ON address { > struct listen_addr *la; > if ((la = calloc(1, sizeof(struct listen_addr))) == > NULL) > fatal("parse conf_main listen on calloc"); > la->fd = -1; > memcpy(&la->sa, addr2sa(&$3, BGP_PORT), sizeof(la->sa)); > TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); > } > | FIBPRIORITY NUMBER { > if ($2 <= RTP_NONE || $2 > RTP_MAX) { > yyerror("invalid fib-priority"); > YYERROR; > } > conf->fib_priority = $2; > } > | FIBUPDATE yesno { > struct rde_rib *rr; > rr = find_rib("Loc-RIB"); > if (rr == NULL) > fatalx("RTABLE can not find the main RIB!"); > if ($2 == 0) > rr->flags |= F_RIB_NOFIBSYNC; > else > rr->flags &= ~F_RIB_NOFIBSYNC; > } > | ROUTECOLL yesno { > if ($2 == 1) > conf->flags |= BGPD_FLAG_NO_EVALUATE; > else > conf->flags &= ~BGPD_FLAG_NO_EVALUATE; > } > | RDE RIB STRING { > if (add_rib($3, conf->default_tableid, F_RIB_NOFIB)) { > free($3); > YYERROR; > } > free($3); > } > | RDE RIB STRING yesno EVALUATE { > if ($4) { > free($3); > yyerror("bad rde rib definition"); > YYERROR; > } > if (add_rib($3, conf->default_tableid, > F_RIB_NOFIB | F_RIB_NOEVALUATE)) { > free($3); > YYERROR; > } > free($3); > } > | RDE RIB STRING RTABLE NUMBER { > if (add_rib($3, $5, 0)) { > free($3); > YYERROR; > } > free($3); > } > | RDE RIB STRING RTABLE NUMBER FIBUPDATE yesno { > int flags = 0; > if ($7 == 0) > flags = F_RIB_NOFIBSYNC; > if (add_rib($3, $5, flags)) { > free($3); > YYERROR; > } > free($3); > } > | TRANSPARENT yesno { > if ($2 == 1) > conf->flags |= BGPD_FLAG_DECISION_TRANS_AS; > else > conf->flags &= ~BGPD_FLAG_DECISION_TRANS_AS; > } > | LOG STRING { > if (!strcmp($2, "updates")) > conf->log |= BGPD_LOG_UPDATES; > else { > free($2); > YYERROR; > } > free($2); > } > | network > | DUMP STRING STRING optnumber { > int action; > if ($4 < 0 || $4 > INT_MAX) { > yyerror("bad timeout"); > free($2); > free($3); > YYERROR; > } > if (!strcmp($2, "table")) > action = MRT_TABLE_DUMP; > else if (!strcmp($2, "table-mp")) > action = MRT_TABLE_DUMP_MP; > else if (!strcmp($2, "table-v2")) > action = MRT_TABLE_DUMP_V2; > else { > yyerror("unknown mrt dump type"); > free($2); > free($3); > YYERROR; > } > free($2); > if (add_mrtconfig(action, $3, $4, NULL, NULL) == -1) { > free($3); > YYERROR; > } > free($3); > } > | DUMP RIB STRING STRING STRING optnumber { > int action; > if ($6 < 0 || $6 > INT_MAX) { > yyerror("bad timeout"); > free($3); > free($4); > free($5); > YYERROR; > } > if (!strcmp($4, "table")) > action = MRT_TABLE_DUMP; > else if (!strcmp($4, "table-mp")) > action = MRT_TABLE_DUMP_MP; > else if (!strcmp($4, "table-v2")) > action = MRT_TABLE_DUMP_V2; > else { > yyerror("unknown mrt dump type"); > free($3); > free($4); > free($5); > YYERROR; > } > free($4); > if (add_mrtconfig(action, $5, $6, NULL, $3) == -1) { > free($3); > free($5); > YYERROR; > } > free($3); > free($5); > } > | mrtdump > | RDE STRING EVALUATE { > if (!strcmp($2, "route-age")) > conf->flags |= BGPD_FLAG_DECISION_ROUTEAGE; > else { > yyerror("unknown route decision type"); > free($2); > YYERROR; > } > free($2); > } > | RDE STRING IGNORE { > if (!strcmp($2, "route-age")) > conf->flags &= ~BGPD_FLAG_DECISION_ROUTEAGE; > else { > yyerror("unknown route decision type"); > free($2); > YYERROR; > } > free($2); > } > | RDE MED COMPARE STRING { > if (!strcmp($4, "always")) > conf->flags |= BGPD_FLAG_DECISION_MED_ALWAYS; > else if (!strcmp($4, "strict")) > conf->flags &= ~BGPD_FLAG_DECISION_MED_ALWAYS; > else { > yyerror("rde med compare: " > "unknown setting \"%s\"", $4); > free($4); > YYERROR; > } > free($4); > } > | NEXTHOP QUALIFY VIA STRING { > if (!strcmp($4, "bgp")) > conf->flags |= BGPD_FLAG_NEXTHOP_BGP; > else if (!strcmp($4, "default")) > conf->flags |= BGPD_FLAG_NEXTHOP_DEFAULT; > else { > yyerror("nexthop depend on: " > "unknown setting \"%s\"", $4); > free($4); > YYERROR; > } > free($4); > } > | RTABLE NUMBER { > struct rde_rib *rr; > if (ktable_exists($2, NULL) != 1) { > yyerror("rtable id %lld does not exist", $2); > YYERROR; > } > rr = find_rib("Loc-RIB"); > if (rr == NULL) > fatalx("RTABLE can not find the main RIB!"); > rr->rtableid = $2; > } > | CONNECTRETRY NUMBER { > if ($2 > USHRT_MAX || $2 < 1) { > yyerror("invalid connect-retry"); > YYERROR; > } > conf->connectretry = $2; > } > | SOCKET STRING restricted { > if (strlen($2) >= > sizeof(((struct sockaddr_un *)0)->sun_path)) { > yyerror("socket path too long"); > YYERROR; > } > if ($3) { > free(conf->rcsock); > conf->rcsock = $2; > } else { > free(conf->csock); > conf->csock = $2; > } > } > ; > mrtdump : DUMP STRING inout STRING optnumber { > int action; > if ($5 < 0 || $5 > INT_MAX) { > yyerror("bad timeout"); > free($2); > free($4); > YYERROR; > } > if (!strcmp($2, "all")) > action = $3 ? MRT_ALL_IN : MRT_ALL_OUT; > else if (!strcmp($2, "updates")) > action = $3 ? MRT_UPDATE_IN : MRT_UPDATE_OUT; > else { > yyerror("unknown mrt msg dump type"); > free($2); > free($4); > YYERROR; > } > if (add_mrtconfig(action, $4, $5, curpeer, NULL) == > -1) { > free($2); > free($4); > YYERROR; > } > free($2); > free($4); > } > ; > network : NETWORK prefix filter_set { > struct network *n, *m; > if ((n = calloc(1, sizeof(struct network))) == NULL) > fatal("new_network"); > memcpy(&n->net.prefix, &$2.prefix, > sizeof(n->net.prefix)); > n->net.prefixlen = $2.len; > filterset_move($3, &n->net.attrset); > free($3); > TAILQ_FOREACH(m, netconf, entry) { > if (n->net.prefixlen == m->net.prefixlen && > prefix_compare(&n->net.prefix, > &m->net.prefix, n->net.prefixlen) == 0) > yyerror("duplicate prefix " > "in network statement"); > } > TAILQ_INSERT_TAIL(netconf, n, entry); > } > | NETWORK family RTLABEL STRING filter_set { > struct network *n; > if ((n = calloc(1, sizeof(struct network))) == NULL) > fatal("new_network"); > if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) == > -1) { > yyerror("unknown family"); > filterset_free($5); > free($5); > YYERROR; > } > n->net.type = NETWORK_RTLABEL; > n->net.rtlabel = rtlabel_name2id($4); > filterset_move($5, &n->net.attrset); > free($5); > TAILQ_INSERT_TAIL(netconf, n, entry); > } > | NETWORK family nettype filter_set { > struct network *n; > if ((n = calloc(1, sizeof(struct network))) == NULL) > fatal("new_network"); > if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) == > -1) { > yyerror("unknown family"); > filterset_free($4); > free($4); > YYERROR; > } > n->net.type = $3 ? NETWORK_STATIC : NETWORK_CONNECTED; > filterset_move($4, &n->net.attrset); > free($4); > TAILQ_INSERT_TAIL(netconf, n, entry); > } > ; > inout : IN { $$ = 1; } > | OUT { $$ = 0; } > ; > restricted : RESTRICTED { $$ = 1; } > | /* nothing */ { $$ = 0; } > ; > address : STRING { > u_int8_t len; > if (!host($1, &$$, &len)) { > yyerror("could not parse address spec \"%s\"", > $1); > free($1); > YYERROR; > } > free($1); > if (($$.aid == AID_INET && len != 32) || > ($$.aid == AID_INET6 && len != 128)) { > /* unreachable */ > yyerror("got prefixlen %u, expected %u", > len, $$.aid == AID_INET ? 32 : 128); > YYERROR; > } > } > ; > prefix : STRING '/' NUMBER { > char *s; > if ($3 < 0 || $3 > 128) { > yyerror("bad prefixlen %lld", $3); > free($1); > YYERROR; > } > if (asprintf(&s, "%s/%lld", $1, $3) == -1) > fatal(NULL); > free($1); > if (!host(s, &$$.prefix, &$$.len)) { > yyerror("could not parse address \"%s\"", s); > free(s); > YYERROR; > } > free(s); > } > | NUMBER '/' NUMBER { > char *s; > /* does not match IPv6 */ > if ($1 < 0 || $1 > 255 || $3 < 0 || $3 > 32) { > yyerror("bad prefix %lld/%lld", $1, $3); > YYERROR; > } > if (asprintf(&s, "%lld/%lld", $1, $3) == -1) > fatal(NULL); > if (!host(s, &$$.prefix, &$$.len)) { > yyerror("could not parse address \"%s\"", s); > free(s); > YYERROR; > } > free(s); > } > ; > addrspec : address { > memcpy(&$$.prefix, &$1, sizeof(struct bgpd_addr)); > if ($$.prefix.aid == AID_INET) > $$.len = 32; > else > $$.len = 128; > } > | prefix > ; > optnl : '\n' optnl > | > ; > nl : '\n' optnl /* one newline or more */ > ; > optnumber : /* empty */ { $$ = 0; } > | NUMBER > ; > rdomain : RDOMAIN NUMBER optnl '{' optnl { > if (ktable_exists($2, NULL) != 1) { > yyerror("rdomain %lld does not exist", $2); > YYERROR; > } > if (!(currdom = calloc(1, sizeof(struct rdomain)))) > fatal(NULL); > currdom->rtableid = $2; > TAILQ_INIT(&currdom->import); > TAILQ_INIT(&currdom->export); > TAILQ_INIT(&currdom->net_l); > netconf = &currdom->net_l; > } > rdomainopts_l '}' { > /* insert into list */ > SIMPLEQ_INSERT_TAIL(&conf->rdomains, currdom, entry); > currdom = NULL; > netconf = &conf->networks; > } > rdomainopts_l : rdomainopts_l rdomainoptsl > | rdomainoptsl > ; > rdomainoptsl : rdomainopts nl > ; > rdomainopts : RD STRING { > struct filter_extcommunity ext; > u_int64_t rd; > if (parseextcommunity(&ext, "rt", $2) == -1) { > free($2); > YYERROR; > } > free($2); > /* > * RD is almost encode like an ext-community, > * but only almost so convert here. > */ > if (community_ext_conv(&ext, 0, &rd)) { > yyerror("bad encoding of rd"); > YYERROR; > } > rd = betoh64(rd) & 0xffffffffffffULL; > switch (ext.type) { > case EXT_COMMUNITY_TRANS_TWO_AS: > rd |= (0ULL << 48); > break; > case EXT_COMMUNITY_TRANS_IPV4: > rd |= (1ULL << 48); > break; > case EXT_COMMUNITY_TRANS_FOUR_AS: > rd |= (2ULL << 48); > break; > default: > yyerror("bad encoding of rd"); > YYERROR; > } > currdom->rd = htobe64(rd); > } > | EXPORTTRGT STRING STRING { > struct filter_set *set; > if ((set = calloc(1, sizeof(struct filter_set))) == > NULL) > fatal(NULL); > set->type = ACTION_SET_EXT_COMMUNITY; > if (parseextcommunity(&set->action.ext_community, > $2, $3) == -1) { > free($3); > free($2); > free(set); > YYERROR; > } > free($3); > free($2); > TAILQ_INSERT_TAIL(&currdom->export, set, entry); > } > | IMPORTTRGT STRING STRING { > struct filter_set *set; > if ((set = calloc(1, sizeof(struct filter_set))) == > NULL) > fatal(NULL); > set->type = ACTION_SET_EXT_COMMUNITY; > if (parseextcommunity(&set->action.ext_community, > $2, $3) == -1) { > free($3); > free($2); > free(set); > YYERROR; > } > free($3); > free($2); > TAILQ_INSERT_TAIL(&currdom->import, set, entry); > } > | DESCR string { > if (strlcpy(currdom->descr, $2, > sizeof(currdom->descr)) >= > sizeof(currdom->descr)) { > yyerror("descr \"%s\" too long: max %zu", > $2, sizeof(currdom->descr) - 1); > free($2); > YYERROR; > } > free($2); > } > | FIBUPDATE yesno { > if ($2 == 0) > currdom->flags |= F_RIB_NOFIBSYNC; > else > currdom->flags &= ~F_RIB_NOFIBSYNC; > } > | network > | DEPEND ON STRING { > /* XXX this is a hack */ > if (if_nametoindex($3) == 0) { > yyerror("interface %s does not exist", $3); > free($3); > YYERROR; > } > strlcpy(currdom->ifmpe, $3, IFNAMSIZ); > free($3); > if (get_mpe_label(currdom)) { > yyerror("failed to get mpls label from %s", > currdom->ifmpe); > YYERROR; > } > } > ; > neighbor : { curpeer = new_peer(); } > NEIGHBOR addrspec { > memcpy(&curpeer->conf.remote_addr, &$3.prefix, > sizeof(curpeer->conf.remote_addr)); > curpeer->conf.remote_masklen = $3.len; > if (($3.prefix.aid == AID_INET && $3.len != 32) || > ($3.prefix.aid == AID_INET6 && $3.len != 128)) > curpeer->conf.template = 1; > if (curpeer->conf.capabilities.mp[ > curpeer->conf.remote_addr.aid] == -1) > curpeer->conf.capabilities.mp[ > curpeer->conf.remote_addr.aid] = 1; > if (get_id(curpeer)) { > yyerror("get_id failed"); > YYERROR; > } > } > peeropts_h { > if (curpeer_filter[0] != NULL) > TAILQ_INSERT_TAIL(peerfilter_l, > curpeer_filter[0], entry); > if (curpeer_filter[1] != NULL) > TAILQ_INSERT_TAIL(peerfilter_l, > curpeer_filter[1], entry); > curpeer_filter[0] = NULL; > curpeer_filter[1] = NULL; > if (neighbor_consistent(curpeer) == -1) > YYERROR; > curpeer->next = peer_l; > peer_l = curpeer; > curpeer = curgroup; > } > ; > group : GROUP string optnl '{' optnl { > curgroup = curpeer = new_group(); > if (strlcpy(curgroup->conf.group, $2, > sizeof(curgroup->conf.group)) >= > sizeof(curgroup->conf.group)) { > yyerror("group name \"%s\" too long: max %zu", > $2, sizeof(curgroup->conf.group) - 1); > free($2); > YYERROR; > } > free($2); > if (get_id(curgroup)) { > yyerror("get_id failed"); > YYERROR; > } > } > groupopts_l '}' { > if (curgroup_filter[0] != NULL) > TAILQ_INSERT_TAIL(groupfilter_l, > curgroup_filter[0], entry); > if (curgroup_filter[1] != NULL) > TAILQ_INSERT_TAIL(groupfilter_l, > curgroup_filter[1], entry); > curgroup_filter[0] = NULL; > curgroup_filter[1] = NULL; > free(curgroup); > curgroup = NULL; > } > ; > groupopts_l : groupopts_l groupoptsl > | groupoptsl > ; > groupoptsl : peeropts nl > | neighbor nl > | error nl > ; > peeropts_h : '{' optnl peeropts_l '}' > | /* empty */ > ; > peeropts_l : peeropts_l peeroptsl > | peeroptsl > ; > peeroptsl : peeropts nl > ; > peeropts : REMOTEAS as4number { > curpeer->conf.remote_as = $2; > } > | LOCALAS as4number { > curpeer->conf.local_as = $2; > if ($2 > USHRT_MAX) > curpeer->conf.local_short_as = AS_TRANS; > else > curpeer->conf.local_short_as = $2; > } > | LOCALAS as4number asnumber { > curpeer->conf.local_as = $2; > curpeer->conf.local_short_as = $3; > } > | DESCR string { > if (strlcpy(curpeer->conf.descr, $2, > sizeof(curpeer->conf.descr)) >= > sizeof(curpeer->conf.descr)) { > yyerror("descr \"%s\" too long: max %zu", > $2, sizeof(curpeer->conf.descr) - 1); > free($2); > YYERROR; > } > free($2); > } > | LOCALADDR address { > memcpy(&curpeer->conf.local_addr, &$2, > sizeof(curpeer->conf.local_addr)); > } > | MULTIHOP NUMBER { > if ($2 < 2 || $2 > 255) { > yyerror("invalid multihop distance %lld", $2); > YYERROR; > } > curpeer->conf.distance = $2; > } > | PASSIVE { > curpeer->conf.passive = 1; > } > | DOWN { > curpeer->conf.down = 1; > } > | DOWN STRING { > curpeer->conf.down = 1; > if (strlcpy(curpeer->conf.shutcomm, $2, > sizeof(curpeer->conf.shutcomm)) >= > sizeof(curpeer->conf.shutcomm)) { > yyerror("shutdown reason too long"); > free($2); > YYERROR; > } > free($2); > } > | RIB STRING { > if (!find_rib($2)) { > yyerror("rib \"%s\" does not exist.", $2); > free($2); > YYERROR; > } > if (strlcpy(curpeer->conf.rib, $2, > sizeof(curpeer->conf.rib)) >= > sizeof(curpeer->conf.rib)) { > yyerror("rib name \"%s\" too long: max %zu", > $2, sizeof(curpeer->conf.rib) - 1); > free($2); > YYERROR; > } > free($2); > } > | HOLDTIME NUMBER { > if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) { > yyerror("holdtime must be between %u and %u", > MIN_HOLDTIME, USHRT_MAX); > YYERROR; > } > curpeer->conf.holdtime = $2; > } > | HOLDTIME YMIN NUMBER { > if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) { > yyerror("holdtime must be between %u and %u", > MIN_HOLDTIME, USHRT_MAX); > YYERROR; > } > curpeer->conf.min_holdtime = $3; > } > | ANNOUNCE family STRING { > u_int8_t aid, safi; > int8_t val = 1; > if (!strcmp($3, "none")) { > safi = SAFI_UNICAST; > val = 0; > } else if (!strcmp($3, "unicast")) { > safi = SAFI_UNICAST; > } else if (!strcmp($3, "vpn")) { > safi = SAFI_MPLSVPN; > } else { > yyerror("unknown/unsupported SAFI \"%s\"", > $3); > free($3); > YYERROR; > } > free($3); > if (afi2aid($2, safi, &aid) == -1) { > yyerror("unknown AFI/SAFI pair"); > YYERROR; > } > curpeer->conf.capabilities.mp[aid] = val; > } > | ANNOUNCE CAPABILITIES yesno { > curpeer->conf.announce_capa = $3; > } > | ANNOUNCE REFRESH yesno { > curpeer->conf.capabilities.refresh = $3; > } > | ANNOUNCE RESTART yesno { > curpeer->conf.capabilities.grestart.restart = $3; > } > | ANNOUNCE AS4BYTE yesno { > curpeer->conf.capabilities.as4byte = $3; > } > | ANNOUNCE SELF { > curpeer->conf.announce_type = ANNOUNCE_SELF; > } > | ANNOUNCE STRING { > if (!strcmp($2, "self")) > curpeer->conf.announce_type = ANNOUNCE_SELF; > else if (!strcmp($2, "none")) > curpeer->conf.announce_type = ANNOUNCE_NONE; > else if (!strcmp($2, "all")) > curpeer->conf.announce_type = ANNOUNCE_ALL; > else if (!strcmp($2, "default-route")) > curpeer->conf.announce_type = > ANNOUNCE_DEFAULT_ROUTE; > else { > yyerror("invalid announce type"); > free($2); > YYERROR; > } > free($2); > } > | ENFORCE NEIGHBORAS yesno { > if ($3) > curpeer->conf.enforce_as = ENFORCE_AS_ON; > else > curpeer->conf.enforce_as = ENFORCE_AS_OFF; > } > | ENFORCE LOCALAS yesno { > if ($3) > curpeer->conf.enforce_local_as = ENFORCE_AS_ON; > else > curpeer->conf.enforce_local_as = ENFORCE_AS_OFF; > } > | MAXPREFIX NUMBER restart { > if ($2 < 0 || $2 > UINT_MAX) { > yyerror("bad maximum number of prefixes"); > YYERROR; > } > curpeer->conf.max_prefix = $2; > curpeer->conf.max_prefix_restart = $3; > } > | TCP MD5SIG PASSWORD string { > if (curpeer->conf.auth.method) { > yyerror("auth method cannot be redefined"); > free($4); > YYERROR; > } > if (strlcpy(curpeer->conf.auth.md5key, $4, > sizeof(curpeer->conf.auth.md5key)) >= > sizeof(curpeer->conf.auth.md5key)) { > yyerror("tcp md5sig password too long: max %zu", > sizeof(curpeer->conf.auth.md5key) - 1); > free($4); > YYERROR; > } > curpeer->conf.auth.method = AUTH_MD5SIG; > curpeer->conf.auth.md5key_len = strlen($4); > free($4); > } > | TCP MD5SIG KEY string { > if (curpeer->conf.auth.method) { > yyerror("auth method cannot be redefined"); > free($4); > YYERROR; > } > if (str2key($4, curpeer->conf.auth.md5key, > sizeof(curpeer->conf.auth.md5key)) == -1) { > free($4); > YYERROR; > } > curpeer->conf.auth.method = AUTH_MD5SIG; > curpeer->conf.auth.md5key_len = strlen($4) / 2; > free($4); > } > | IPSEC espah IKE { > if (curpeer->conf.auth.method) { > yyerror("auth method cannot be redefined"); > YYERROR; > } > if ($2) > curpeer->conf.auth.method = AUTH_IPSEC_IKE_ESP; > else > curpeer->conf.auth.method = AUTH_IPSEC_IKE_AH; > } > | IPSEC espah inout SPI NUMBER STRING STRING encspec { > u_int32_t auth_alg; > u_int8_t keylen; > if (curpeer->conf.auth.method && > (((curpeer->conf.auth.spi_in && $3 == 1) || > (curpeer->conf.auth.spi_out && $3 == 0)) || > ($2 == 1 && curpeer->conf.auth.method != > AUTH_IPSEC_MANUAL_ESP) || > ($2 == 0 && curpeer->conf.auth.method != > AUTH_IPSEC_MANUAL_AH))) { > yyerror("auth method cannot be redefined"); > free($6); > free($7); > YYERROR; > } > if (!strcmp($6, "sha1")) { > auth_alg = SADB_AALG_SHA1HMAC; > keylen = 20; > } else if (!strcmp($6, "md5")) { > auth_alg = SADB_AALG_MD5HMAC; > keylen = 16; > } else { > yyerror("unknown auth algorithm \"%s\"", $6); > free($6); > free($7); > YYERROR; > } > free($6); > if (strlen($7) / 2 != keylen) { > yyerror("auth key len: must be %u bytes, " > "is %zu bytes", keylen, strlen($7) / 2); > free($7); > YYERROR; > } > if ($2) > curpeer->conf.auth.method = > AUTH_IPSEC_MANUAL_ESP; > else { > if ($8.enc_alg) { > yyerror("\"ipsec ah\" doesn't take " > "encryption keys"); > free($7); > YYERROR; > } > curpeer->conf.auth.method = > AUTH_IPSEC_MANUAL_AH; > } > if ($5 <= SPI_RESERVED_MAX || $5 > UINT_MAX) { > yyerror("bad spi number %lld", $5); > free($7); > YYERROR; > } > if ($3 == 1) { > if (str2key($7, curpeer->conf.auth.auth_key_in, > sizeof(curpeer->conf.auth.auth_key_in)) == > -1) { > free($7); > YYERROR; > } > curpeer->conf.auth.spi_in = $5; > curpeer->conf.auth.auth_alg_in = auth_alg; > curpeer->conf.auth.enc_alg_in = $8.enc_alg; > memcpy(&curpeer->conf.auth.enc_key_in, > &$8.enc_key, > sizeof(curpeer->conf.auth.enc_key_in)); > curpeer->conf.auth.enc_keylen_in = > $8.enc_key_len; > curpeer->conf.auth.auth_keylen_in = keylen; > } else { > if (str2key($7, curpeer->conf.auth.auth_key_out, > sizeof(curpeer->conf.auth.auth_key_out)) == > -1) { > free($7); > YYERROR; > } > curpeer->conf.auth.spi_out = $5; > curpeer->conf.auth.auth_alg_out = auth_alg; > curpeer->conf.auth.enc_alg_out = $8.enc_alg; > memcpy(&curpeer->conf.auth.enc_key_out, > &$8.enc_key, > sizeof(curpeer->conf.auth.enc_key_out)); > curpeer->conf.auth.enc_keylen_out = > $8.enc_key_len; > curpeer->conf.auth.auth_keylen_out = keylen; > } > free($7); > } > | TTLSECURITY yesno { > curpeer->conf.ttlsec = $2; > } > | SET filter_set_opt { > struct filter_rule *r; > r = get_rule($2->type); > if (merge_filterset(&r->set, $2) == -1) > YYERROR; > } > | SET optnl "{" optnl filter_set_l optnl "}" { > struct filter_rule *r; > struct filter_set *s; > while ((s = TAILQ_FIRST($5)) != NULL) { > TAILQ_REMOVE($5, s, entry); > r = get_rule(s->type); > if (merge_filterset(&r->set, s) == -1) > YYERROR; > } > free($5); > } > | mrtdump > | REFLECTOR { > if ((conf->flags & BGPD_FLAG_REFLECTOR) && > conf->clusterid != 0) { > yyerror("only one route reflector " > "cluster allowed"); > YYERROR; > } > conf->flags |= BGPD_FLAG_REFLECTOR; > curpeer->conf.reflector_client = 1; > } > | REFLECTOR address { > if ($2.aid != AID_INET) { > yyerror("route reflector cluster-id must be " > "an IPv4 address"); > YYERROR; > } > if ((conf->flags & BGPD_FLAG_REFLECTOR) && > conf->clusterid != $2.v4.s_addr) { > yyerror("only one route reflector " > "cluster allowed"); > YYERROR; > } > conf->flags |= BGPD_FLAG_REFLECTOR; > curpeer->conf.reflector_client = 1; > conf->clusterid = $2.v4.s_addr; > } > | DEPEND ON STRING { > if (strlcpy(curpeer->conf.if_depend, $3, > sizeof(curpeer->conf.if_depend)) >= > sizeof(curpeer->conf.if_depend)) { > yyerror("interface name \"%s\" too long: " > "max %zu", $3, > sizeof(curpeer->conf.if_depend) - 1); > free($3); > YYERROR; > } > free($3); > } > | DEMOTE STRING { > if (strlcpy(curpeer->conf.demote_group, $2, > sizeof(curpeer->conf.demote_group)) >= > sizeof(curpeer->conf.demote_group)) { > yyerror("demote group name \"%s\" too long: " > "max %zu", $2, > sizeof(curpeer->conf.demote_group) - 1); > free($2); > YYERROR; > } > free($2); > if (carp_demote_init(curpeer->conf.demote_group, > cmd_opts & BGPD_OPT_FORCE_DEMOTE) == -1) { > yyerror("error initializing group \"%s\"", > curpeer->conf.demote_group); > YYERROR; > } > } > | TRANSPARENT yesno { > if ($2 == 1) > curpeer->conf.flags |= PEERFLAG_TRANS_AS; > else > curpeer->conf.flags &= ~PEERFLAG_TRANS_AS; > } > | LOG STRING { > if (!strcmp($2, "updates")) > curpeer->conf.flags |= PEERFLAG_LOG_UPDATES; > else if (!strcmp($2, "no")) > curpeer->conf.flags &= ~PEERFLAG_LOG_UPDATES; > else { > free($2); > YYERROR; > } > free($2); > } > ; > restart : /* nada */ { $$ = 0; } > | RESTART NUMBER { > if ($2 < 1 || $2 > USHRT_MAX) { > yyerror("restart out of range. 1 to %u minutes", > USHRT_MAX); > YYERROR; > } > $$ = $2; > } > ; > family : IPV4 { $$ = AFI_IPv4; } > | IPV6 { $$ = AFI_IPv6; } > ; > nettype : STATIC { $$ = 1; }, > | CONNECTED { $$ = 0; } > ; > espah : ESP { $$ = 1; } > | AH { $$ = 0; } > ; > encspec : /* nada */ { > bzero(&$$, sizeof($$)); > } > | STRING STRING { > bzero(&$$, sizeof($$)); > if (!strcmp($1, "3des") || !strcmp($1, "3des-cbc")) { > $$.enc_alg = SADB_EALG_3DESCBC; > $$.enc_key_len = 21; /* XXX verify */ > } else if (!strcmp($1, "aes") || > !strcmp($1, "aes-128-cbc")) { > $$.enc_alg = SADB_X_EALG_AES; > $$.enc_key_len = 16; > } else { > yyerror("unknown enc algorithm \"%s\"", $1); > free($1); > free($2); > YYERROR; > } > free($1); > if (strlen($2) / 2 != $$.enc_key_len) { > yyerror("enc key length wrong: should be %u " > "bytes, is %zu bytes", > $$.enc_key_len * 2, strlen($2)); > free($2); > YYERROR; > } > if (str2key($2, $$.enc_key, sizeof($$.enc_key)) == -1) { > free($2); > YYERROR; > } > free($2); > } > ; > filterrule : action quick filter_rib_h direction filter_peer_h > filter_match_h filter_set > { > struct filter_rule r; > struct filter_rib_l *rb, *rbnext; > bzero(&r, sizeof(r)); > r.action = $1; > r.quick = $2; > r.dir = $4; > if ($3) { > if (r.dir != DIR_IN) { > yyerror("rib only allowed on \"from\" " > "rules."); > for (rb = $3; rb != NULL; rb = rbnext) { > rbnext = rb->next; > free(rb); > } > YYERROR; > } > } > if (expand_rule(&r, $3, $5, &$6, $7) == -1) > YYERROR; > } > ; > action : ALLOW { $$ = ACTION_ALLOW; } > | DENY { $$ = ACTION_DENY; } > | MATCH { $$ = ACTION_NONE; } > ; > quick : /* empty */ { $$ = 0; } > | QUICK { $$ = 1; } > ; > direction : FROM { $$ = DIR_IN; } > | TO { $$ = DIR_OUT; } > ; > filter_rib_h : /* empty */ { $$ = NULL; } > | RIB filter_rib { $$ = $2; } > | RIB '{' filter_rib_l '}' { $$ = $3; } > filter_rib_l : filter_rib { $$ = $1; } > | filter_rib_l comma filter_rib { > $3->next = $1; > $$ = $3; > } > ; > filter_rib : STRING { > if (!find_rib($1)) { > yyerror("rib \"%s\" does not exist.", $1); > free($1); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_rib_l))) == > NULL) > fatal(NULL); > $$->next = NULL; > if (strlcpy($$->name, $1, sizeof($$->name)) >= > sizeof($$->name)) { > yyerror("rib name \"%s\" too long: " > "max %zu", $1, sizeof($$->name) - 1); > free($1); > free($$); > YYERROR; > } > free($1); > } > ; > filter_peer_h : filter_peer > | '{' filter_peer_l '}' { $$ = $2; } > ; > filter_peer_l : filter_peer { $$ = $1; } > | filter_peer_l comma filter_peer { > $3->next = $1; > $$ = $3; > } > ; > filter_peer : ANY { > if (($$ = calloc(1, sizeof(struct filter_peers_l))) == > NULL) > fatal(NULL); > $$->p.peerid = $$->p.groupid = 0; > $$->next = NULL; > } > | address { > struct peer *p; > if (($$ = calloc(1, sizeof(struct filter_peers_l))) == > NULL) > fatal(NULL); > $$->p.remote_as = $$->p.groupid = $$->p.peerid = 0; > $$->next = NULL; > for (p = peer_l; p != NULL; p = p->next) > if (!memcmp(&p->conf.remote_addr, > &$1, sizeof(p->conf.remote_addr))) { > $$->p.peerid = p->conf.id; > break; > } > if ($$->p.peerid == 0) { > yyerror("no such peer: %s", log_addr(&$1)); > free($$); > YYERROR; > } > } > | AS as4number { > if (($$ = calloc(1, sizeof(struct filter_peers_l))) == > NULL) > fatal(NULL); > $$->p.groupid = $$->p.peerid = 0; > $$->p.remote_as = $2; > } > | GROUP STRING { > struct peer *p; > if (($$ = calloc(1, sizeof(struct filter_peers_l))) == > NULL) > fatal(NULL); > $$->p.remote_as = $$->p.peerid = 0; > $$->next = NULL; > for (p = peer_l; p != NULL; p = p->next) > if (!strcmp(p->conf.group, $2)) { > $$->p.groupid = p->conf.groupid; > break; > } > if ($$->p.groupid == 0) { > yyerror("no such group: \"%s\"", $2); > free($2); > free($$); > YYERROR; > } > free($2); > } > | EBGP { > if (($$ = calloc(1, sizeof(struct filter_peers_l))) == > NULL) > fatal(NULL); > $$->p.ebgp = 1; > } > | IBGP { > if (($$ = calloc(1, sizeof(struct filter_peers_l))) == > NULL) > fatal(NULL); > $$->p.ibgp = 1; > } > ; > filter_prefix_h : IPV4 prefixlenop { > if ($2.op == OP_NONE) > $2.op = OP_GE; > if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == > NULL) > fatal(NULL); > $$->p.addr.aid = AID_INET; > if (merge_prefixspec($$, &$2) == -1) { > free($$); > YYERROR; > } > } > | IPV6 prefixlenop { > if ($2.op == OP_NONE) > $2.op = OP_GE; > if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == > NULL) > fatal(NULL); > $$->p.addr.aid = AID_INET6; > if (merge_prefixspec($$, &$2) == -1) { > free($$); > YYERROR; > } > } > | PREFIX filter_prefix { $$ = $2; } > | PREFIX '{' filter_prefix_m '}' { $$ = $3; } > ; > filter_prefix_m : filter_prefix_l > | '{' filter_prefix_l '}' { $$ = $2; } > | '{' filter_prefix_l '}' filter_prefix_m > { > struct filter_prefix_l *p; > /* merge, both can be lists */ > for (p = $2; p != NULL && p->next != NULL; p = p->next) > ; /* nothing */ > if (p != NULL) > p->next = $4; > $$ = $2; > } > filter_prefix_l : filter_prefix { $$ = $1; } > | filter_prefix_l comma filter_prefix { > $3->next = $1; > $$ = $3; > } > ; > filter_prefix : prefix prefixlenop { > if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == > NULL) > fatal(NULL); > memcpy(&$$->p.addr, &$1.prefix, > sizeof($$->p.addr)); > $$->p.len = $1.len; > if (merge_prefixspec($$, &$2) == -1) { > free($$); > YYERROR; > } > } > ; > filter_as_h : filter_as_t > | '{' filter_as_t_l '}' { $$ = $2; } > ; > filter_as_t_l : filter_as_t > | filter_as_t_l comma filter_as_t { > struct filter_as_l *a; > /* merge, both can be lists */ > for (a = $1; a != NULL && a->next != NULL; a = a->next) > ; /* nothing */ > if (a != NULL) > a->next = $3; > $$ = $1; > } > ; > filter_as_t : filter_as_type filter_as { > $$ = $2; > $$->a.type = $1; > } > | filter_as_type '{' filter_as_l_h '}' { > struct filter_as_l *a; > $$ = $3; > for (a = $$; a != NULL; a = a->next) > a->a.type = $1; > } > ; > filter_as_l_h : filter_as_l > | '{' filter_as_l '}' { $$ = $2; } > | '{' filter_as_l '}' filter_as_l_h > { > struct filter_as_l *a; > /* merge, both can be lists */ > for (a = $2; a != NULL && a->next != NULL; a = a->next) > ; /* nothing */ > if (a != NULL) > a->next = $4; > $$ = $2; > } > ; > filter_as_l : filter_as > | filter_as_l comma filter_as { > $3->next = $1; > $$ = $3; > } > ; > filter_as : as4number_any { > if (($$ = calloc(1, sizeof(struct filter_as_l))) == > NULL) > fatal(NULL); > $$->a.as = $1; > $$->a.op = OP_EQ; > } > | NEIGHBORAS { > if (($$ = calloc(1, sizeof(struct filter_as_l))) == > NULL) > fatal(NULL); > $$->a.flags = AS_FLAG_NEIGHBORAS; > } > | equalityop as4number_any { > if (($$ = calloc(1, sizeof(struct filter_as_l))) == > NULL) > fatal(NULL); > $$->a.op = $1; > $$->a.as = $2; > } > | as4number_any binaryop as4number_any { > if (($$ = calloc(1, sizeof(struct filter_as_l))) == > NULL) > fatal(NULL); > if ($1 >= $3) { > yyerror("start AS is bigger than end"); > YYERROR; > } > $$->a.op = $2; > $$->a.as_min = $1; > $$->a.as_max = $3; > } > ; > filter_match_h : /* empty */ { > bzero(&$$, sizeof($$)); > $$.m.community.as = COMMUNITY_UNSET; > $$.m.large_community.as = COMMUNITY_UNSET; > } > | { > bzero(&fmopts, sizeof(fmopts)); > fmopts.m.community.as = COMMUNITY_UNSET; > fmopts.m.large_community.as = COMMUNITY_UNSET; > } > filter_match { > memcpy(&$$, &fmopts, sizeof($$)); > } > ; > filter_match : filter_elm > | filter_match filter_elm > ; > filter_elm : filter_prefix_h { > if (fmopts.prefix_l != NULL) { > yyerror("\"prefix\" already specified"); > YYERROR; > } > fmopts.prefix_l = $1; > } > | filter_as_h { > if (fmopts.as_l != NULL) { > yyerror("AS filters already specified"); > YYERROR; > } > fmopts.as_l = $1; > } > | MAXASLEN NUMBER { > if (fmopts.m.aslen.type != ASLEN_NONE) { > yyerror("AS length filters already specified"); > YYERROR; > } > if ($2 < 0 || $2 > UINT_MAX) { > yyerror("bad max-as-len %lld", $2); > YYERROR; > } > fmopts.m.aslen.type = ASLEN_MAX; > fmopts.m.aslen.aslen = $2; > } > | MAXASSEQ NUMBER { > if (fmopts.m.aslen.type != ASLEN_NONE) { > yyerror("AS length filters already specified"); > YYERROR; > } > if ($2 < 0 || $2 > UINT_MAX) { > yyerror("bad max-as-seq %lld", $2); > YYERROR; > } > fmopts.m.aslen.type = ASLEN_SEQ; > fmopts.m.aslen.aslen = $2; > } > | COMMUNITY STRING { > if (fmopts.m.community.as != COMMUNITY_UNSET) { > yyerror("\"community\" already specified"); > free($2); > YYERROR; > } > if (parsecommunity(&fmopts.m.community, $2) == -1) { > free($2); > YYERROR; > } > free($2); > } > | LARGECOMMUNITY STRING { > if (fmopts.m.large_community.as != COMMUNITY_UNSET) { > yyerror("\"large-community\" already specified"); > free($2); > YYERROR; > } > if (parselargecommunity(&fmopts.m.large_community, $2) == -1) { > free($2); > YYERROR; > } > free($2); > } > | EXTCOMMUNITY STRING STRING { > if (fmopts.m.ext_community.flags & > EXT_COMMUNITY_FLAG_VALID) { > yyerror("\"ext-community\" already specified"); > free($2); > free($3); > YYERROR; > } > if (parseextcommunity(&fmopts.m.ext_community, > $2, $3) == -1) { > free($2); > free($3); > YYERROR; > } > free($2); > free($3); > } > | NEXTHOP address { > if (fmopts.m.nexthop.flags) { > yyerror("nexthop already specified"); > YYERROR; > } > fmopts.m.nexthop.addr = $2; > fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR; > } > | NEXTHOP NEIGHBOR { > if (fmopts.m.nexthop.flags) { > yyerror("nexthop already specified"); > YYERROR; > } > fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR; > } > ; > prefixlenop : /* empty */ { bzero(&$$, sizeof($$)); } > | LONGER { > bzero(&$$, sizeof($$)); > $$.op = OP_GE; > $$.len_min = -1; > } > | PREFIXLEN unaryop NUMBER { > bzero(&$$, sizeof($$)); > if ($3 < 0 || $3 > 128) { > yyerror("prefixlen must be >= 0 and <= 128"); > YYERROR; > } > if ($2 == OP_GT && $3 == 0) { > yyerror("prefixlen must be > 0"); > YYERROR; > } > $$.op = $2; > $$.len_min = $3; > } > | PREFIXLEN NUMBER binaryop NUMBER { > bzero(&$$, sizeof($$)); > if ($2 < 0 || $2 > 128 || $4 < 0 || $4 > 128) { > yyerror("prefixlen must be < 128"); > YYERROR; > } > if ($2 >= $4) { > yyerror("start prefixlen is bigger than end"); > YYERROR; > } > $$.op = $3; > $$.len_min = $2; > $$.len_max = $4; > } > ; > filter_as_type : AS { $$ = AS_ALL; } > | SOURCEAS { $$ = AS_SOURCE; } > | TRANSITAS { $$ = AS_TRANSIT; } > | PEERAS { $$ = AS_PEER; } > ; > filter_set : /* empty */ { $$ = > NULL; } > | SET filter_set_opt { > if (($$ = calloc(1, sizeof(struct filter_set_head))) == > NULL) > fatal(NULL); > TAILQ_INIT($$); > TAILQ_INSERT_TAIL($$, $2, entry); > } > | SET optnl "{" optnl filter_set_l optnl "}" { $$ = $5; } > ; > filter_set_l : filter_set_l comma filter_set_opt { > $$ = $1; > if (merge_filterset($$, $3) == 1) > YYERROR; > } > | filter_set_opt { > if (($$ = calloc(1, sizeof(struct filter_set_head))) == > NULL) > fatal(NULL); > TAILQ_INIT($$); > TAILQ_INSERT_TAIL($$, $1, entry); > } > ; > delete : /* empty */ { $$ = 0; } > | DELETE { $$ = 1; } > ; > filter_set_opt : LOCALPREF NUMBER { > if ($2 < -INT_MAX || $2 > UINT_MAX) { > yyerror("bad localpref %lld", $2); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > if ($2 >= 0) { > $$->type = ACTION_SET_LOCALPREF; > $$->action.metric = $2; > } else { > $$->type = ACTION_SET_RELATIVE_LOCALPREF; > $$->action.relative = $2; > } > } > | LOCALPREF '+' NUMBER { > if ($3 < 0 || $3 > INT_MAX) { > yyerror("bad localpref +%lld", $3); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_RELATIVE_LOCALPREF; > $$->action.relative = $3; > } > | LOCALPREF '-' NUMBER { > if ($3 < 0 || $3 > INT_MAX) { > yyerror("bad localpref -%lld", $3); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_RELATIVE_LOCALPREF; > $$->action.relative = -$3; > } > | MED NUMBER { > if ($2 < -INT_MAX || $2 > UINT_MAX) { > yyerror("bad metric %lld", $2); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > if ($2 >= 0) { > $$->type = ACTION_SET_MED; > $$->action.metric = $2; > } else { > $$->type = ACTION_SET_RELATIVE_MED; > $$->action.relative = $2; > } > } > | MED '+' NUMBER { > if ($3 < 0 || $3 > INT_MAX) { > yyerror("bad metric +%lld", $3); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_RELATIVE_MED; > $$->action.relative = $3; > } > | MED '-' NUMBER { > if ($3 < 0 || $3 > INT_MAX) { > yyerror("bad metric -%lld", $3); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_RELATIVE_MED; > $$->action.relative = -$3; > } > | METRIC NUMBER { /* alias for MED */ > if ($2 < -INT_MAX || $2 > UINT_MAX) { > yyerror("bad metric %lld", $2); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > if ($2 >= 0) { > $$->type = ACTION_SET_MED; > $$->action.metric = $2; > } else { > $$->type = ACTION_SET_RELATIVE_MED; > $$->action.relative = $2; > } > } > | METRIC '+' NUMBER { > if ($3 < 0 || $3 > INT_MAX) { > yyerror("bad metric +%lld", $3); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_RELATIVE_MED; > $$->action.metric = $3; > } > | METRIC '-' NUMBER { > if ($3 < 0 || $3 > INT_MAX) { > yyerror("bad metric -%lld", $3); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_RELATIVE_MED; > $$->action.relative = -$3; > } > | WEIGHT NUMBER { > if ($2 < -INT_MAX || $2 > UINT_MAX) { > yyerror("bad weight %lld", $2); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > if ($2 > 0) { > $$->type = ACTION_SET_WEIGHT; > $$->action.metric = $2; > } else { > $$->type = ACTION_SET_RELATIVE_WEIGHT; > $$->action.relative = $2; > } > } > | WEIGHT '+' NUMBER { > if ($3 < 0 || $3 > INT_MAX) { > yyerror("bad weight +%lld", $3); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_RELATIVE_WEIGHT; > $$->action.relative = $3; > } > | WEIGHT '-' NUMBER { > if ($3 < 0 || $3 > INT_MAX) { > yyerror("bad weight -%lld", $3); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_RELATIVE_WEIGHT; > $$->action.relative = -$3; > } > | NEXTHOP address { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_NEXTHOP; > memcpy(&$$->action.nexthop, &$2, > sizeof($$->action.nexthop)); > } > | NEXTHOP BLACKHOLE { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_NEXTHOP_BLACKHOLE; > } > | NEXTHOP REJECT { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_NEXTHOP_REJECT; > } > | NEXTHOP NOMODIFY { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_NEXTHOP_NOMODIFY; > } > | NEXTHOP SELF { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_NEXTHOP_SELF; > } > | PREPEND_SELF NUMBER { > if ($2 < 0 || $2 > 128) { > yyerror("bad number of prepends"); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_PREPEND_SELF; > $$->action.prepend = $2; > } > | PREPEND_PEER NUMBER { > if ($2 < 0 || $2 > 128) { > yyerror("bad number of prepends"); > YYERROR; > } > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_PREPEND_PEER; > $$->action.prepend = $2; > } > | PFTABLE STRING { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_PFTABLE; > if (!(cmd_opts & BGPD_OPT_NOACTION) && > pftable_exists($2) != 0) { > yyerror("pftable name does not exist"); > free($2); > free($$); > YYERROR; > } > if (strlcpy($$->action.pftable, $2, > sizeof($$->action.pftable)) >= > sizeof($$->action.pftable)) { > yyerror("pftable name too long"); > free($2); > free($$); > YYERROR; > } > if (pftable_add($2) != 0) { > yyerror("Couldn't register table"); > free($2); > free($$); > YYERROR; > } > free($2); > } > | RTLABEL STRING { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_RTLABEL; > if (strlcpy($$->action.rtlabel, $2, > sizeof($$->action.rtlabel)) >= > sizeof($$->action.rtlabel)) { > yyerror("rtlabel name too long"); > free($2); > free($$); > YYERROR; > } > free($2); > } > | COMMUNITY delete STRING { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > if ($2) > $$->type = ACTION_DEL_COMMUNITY; > else > $$->type = ACTION_SET_COMMUNITY; > if (parsecommunity(&$$->action.community, $3) == -1) { > free($3); > free($$); > YYERROR; > } > free($3); > /* Don't allow setting of any match */ > if (!$2 && ($$->action.community.as == COMMUNITY_ANY || > $$->action.community.type == COMMUNITY_ANY)) { > yyerror("'*' is not allowed in set community"); > free($$); > YYERROR; > } > } > | LARGECOMMUNITY delete STRING { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > if ($2) > $$->type = ACTION_DEL_LARGE_COMMUNITY; > else > $$->type = ACTION_SET_LARGE_COMMUNITY; > if (parselargecommunity(&$$->action.large_community, > $3) == -1) { > free($3); > free($$); > YYERROR; > } > free($3); > /* Don't allow setting of any match */ > if (!$2 && > ($$->action.large_community.as == COMMUNITY_ANY || > $$->action.large_community.ld1 == COMMUNITY_ANY || > $$->action.large_community.ld2 == COMMUNITY_ANY)) { > yyerror("'*' is not allowed in set community"); > free($$); > YYERROR; > } > } > | EXTCOMMUNITY delete STRING STRING { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > if ($2) > $$->type = ACTION_DEL_EXT_COMMUNITY; > else > $$->type = ACTION_SET_EXT_COMMUNITY; > if (parseextcommunity(&$$->action.ext_community, > $3, $4) == -1) { > free($3); > free($4); > free($$); > YYERROR; > } > free($3); > free($4); > } > | ORIGIN origincode { > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) > fatal(NULL); > $$->type = ACTION_SET_ORIGIN; > $$->action.origin = $2; > } > ; > origincode : string { > if (!strcmp($1, "egp")) > $$ = ORIGIN_EGP; > else if (!strcmp($1, "igp")) > $$ = ORIGIN_IGP; > else if (!strcmp($1, "incomplete")) > $$ = ORIGIN_INCOMPLETE; > else { > yyerror("unknown origin \"%s\"", $1); > free($1); > YYERROR; > } > free($1); > }; > comma : "," > | /* empty */ > ; > unaryop : '=' { $$ = OP_EQ; } > | NE { $$ = OP_NE; } > | LE { $$ = OP_LE; } > | '<' { $$ = OP_LT; } > | GE { $$ = OP_GE; } > | '>' { $$ = OP_GT; } > ; > equalityop : '=' { $$ = OP_EQ; } > | NE { $$ = OP_NE; } > ; > binaryop : '-' { $$ = OP_RANGE; } > | XRANGE { $$ = OP_XRANGE; } > ; > %% > struct keywords { > const char *k_name; > int k_val; > }; > int > yyerror(const char *fmt, ...) > { > va_list ap; > char *msg; > file->errors++; > va_start(ap, fmt); > if (vasprintf(&msg, fmt, ap) == -1) > fatalx("yyerror vasprintf"); > va_end(ap); > logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); > free(msg); > return (0); > } > int > kw_cmp(const void *k, const void *e) > { > return (strcmp(k, ((const struct keywords *)e)->k_name)); > } > int > lookup(char *s) > { > /* this has to be sorted always */ > static const struct keywords keywords[] = { > { "AS", AS}, > { "IPv4", IPV4}, > { "IPv6", IPV6}, > { "ah", AH}, > { "allow", ALLOW}, > { "announce", ANNOUNCE}, > { "any", ANY}, > { "as-4byte", AS4BYTE }, > { "blackhole", BLACKHOLE}, > { "capabilities", CAPABILITIES}, > { "community", COMMUNITY}, > { "compare", COMPARE}, > { "connect-retry", CONNECTRETRY}, > { "connected", CONNECTED}, > { "delete", DELETE}, > { "demote", DEMOTE}, > { "deny", DENY}, > { "depend", DEPEND}, > { "descr", DESCR}, > { "down", DOWN}, > { "dump", DUMP}, > { "ebgp", EBGP}, > { "enforce", ENFORCE}, > { "esp", ESP}, > { "evaluate", EVALUATE}, > { "export-target", EXPORTTRGT}, > { "ext-community", EXTCOMMUNITY}, > { "fib-priority", FIBPRIORITY}, > { "fib-update", FIBUPDATE}, > { "from", FROM}, > { "group", GROUP}, > { "holdtime", HOLDTIME}, > { "ibgp", IBGP}, > { "ignore", IGNORE}, > { "ike", IKE}, > { "import-target", IMPORTTRGT}, > { "in", IN}, > { "include", INCLUDE}, > { "inet", IPV4}, > { "inet6", IPV6}, > { "ipsec", IPSEC}, > { "key", KEY}, > { "large-community", LARGECOMMUNITY}, > { "listen", LISTEN}, > { "local-address", LOCALADDR}, > { "local-as", LOCALAS}, > { "localpref", LOCALPREF}, > { "log", LOG}, > { "match", MATCH}, > { "max-as-len", MAXASLEN}, > { "max-as-seq", MAXASSEQ}, > { "max-prefix", MAXPREFIX}, > { "md5sig", MD5SIG}, > { "med", MED}, > { "metric", METRIC}, > { "min", YMIN}, > { "multihop", MULTIHOP}, > { "neighbor", NEIGHBOR}, > { "neighbor-as", NEIGHBORAS}, > { "network", NETWORK}, > { "nexthop", NEXTHOP}, > { "no-modify", NOMODIFY}, > { "on", ON}, > { "or-longer", LONGER}, > { "origin", ORIGIN}, > { "out", OUT}, > { "passive", PASSIVE}, > { "password", PASSWORD}, > { "peer-as", PEERAS}, > { "pftable", PFTABLE}, > { "prefix", PREFIX}, > { "prefixlen", PREFIXLEN}, > { "prepend-neighbor", PREPEND_PEER}, > { "prepend-self", PREPEND_SELF}, > { "qualify", QUALIFY}, > { "quick", QUICK}, > { "rd", RD}, > { "rde", RDE}, > { "rdomain", RDOMAIN}, > { "refresh", REFRESH }, > { "reject", REJECT}, > { "remote-as", REMOTEAS}, > { "restart", RESTART}, > { "restricted", RESTRICTED}, > { "rib", RIB}, > { "route-collector", ROUTECOLL}, > { "route-reflector", REFLECTOR}, > { "router-id", ROUTERID}, > { "rtable", RTABLE}, > { "rtlabel", RTLABEL}, > { "self", SELF}, > { "set", SET}, > { "socket", SOCKET }, > { "source-as", SOURCEAS}, > { "spi", SPI}, > { "static", STATIC}, > { "tcp", TCP}, > { "to", TO}, > { "transit-as", TRANSITAS}, > { "transparent-as", TRANSPARENT}, > { "ttl-security", TTLSECURITY}, > { "via", VIA}, > { "weight", WEIGHT} > }; > const struct keywords *p; > p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), > sizeof(keywords[0]), kw_cmp); > if (p) > return (p->k_val); > else > return (STRING); > } > #define MAXPUSHBACK 128 > u_char *parsebuf; > int parseindex; > u_char pushback_buffer[MAXPUSHBACK]; > int pushback_index = 0; > int > lgetc(int quotec) > { > int c, next; > if (parsebuf) { > /* Read character from the parsebuffer instead of input. */ > if (parseindex >= 0) { > c = parsebuf[parseindex++]; > if (c != '\0') > return (c); > parsebuf = NULL; > } else > parseindex++; > } > if (pushback_index) > return (pushback_buffer[--pushback_index]); > if (quotec) { > if ((c = getc(file->stream)) == EOF) { > yyerror("reached end of file while parsing " > "quoted string"); > if (file == topfile || popfile() == EOF) > return (EOF); > return (quotec); > } > return (c); > } > while ((c = getc(file->stream)) == '\\') { > next = getc(file->stream); > if (next != '\n') { > c = next; > break; > } > yylval.lineno = file->lineno; > file->lineno++; > } > while (c == EOF) { > if (file == topfile || popfile() == EOF) > return (EOF); > c = getc(file->stream); > } > return (c); > } > int > lungetc(int c) > { > if (c == EOF) > return (EOF); > if (parsebuf) { > parseindex--; > if (parseindex >= 0) > return (c); > } > if (pushback_index < MAXPUSHBACK-1) > return (pushback_buffer[pushback_index++] = c); > else > return (EOF); > } > int > findeol(void) > { > int c; > parsebuf = NULL; > /* skip to either EOF or the first real EOL */ > while (1) { > if (pushback_index) > c = pushback_buffer[--pushback_index]; > else > c = lgetc(0); > if (c == '\n') { > file->lineno++; > break; > } > if (c == EOF) > break; > } > return (ERROR); > } > int > yylex(void) > { > u_char buf[8096]; > u_char *p, *val; > int quotec, next, c; > int token; > top: > p = buf; > while ((c = lgetc(0)) == ' ' || c == '\t') > ; /* nothing */ > yylval.lineno = file->lineno; > if (c == '#') > while ((c = lgetc(0)) != '\n' && c != EOF) > ; /* nothing */ > if (c == '$' && parsebuf == NULL) { > while (1) { > if ((c = lgetc(0)) == EOF) > return (0); > if (p + 1 >= buf + sizeof(buf) - 1) { > yyerror("string too long"); > return (findeol()); > } > if (isalnum(c) || c == '_') { > *p++ = c; > continue; > } > *p = '\0'; > lungetc(c); > break; > } > val = symget(buf); > if (val == NULL) { > yyerror("macro '%s' not defined", buf); > return (findeol()); > } > parsebuf = val; > parseindex = 0; > goto top; > } > switch (c) { > case '\'': > case '"': > quotec = c; > while (1) { > if ((c = lgetc(quotec)) == EOF) > return (0); > if (c == '\n') { > file->lineno++; > continue; > } else if (c == '\\') { > if ((next = lgetc(quotec)) == EOF) > return (0); > if (next == quotec || c == ' ' || c == '\t') > c = next; > else if (next == '\n') { > file->lineno++; > continue; > } else > lungetc(next); > } else if (c == quotec) { > *p = '\0'; > break; > } else if (c == '\0') { > yyerror("syntax error"); > return (findeol()); > } > if (p + 1 >= buf + sizeof(buf) - 1) { > yyerror("string too long"); > return (findeol()); > } > *p++ = c; > } > yylval.v.string = strdup(buf); > if (yylval.v.string == NULL) > fatal("yylex: strdup"); > return (STRING); > case '!': > next = lgetc(0); > if (next == '=') > return (NE); > lungetc(next); > break; > case '<': > next = lgetc(0); > if (next == '=') > return (LE); > lungetc(next); > break; > case '>': > next = lgetc(0); > if (next == '<') > return (XRANGE); > else if (next == '=') > return (GE); > lungetc(next); > break; > } > #define allowed_to_end_number(x) \ > (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') > if (c == '-' || isdigit(c)) { > do { > *p++ = c; > if ((unsigned)(p-buf) >= sizeof(buf)) { > yyerror("string too long"); > return (findeol()); > } > } while ((c = lgetc(0)) != EOF && isdigit(c)); > lungetc(c); > if (p == buf + 1 && buf[0] == '-') > goto nodigits; > if (c == EOF || allowed_to_end_number(c)) { > const char *errstr = NULL; > *p = '\0'; > yylval.v.number = strtonum(buf, LLONG_MIN, > LLONG_MAX, &errstr); > if (errstr) { > yyerror("\"%s\" invalid number: %s", > buf, errstr); > return (findeol()); > } > return (NUMBER); > } else { > nodigits: > while (p > buf + 1) > lungetc(*--p); > c = *--p; > if (c == '-') > return (c); > } > } > #define allowed_in_string(x) \ > (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ > x != '{' && x != '}' && x != '<' && x != '>' && \ > x != '!' && x != '=' && x != '/' && x != '#' && \ > x != ',')) > if (isalnum(c) || c == ':' || c == '_' || c == '*') { > do { > *p++ = c; > if ((unsigned)(p-buf) >= sizeof(buf)) { > yyerror("string too long"); > return (findeol()); > } > } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); > lungetc(c); > *p = '\0'; > if ((token = lookup(buf)) == STRING) > if ((yylval.v.string = strdup(buf)) == NULL) > fatal("yylex: strdup"); > return (token); > } > if (c == '\n') { > yylval.lineno = file->lineno; > file->lineno++; > } > if (c == EOF) > return (0); > return (c); > } > int > check_file_secrecy(int fd, const char *fname) > { > struct stat st; > if (fstat(fd, &st)) { > log_warn("cannot stat %s", fname); > return (-1); > } > return (0); > } > struct file * > pushfile(const char *name, int secret) > { > struct file *nfile; > if ((nfile = calloc(1, sizeof(struct file))) == NULL) { > log_warn("malloc"); > return (NULL); > } > if ((nfile->name = strdup(name)) == NULL) { > log_warn("malloc"); > free(nfile); > return (NULL); > } > if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { > log_warn("%s", nfile->name); > free(nfile->name); > free(nfile); > return (NULL); > } > if (secret && > check_file_secrecy(fileno(nfile->stream), nfile->name)) { > fclose(nfile->stream); > free(nfile->name); > free(nfile); > return (NULL); > } > nfile->lineno = 1; > TAILQ_INSERT_TAIL(&files, nfile, entry); > return (nfile); > } > int > popfile(void) > { > struct file *prev; > if ((prev = TAILQ_PREV(file, files, entry)) != NULL) > prev->errors += file->errors; > TAILQ_REMOVE(&files, file, entry); > fclose(file->stream); > free(file->name); > free(file); > file = prev; > return (file ? 0 : EOF); > } > int > parse_config(char *filename, struct bgpd_config *xconf, struct peer > **xpeers) > { > struct sym *sym, *next; > struct peer *p, *pnext; > struct rde_rib *rr; > int errors = 0; > conf = new_config(); > if ((filter_l = calloc(1, sizeof(struct filter_head))) == NULL) > fatal(NULL); > if ((peerfilter_l = calloc(1, sizeof(struct filter_head))) == NULL) > fatal(NULL); > if ((groupfilter_l = calloc(1, sizeof(struct filter_head))) == NULL) > fatal(NULL); > TAILQ_INIT(filter_l); > TAILQ_INIT(peerfilter_l); > TAILQ_INIT(groupfilter_l); > peer_l = NULL; > peer_l_old = *xpeers; > curpeer = NULL; > curgroup = NULL; > id = 1; > netconf = &conf->networks; > add_rib("Adj-RIB-In", conf->default_tableid, > F_RIB_NOFIB | F_RIB_NOEVALUATE); > add_rib("Loc-RIB", conf->default_tableid, F_RIB_LOCAL); > if ((file = pushfile(filename, 1)) == NULL) { > free(conf); > return (-1); > } > topfile = file; > yyparse(); > errors = file->errors; > popfile(); > /* Free macros and check which have not been used. */ > TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { > if ((cmd_opts & BGPD_OPT_VERBOSE2) && !sym->used) > fprintf(stderr, "warning: macro \"%s\" not " > "used\n", sym->nam); > if (!sym->persist) { > free(sym->nam); > free(sym->val); > TAILQ_REMOVE(&symhead, sym, entry); > free(sym); > } > } > if (errors) { > for (p = peer_l; p != NULL; p = pnext) { > pnext = p->next; > free(p); > } > while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) { > SIMPLEQ_REMOVE_HEAD(&ribnames, entry); > free(rr); > } > filterlist_free(filter_l); > filterlist_free(peerfilter_l); > filterlist_free(groupfilter_l); > free_config(conf); > } else { > /* > * Move filter list and static group and peer filtersets > * together. Static group sets come first then peer sets > * last normal filter rules. > */ > merge_filter_lists(conf->filters, groupfilter_l); > merge_filter_lists(conf->filters, peerfilter_l); > merge_filter_lists(conf->filters, filter_l); > errors += mrt_mergeconfig(xconf->mrt, conf->mrt); > errors += merge_config(xconf, conf, peer_l); > *xpeers = peer_l; > for (p = peer_l_old; p != NULL; p = pnext) { > pnext = p->next; > free(p); > } > free(filter_l); > free(peerfilter_l); > free(groupfilter_l); > } > return (errors ? -1 : 0); > } > int > symset(const char *nam, const char *val, int persist) > { > struct sym *sym; > TAILQ_FOREACH(sym, &symhead, entry) { > if (strcmp(nam, sym->nam) == 0) > break; > } > if (sym != NULL) { > if (sym->persist == 1) > return (0); > else { > free(sym->nam); > free(sym->val); > TAILQ_REMOVE(&symhead, sym, entry); > free(sym); > } > } > if ((sym = calloc(1, sizeof(*sym))) == NULL) > return (-1); > sym->nam = strdup(nam); > if (sym->nam == NULL) { > free(sym); > return (-1); > } > sym->val = strdup(val); > if (sym->val == NULL) { > free(sym->nam); > free(sym); > return (-1); > } > sym->used = 0; > sym->persist = persist; > TAILQ_INSERT_TAIL(&symhead, sym, entry); > return (0); > } > int > cmdline_symset(char *s) > { > char *sym, *val; > int ret; > size_t len; > if ((val = strrchr(s, '=')) == NULL) > return (-1); > len = strlen(s) - strlen(val) + 1; > if ((sym = malloc(len)) == NULL) > fatal("cmdline_symset: malloc"); > strlcpy(sym, s, len); > ret = symset(sym, val + 1, 1); > free(sym); > return (ret); > } > char * > symget(const char *nam) > { > struct sym *sym; > TAILQ_FOREACH(sym, &symhead, entry) { > if (strcmp(nam, sym->nam) == 0) { > sym->used = 1; > return (sym->val); > } > } > return (NULL); > } > int > getcommunity(char *s) > { > int val; > const char *errstr; > if (strcmp(s, "*") == 0) > return (COMMUNITY_ANY); > if (strcmp(s, "neighbor-as") == 0) > return (COMMUNITY_NEIGHBOR_AS); > if (strcmp(s, "local-as") == 0) > return (COMMUNITY_LOCAL_AS); > val = strtonum(s, 0, USHRT_MAX, &errstr); > if (errstr) { > yyerror("Community %s is %s (max: %u)", s, errstr, USHRT_MAX); > return (COMMUNITY_ERROR); > } > return (val); > } > int > parsecommunity(struct filter_community *c, char *s) > { > char *p; > int i, as; > /* Well-known communities */ > if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) { > c->as = COMMUNITY_WELLKNOWN; > c->type = COMMUNITY_GRACEFUL_SHUTDOWN; > return (0); > } else if (strcasecmp(s, "NO_EXPORT") == 0) { > c->as = COMMUNITY_WELLKNOWN; > c->type = COMMUNITY_NO_EXPORT; > return (0); > } else if (strcasecmp(s, "NO_ADVERTISE") == 0) { > c->as = COMMUNITY_WELLKNOWN; > c->type = COMMUNITY_NO_ADVERTISE; > return (0); > } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) { > c->as = COMMUNITY_WELLKNOWN; > c->type = COMMUNITY_NO_EXPSUBCONFED; > return (0); > } else if (strcasecmp(s, "NO_PEER") == 0) { > c->as = COMMUNITY_WELLKNOWN; > c->type = COMMUNITY_NO_PEER; > return (0); > } else if (strcasecmp(s, "BLACKHOLE") == 0) { > c->as = COMMUNITY_WELLKNOWN; > c->type = COMMUNITY_BLACKHOLE; > return (0); > } > if ((p = strchr(s, ':')) == NULL) { > yyerror("Bad community syntax"); > return (-1); > } > *p++ = 0; > if ((i = getcommunity(s)) == COMMUNITY_ERROR) > return (-1); > as = i; > if ((i = getcommunity(p)) == COMMUNITY_ERROR) > return (-1); > c->as = as; > c->type = i; > return (0); > } > int64_t > getlargecommunity(char *s) > { > u_int val; > const char *errstr; > if (strcmp(s, "*") == 0) > return (COMMUNITY_ANY); > if (strcmp(s, "neighbor-as") == 0) > return (COMMUNITY_NEIGHBOR_AS); > if (strcmp(s, "local-as") == 0) > return (COMMUNITY_LOCAL_AS); > val = strtonum(s, 0, UINT_MAX, &errstr); > if (errstr) { > yyerror("Large Community %s is %s (max: %u)", > s, errstr, UINT_MAX); > return (COMMUNITY_ERROR); > } > return (val); > } > int > parselargecommunity(struct filter_largecommunity *c, char *s) > { > char *p, *q; > int64_t as, ld1, ld2; > if ((p = strchr(s, ':')) == NULL) { > yyerror("Bad community syntax"); > return (-1); > } > *p++ = 0; > if ((q = strchr(p, ':')) == NULL) { > yyerror("Bad community syntax"); > return (-1); > } > *q++ = 0; > if ((as = getlargecommunity(s)) == COMMUNITY_ERROR) > return (-1); > if ((ld1 = getlargecommunity(p)) == COMMUNITY_ERROR) > return (-1); > if ((ld2 = getlargecommunity(q)) == COMMUNITY_ERROR) > return (-1); > c->as = as; > c->ld1 = ld1; > c->ld2 = ld2; > return (0); > } > int > parsesubtype(char *name, int *type, int *subtype) > { > const struct ext_comm_pairs *cp; > int found = 0; > for (cp = iana_ext_comms; cp->subname != NULL; cp++) { > if (strcmp(name, cp->subname) == 0) { > if (found == 0) { > *type = cp->type; > *subtype = cp->subtype; > } > found++; > } > } > if (found > 1) > *type = -1; > return (found); > } > int > parseextvalue(char *s, u_int32_t *v) > { > const char *errstr; > char *p; > struct in_addr ip; > u_int32_t uvalh = 0, uval; > if ((p = strchr(s, '.')) == NULL) { > /* AS_PLAIN number (4 or 2 byte) */ > uval = strtonum(s, 0, UINT_MAX, &errstr); > if (errstr) { > yyerror("Bad ext-community %s is %s", s, errstr); > return (-1); > } > *v = uval; > if (uval <= USHRT_MAX) > return (EXT_COMMUNITY_TRANS_TWO_AS); > else > return (EXT_COMMUNITY_TRANS_FOUR_AS); > } else if (strchr(p + 1, '.') == NULL) { > /* AS_DOT number (4-byte) */ > *p++ = '\0'; > uvalh = strtonum(s, 0, USHRT_MAX, &errstr); > if (errstr) { > yyerror("Bad ext-community %s is %s", s, errstr); > return (-1); > } > uval = strtonum(p, 0, USHRT_MAX, &errstr); > if (errstr) { > yyerror("Bad ext-community %s is %s", p, errstr); > return (-1); > } > *v = uval | (uvalh << 16); > return (EXT_COMMUNITY_TRANS_FOUR_AS); > } else { > /* more than one dot -> IP address */ > if (inet_aton(s, &ip) == 0) { > yyerror("Bad ext-community %s not parseable", s); > return (-1); > } > *v = ip.s_addr; > return (EXT_COMMUNITY_TRANS_IPV4); > } > return (-1); > } > int > parseextcommunity(struct filter_extcommunity *c, char *t, char *s) > { > const struct ext_comm_pairs *cp; > const char *errstr; > u_int64_t ullval; > u_int32_t uval; > char *p, *ep; > int type, subtype; > if (parsesubtype(t, &type, &subtype) == 0) { > yyerror("Bad ext-community unknown type"); > return (-1); > } > switch (type) { > case -1: > if ((p = strchr(s, ':')) == NULL) { > yyerror("Bad ext-community %s is %s", s, errstr); > return (-1); > } > *p++ = '\0'; > if ((type = parseextvalue(s, &uval)) == -1) > return (-1); > switch (type) { > case EXT_COMMUNITY_TRANS_TWO_AS: > ullval = strtonum(p, 0, UINT_MAX, &errstr); > break; > case EXT_COMMUNITY_TRANS_IPV4: > case EXT_COMMUNITY_TRANS_FOUR_AS: > ullval = strtonum(p, 0, USHRT_MAX, &errstr); > break; > default: > fatalx("parseextcommunity: unexpected result"); > } > if (errstr) { > yyerror("Bad ext-community %s is %s", p, errstr); > return (-1); > } > switch (type) { > case EXT_COMMUNITY_TRANS_TWO_AS: > c->data.ext_as.as = uval; > c->data.ext_as.val = ullval; > break; > case EXT_COMMUNITY_TRANS_IPV4: > c->data.ext_ip.addr.s_addr = uval; > c->data.ext_ip.val = ullval; > break; > case EXT_COMMUNITY_TRANS_FOUR_AS: > c->data.ext_as4.as4 = uval; > c->data.ext_as4.val = ullval; > break; > } > break; > case EXT_COMMUNITY_TRANS_OPAQUE: > case EXT_COMMUNITY_TRANS_EVPN: > errno = 0; > ullval = strtoull(s, &ep, 0); > if (s[0] == '\0' || *ep != '\0') { > yyerror("Bad ext-community bad value"); > return (-1); > } > if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) { > yyerror("Bad ext-community value too big"); > return (-1); > } > c->data.ext_opaq = ullval; > break; > case EXT_COMMUNITY_NON_TRANS_OPAQUE: > if (strcmp(s, "valid") == 0) > c->data.ext_opaq = EXT_COMMUNITY_OVS_VALID; > else if (strcmp(s, "invalid") == 0) > c->data.ext_opaq = EXT_COMMUNITY_OVS_INVALID; > else if (strcmp(s, "not-found") == 0) > c->data.ext_opaq = EXT_COMMUNITY_OVS_NOTFOUND; > else { > yyerror("Bad ext-community %s is %s", s, errstr); > return (-1); > } > break; > } > c->type = type; > c->subtype = subtype; > /* verify type/subtype combo */ > for (cp = iana_ext_comms; cp->subname != NULL; cp++) { > if (cp->type == type && cp->subtype == subtype) { > c->flags |= EXT_COMMUNITY_FLAG_VALID; > return (0); > } > } > yyerror("Bad ext-community bad format for type"); > return (-1); > } > struct peer * > alloc_peer(void) > { > struct peer *p; > u_int8_t i; > if ((p = calloc(1, sizeof(struct peer))) == NULL) > fatal("new_peer"); > /* some sane defaults */ > p->state = STATE_NONE; > p->next = NULL; > p->conf.distance = 1; > p->conf.announce_type = ANNOUNCE_UNDEF; > p->conf.announce_capa = 1; > for (i = 0; i < AID_MAX; i++) > p->conf.capabilities.mp[i] = -1; > p->conf.capabilities.refresh = 1; > p->conf.capabilities.grestart.restart = 1; > p->conf.capabilities.as4byte ~ Makefile ~ pfkey.c > undo unintentional commits (phessler@) ifstated ~ parse.y > Remove unnecessary NULL check and fix an incorrect warning. > Ok jca@ (rob@) radiusd ~ radiusd_bsdauth.c > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(), > in case the parent process was started with a dangling child. This style > ensures any potential parent:child interlock isn't disrupted due to the > "wrong" child being waited on first. Then the other other childs can > safely > zombie. > ok millert jca brynet (deraadt@) =============================================================================== _______________________________________________ odc mailing list [email protected] http://www.squish.net/mailman/listinfo/odc
