? relayd/parse.c ? relayd/relayd.8.manlint ? relayd/relayd.conf.5.manlint ? relayd/y.tab.h ? relayctl/relayctl ? relayctl/relayctl.8.manlint Index: relayd/parse.y =================================================================== RCS file: /cvs/src/usr.sbin/relayd/parse.y,v retrieving revision 1.204 diff -u -p -r1.204 parse.y --- relayd/parse.y 2 May 2015 13:15:24 -0000 1.204 +++ relayd/parse.y 21 Oct 2015 00:28:25 -0000 @@ -173,6 +173,7 @@ typedef struct { %token ROUTER RTLABEL TRANSPARENT TRAP UPDATES URL VIRTUAL WITH TTL RTABLE %token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE PASSWORD ECDH %token EDH CURVE +%token NONE LOCAL CONNECTED STATIC OSPF ISIS RIP BGP DEFAULT %token STRING %token NUMBER %type hostname interface table value optstring @@ -182,6 +183,7 @@ typedef struct { %type redirect_proto relay_proto match %type action ruleaf key_option %type tlsdhparams tlsecdhcurve +%type rtprio %type port %type host %type address @@ -1864,8 +1866,8 @@ router : ROUTER STRING { router = rt; tableport = -1; - } '{' optnl routeopts_l '}' { - if (!router->rt_conf.nroutes) { + } '{' optnl routeropts_l '}' { + if (TAILQ_EMPTY(&router->rt_netroutes)) { yyerror("router %s without routes", router->rt_conf.name); free(router); @@ -1881,11 +1883,11 @@ router : ROUTER STRING { } ; -routeopts_l : routeopts_l routeoptsl nl - | routeoptsl optnl +routeropts_l : routeropts_l routeroptsl nl + | routeroptsl optnl ; -routeoptsl : ROUTE address '/' NUMBER { +routeroptsl : ROUTE address '/' NUMBER { struct netroute *nr; if (router->rt_conf.af == AF_UNSPEC) @@ -1914,15 +1916,15 @@ routeoptsl : ROUTE address '/' NUMBER { YYERROR; } nr->nr_conf.prefixlen = $4; + nr->nr_conf.priority = RTP_DEFAULT; nr->nr_conf.routerid = router->rt_conf.id; nr->nr_router = router; bcopy(&$2.ss, &nr->nr_conf.ss, sizeof($2.ss)); - router->rt_conf.nroutes++; - conf->sc_routecount++; TAILQ_INSERT_TAIL(&router->rt_netroutes, nr, nr_entry); + conf->sc_routecount++; TAILQ_INSERT_TAIL(conf->sc_routes, nr, nr_route); - } + } routeopts_l | FORWARD TO tablespec { free(hashkey); hashkey = NULL; @@ -1950,18 +1952,74 @@ routeoptsl : ROUTE address '/' NUMBER { } router->rt_conf.rtable = $2; } - | RTLABEL STRING { - if (strlcpy(router->rt_conf.label, $2, - sizeof(router->rt_conf.label)) >= - sizeof(router->rt_conf.label)) { - yyerror("route label truncated"); + | DISABLE { rlay->rl_conf.flags |= F_DISABLE; } + | include + ; + +routeopts_l : routeopts_l routeoptsl + | routeoptsl + | /* empty */ + ; + +routeoptsl : INTERFACE STRING { + struct netroute *nr = + TAILQ_LAST(&router->rt_netroutes, netroutelist); + struct netroute_config *c = &nr->nr_conf; + size_t len; + + if (strlen(c->ifname)) { + yyerror("interface name already defined"); free($2); YYERROR; } + + len = strlcpy(c->ifname, $2, sizeof(c->ifname)); free($2); + + if (len >= sizeof(c->ifname)) { + yyerror("interface name truncated"); + YYERROR; + } + } + | PRIORITY rtprio { + struct netroute *nr = + TAILQ_LAST(&router->rt_netroutes, netroutelist); + struct netroute_config *c = &nr->nr_conf; + + c->priority = $2; + } + | RTLABEL STRING { + struct netroute *nr = + TAILQ_LAST(&router->rt_netroutes, netroutelist); + struct netroute_config *c = &nr->nr_conf; + size_t len; + + len = strlcpy(c->label, $2, sizeof(c->label)); + free($2); + + if (len >= sizeof(c->label)) { + yyerror("route label truncated"); + YYERROR; + } + } + ; + +rtprio : NONE { $$ = RTP_NONE; } + | LOCAL { $$ = RTP_LOCAL; } + | CONNECTED { $$ = RTP_CONNECTED; } + | STATIC { $$ = RTP_STATIC; } + | OSPF { $$ = RTP_OSPF; } + | ISIS { $$ = RTP_ISIS; } + | RIP { $$ = RTP_RIP; } + | BGP { $$ = RTP_BGP; } + | DEFAULT { $$ = RTP_DEFAULT; } + | NUMBER { + if ($1 < 0 || $1 > RTP_MAX) { + yyerror("invalid priority value: %d\n", $1); + YYERROR; + } + $$ = $1; } - | DISABLE { rlay->rl_conf.flags |= F_DISABLE; } - | include ; dstaf : /* empty */ { @@ -2039,17 +2097,6 @@ hostflags : RETRY NUMBER { } hst->conf.parentid = $2; } - | PRIORITY NUMBER { - if (hst->conf.priority) { - yyerror("priority already set"); - YYERROR; - } - if ($2 < 0 || $2 > RTP_MAX) { - yyerror("invalid priority value: %d\n", $2); - YYERROR; - } - hst->conf.priority = $2; - } | IP TTL NUMBER { if (hst->conf.ttl) { yyerror("ttl value already set"); @@ -2160,6 +2207,7 @@ lookup(char *s) { "append", APPEND }, { "backlog", BACKLOG }, { "backup", BACKUP }, + { "bgp", BGP }, { "block", BLOCK }, { "buffer", BUFFER }, { "ca", CA }, @@ -2168,8 +2216,10 @@ lookup(char *s) { "check", CHECK }, { "ciphers", CIPHERS }, { "code", CODE }, + { "connected", CONNECTED }, { "cookie", COOKIE }, { "curve", CURVE }, + { "default", DEFAULT }, { "demote", DEMOTE }, { "destination", DESTINATION }, { "digest", DIGEST }, @@ -2192,11 +2242,13 @@ lookup(char *s) { "interface", INTERFACE }, { "interval", INTERVAL }, { "ip", IP }, + { "isis", ISIS }, { "key", KEY }, { "label", LABEL }, { "least-states", LEASTSTATES }, { "listen", LISTEN }, { "loadbalance", LOADBALANCE }, + { "local", LOCAL }, { "log", LOG }, { "lookup", LOOKUP }, { "match", MATCH }, @@ -2205,8 +2257,10 @@ lookup(char *s) { "nat", NAT }, { "no", NO }, { "nodelay", NODELAY }, + { "none", NONE }, { "nothing", NOTHING }, { "on", ON }, + { "ospf", OSPF }, { "params", PARAMS }, { "parent", PARENT }, { "pass", PASS }, @@ -2228,6 +2282,7 @@ lookup(char *s) { "response", RESPONSE }, { "retry", RETRY }, { "return", RETURN }, + { "rip", RIP }, { "roundrobin", ROUNDROBIN }, { "route", ROUTE }, { "router", ROUTER }, @@ -2243,6 +2298,7 @@ lookup(char *s) { "source-hash", SRCHASH }, { "splice", SPLICE }, { "ssl", SSL }, + { "static", STATIC }, { "sticky-address", STICKYADDR }, { "style", STYLE }, { "table", TABLE }, Index: relayd/pfe_route.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/pfe_route.c,v retrieving revision 1.9 diff -u -p -r1.9 pfe_route.c --- relayd/pfe_route.c 22 Jan 2015 17:42:09 -0000 1.9 +++ relayd/pfe_route.c 21 Oct 2015 00:28:25 -0000 @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -39,13 +40,11 @@ struct relay_rtmsg { struct sockaddr_in rm_dst; struct sockaddr_in rm_gateway; struct sockaddr_in rm_netmask; - struct sockaddr_rtlabel rm_label; } u4; struct { struct sockaddr_in6 rm_dst; struct sockaddr_in6 rm_gateway; struct sockaddr_in6 rm_netmask; - struct sockaddr_rtlabel rm_label; } u6; } rm_u; }; @@ -90,7 +89,7 @@ sync_routes(struct relayd *env, struct r rt->rt_conf.name, buf, nr->nr_conf.prefixlen, host->conf.name, HOST_ISUP(host->up) ? "up" : "down", - host->conf.priority); + nr->nr_conf.priority); crt.up = host->up; memcpy(&crt.nr, &nr->nr_conf, sizeof(nr->nr_conf)); @@ -106,44 +105,35 @@ sync_routes(struct relayd *env, struct r int pfe_route(struct relayd *env, struct ctl_netroute *crt) { + struct iovec iov[3]; + int iovcnt = 0; + struct relay_rtmsg rm; struct sockaddr_rtlabel sr; + struct sockaddr_dl sdl; struct sockaddr_storage *gw; struct sockaddr_in *s4; struct sockaddr_in6 *s6; - size_t len = 0; + size_t len; char *gwname; int i = 0; gw = &crt->host.ss; gwname = crt->host.name; - bzero(&rm, sizeof(rm)); - bzero(&sr, sizeof(sr)); + memset(&rm, 0, sizeof(rm)); - rm.rm_hdr.rtm_msglen = len; rm.rm_hdr.rtm_version = RTM_VERSION; rm.rm_hdr.rtm_type = HOST_ISUP(crt->up) ? RTM_ADD : RTM_DELETE; rm.rm_hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY | RTF_MPATH; rm.rm_hdr.rtm_seq = env->sc_rtseq++; - rm.rm_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; + rm.rm_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; rm.rm_hdr.rtm_tableid = crt->rt.rtable; - rm.rm_hdr.rtm_priority = crt->host.priority; - - if (strlen(crt->rt.label)) { - rm.rm_hdr.rtm_addrs |= RTA_LABEL; - sr.sr_len = sizeof(sr); - if (snprintf(sr.sr_label, sizeof(sr.sr_label), - "%s", crt->rt.label) == -1) - goto bad; - } - - if (crt->nr.ss.ss_family == AF_INET) { - rm.rm_hdr.rtm_msglen = len = - sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u4); - - bcopy(&sr, &rm.rm_u.u4.rm_label, sizeof(sr)); + rm.rm_hdr.rtm_priority = crt->nr.priority; + len = sizeof(rm.rm_hdr); + switch (crt->nr.ss.ss_family) { + case AF_INET: s4 = &rm.rm_u.u4.rm_dst; s4->sin_family = AF_INET; s4->sin_len = sizeof(rm.rm_u.u4.rm_dst); @@ -156,7 +146,6 @@ pfe_route(struct relayd *env, struct ctl s4->sin_addr.s_addr = ((struct sockaddr_in *)gw)->sin_addr.s_addr; - rm.rm_hdr.rtm_addrs |= RTA_NETMASK; s4 = &rm.rm_u.u4.rm_netmask; s4->sin_family = AF_INET; s4->sin_len = sizeof(rm.rm_u.u4.rm_netmask); @@ -165,12 +154,11 @@ pfe_route(struct relayd *env, struct ctl htonl(0xffffffff << (32 - crt->nr.prefixlen)); else if (crt->nr.prefixlen < 0) rm.rm_hdr.rtm_flags |= RTF_HOST; - } else if (crt->nr.ss.ss_family == AF_INET6) { - rm.rm_hdr.rtm_msglen = len = - sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u6); - bcopy(&sr, &rm.rm_u.u6.rm_label, sizeof(sr)); + len += sizeof(rm.rm_u.u4); + break; + case AF_INET6: s6 = &rm.rm_u.u6.rm_dst; bcopy(((struct sockaddr_in6 *)&crt->nr.ss), s6, sizeof(*s6)); @@ -182,7 +170,6 @@ pfe_route(struct relayd *env, struct ctl s6->sin6_family = AF_INET6; s6->sin6_len = sizeof(*s6); - rm.rm_hdr.rtm_addrs |= RTA_NETMASK; s6 = &rm.rm_u.u6.rm_netmask; s6->sin6_family = AF_INET6; s6->sin6_len = sizeof(*s6); @@ -195,11 +182,64 @@ pfe_route(struct relayd *env, struct ctl / 8] = 0xff00 >> i; } else if (crt->nr.prefixlen < 0) rm.rm_hdr.rtm_flags |= RTF_HOST; - } else + + len += sizeof(rm.rm_u.u6); + break; + + default: fatal("pfe_route: invalid address family"); + } + + iov[iovcnt].iov_base = &rm; + iov[iovcnt].iov_len = len; + iovcnt++; + + if (strlen(crt->nr.ifname)) { + i = if_nametoindex(crt->nr.ifname); + if (i == 0) { + log_debug("%s: gateway %s: interface %s does not exist", + __func__, gwname, crt->nr.ifname); + return (-1); + } + + memset(&sdl, 0, sizeof(sdl)); + + sdl.sdl_family = AF_LINK; + sdl.sdl_len = sizeof(sdl); + sdl.sdl_index = i; + + rm.rm_hdr.rtm_addrs |= RTA_IFP; + iov[iovcnt].iov_base = &sdl; + iov[iovcnt].iov_len = sizeof(sdl); + iovcnt++; + + len += sizeof(sdl); + } + + if (strlen(crt->nr.label)) { + memset(&sr, 0, sizeof(sr)); + + sr.sr_family = AF_UNSPEC; + sr.sr_len = sizeof(sr); + if (strlcpy(sr.sr_label, crt->nr.label, + sizeof(sr.sr_label)) >= sizeof(sr.sr_label)) { + log_debug("%s: gateway %s: label is too long", + __func__, gwname); + return (-1); + } + + rm.rm_hdr.rtm_addrs |= RTA_LABEL; + iov[iovcnt].iov_base = &sr; + iov[iovcnt].iov_len = sizeof(sr); + iovcnt++; + + len += sizeof(sr); + } + + rm.rm_hdr.rtm_msglen = len; retry: - if (write(env->sc_rtsock, &rm, len) == -1) { + if (writev(env->sc_rtsock, iov, iovcnt) == -1) { switch (errno) { case EEXIST: case ESRCH: Index: relayd/relayd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v retrieving revision 1.164 diff -u -p -r1.164 relayd.conf.5 --- relayd/relayd.conf.5 24 Jul 2015 15:25:08 -0000 1.164 +++ relayd/relayd.conf.5 21 Oct 2015 00:28:25 -0000 @@ -204,12 +204,6 @@ starting with 1; it can be shown with th .Xr relayctl 8 .Ic show summary commands. -.It Ic priority Ar number -Change the route priority used when adding a route. -If not specified, the kernel will set a priority of 8 (RTP_STATIC). -In ordinary use, a fallback route should be added statically with a very -high (e.g. 52) priority. -Unused in all other modes. .It Ic retry Ar number The optional retry option adds a tolerance for failed host checks; the check will be retried for @@ -1378,10 +1372,16 @@ This entry is mandatory and must be spec .It Xo .Ic route .Ar address Ns Li / Ns Ar prefix +.Op Ic interface Ar name +.Op Ic priority Ar number +.Op Ic rtlabel Ar label .Xc Specify the network address and prefix length of a route destination that is reachable via the active gateways. -This entry must be specified at least once in a router directive. +An interface, a priority, and a route label can optionally be specified +for the route. +.Pp +At least one route must be specified in a router directive. .It Ic rtable Ar id Add the routes to the kernel routing table with the specified .Ar id . Index: relayd/relayd.h =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v retrieving revision 1.213 diff -u -p -r1.213 relayd.h --- relayd/relayd.h 18 Jul 2015 16:01:28 -0000 1.213 +++ relayd/relayd.h 21 Oct 2015 00:28:25 -0000 @@ -408,7 +408,6 @@ struct host_config { char name[HOST_NAME_MAX+1]; struct sockaddr_storage ss; int ttl; - int priority; }; struct host { @@ -813,6 +812,9 @@ struct netroute_config { objid_t id; struct sockaddr_storage ss; int prefixlen; + char ifname[IFNAMSIZ]; + char label[RT_LABEL_SIZE]; + int priority; objid_t routerid; }; @@ -830,8 +832,6 @@ struct router_config { objid_t id; u_int32_t flags; char name[HOST_NAME_MAX+1]; - char label[RT_LABEL_SIZE]; - int nroutes; objid_t gwtable; in_port_t gwport; int rtable; Index: relayd/snmp.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/snmp.c,v retrieving revision 1.23 diff -u -p -r1.23 snmp.c --- relayd/snmp.c 22 Jan 2015 17:42:09 -0000 1.23 +++ relayd/snmp.c 21 Oct 2015 00:28:25 -0000 @@ -1380,8 +1380,7 @@ snmp_router(struct relayd *env, struct s break; case 5: /* pf label */ if (snmp_agentx_varbind(resp, oid, - AGENTX_OCTET_STRING, router->rt_conf.label, - strlen(router->rt_conf.label)) == -1) + AGENTX_OCTET_STRING, "", 0) == -1) return (-1); break; case 6: /* rtable */ Index: relayctl/relayctl.c =================================================================== RCS file: /cvs/src/usr.sbin/relayctl/relayctl.c,v retrieving revision 1.53 diff -u -p -r1.53 relayctl.c --- relayctl/relayctl.c 22 Jan 2015 17:42:09 -0000 1.53 +++ relayctl/relayctl.c 21 Oct 2015 00:28:25 -0000 @@ -101,9 +101,24 @@ main(int argc, char *argv[]) int ctl_sock; int done = 0; int n, verbose = 0; + const char *sockfile = RELAYD_SOCKET; + int ch; + + while ((ch = getopt(argc, argv, "s:")) != -1) { + switch (ch) { + case 's': + sockfile = optarg; + break; + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; /* parse options */ - if ((res = parse(argc - 1, argv + 1)) == NULL) + if ((res = parse(argc, argv)) == NULL) exit(1); /* connect to relayd control socket */ @@ -112,7 +127,7 @@ main(int argc, char *argv[]) bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; - (void)strlcpy(sun.sun_path, RELAYD_SOCKET, sizeof(sun.sun_path)); + strlcpy(sun.sun_path, sockfile, sizeof(sun.sun_path)); reconnect: if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) { /* Keep retrying if running in monitor mode */ @@ -121,7 +136,7 @@ main(int argc, char *argv[]) usleep(100); goto reconnect; } - err(1, "connect: %s", RELAYD_SOCKET); + err(1, "connect: %s", sockfile); } if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)