? ktrace.out ? ldpd.conf ? y.output Index: lde.c =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/lde.c,v retrieving revision 1.73 diff -u -p -r1.73 lde.c --- lde.c 4 Mar 2017 00:15:35 -0000 1.73 +++ lde.c 22 Jan 2019 03:33:35 -0000 @@ -480,6 +480,7 @@ lde_dispatch_parent(int fd, short event, LIST_INIT(&nconf->tnbr_list); LIST_INIT(&nconf->nbrp_list); LIST_INIT(&nconf->l2vpn_list); + LIST_INIT(&nconf->auth_list); break; case IMSG_RECONF_IFACE: if ((niface = malloc(sizeof(struct iface))) == NULL) @@ -534,6 +535,18 @@ lde_dispatch_parent(int fd, short event, npw->l2vpn = nl2vpn; LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry); break; + case IMSG_RECONF_CONF_AUTH: { + struct ldp_auth *auth; + + auth = malloc(sizeof(*auth)); + if (auth == NULL) + fatal(NULL); + + memcpy(auth, imsg.data, sizeof(*auth)); + + LIST_INSERT_HEAD(&nconf->auth_list, auth, entry); + break; + } case IMSG_RECONF_END: merge_config(ldeconf, nconf); nconf = NULL; Index: ldpd.c =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/ldpd.c,v retrieving revision 1.62 diff -u -p -r1.62 ldpd.c --- ldpd.c 3 Mar 2017 23:36:06 -0000 1.62 +++ ldpd.c 22 Jan 2019 03:33:35 -0000 @@ -60,6 +60,7 @@ static void merge_nbrps(struct ldpd_co static void merge_l2vpns(struct ldpd_conf *, struct ldpd_conf *); static void merge_l2vpn(struct ldpd_conf *, struct l2vpn *, struct l2vpn *); +static void merge_auths(struct ldpd_conf *, struct ldpd_conf *); struct ldpd_global global; struct ldpd_conf *ldpd_conf; @@ -681,11 +682,18 @@ main_imsg_send_config(struct ldpd_conf * struct l2vpn *l2vpn; struct l2vpn_if *lif; struct l2vpn_pw *pw; + struct ldp_auth *auth; if (main_imsg_compose_both(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) return (-1); + LIST_FOREACH(auth, &xconf->auth_list, entry) { + if (main_imsg_compose_both(IMSG_RECONF_CONF_AUTH, + auth, sizeof(*auth)) == -1) + return (-1); + } + LIST_FOREACH(iface, &xconf->iface_list, entry) { if (main_imsg_compose_both(IMSG_RECONF_IFACE, iface, sizeof(*iface)) == -1) @@ -747,6 +755,7 @@ void merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf) { merge_global(conf, xconf); + merge_auths(conf, xconf); merge_af(AF_INET, &conf->ipv4, &xconf->ipv4); merge_af(AF_INET6, &conf->ipv6, &xconf->ipv6); merge_ifaces(conf, xconf); @@ -971,7 +980,7 @@ merge_nbrps(struct ldpd_conf *conf, stru nbr = nbr_find_ldpid(xn->lsr_id.s_addr); if (nbr) { session_shutdown(nbr, S_SHUTDOWN, 0, 0); - if (pfkey_establish(nbr, xn) == -1) + if (pfkey_establish(conf, nbr) == -1) fatalx("pfkey setup failed"); if (nbr_session_active_role(nbr)) nbr_establish_connection(nbr); @@ -984,9 +993,7 @@ merge_nbrps(struct ldpd_conf *conf, stru if (nbrp->flags != xn->flags || nbrp->keepalive != xn->keepalive || nbrp->gtsm_enabled != xn->gtsm_enabled || - nbrp->gtsm_hops != xn->gtsm_hops || - nbrp->auth.method != xn->auth.method || - strcmp(nbrp->auth.md5key, xn->auth.md5key) != 0) + nbrp->gtsm_hops != xn->gtsm_hops) nbrp_changed = 1; else nbrp_changed = 0; @@ -994,10 +1001,6 @@ merge_nbrps(struct ldpd_conf *conf, stru nbrp->keepalive = xn->keepalive; nbrp->gtsm_enabled = xn->gtsm_enabled; nbrp->gtsm_hops = xn->gtsm_hops; - nbrp->auth.method = xn->auth.method; - strlcpy(nbrp->auth.md5key, xn->auth.md5key, - sizeof(nbrp->auth.md5key)); - nbrp->auth.md5key_len = xn->auth.md5key_len; nbrp->flags = xn->flags; if (ldpd_process == PROC_LDP_ENGINE) { @@ -1005,7 +1008,7 @@ merge_nbrps(struct ldpd_conf *conf, stru if (nbr && nbrp_changed) { session_shutdown(nbr, S_SHUTDOWN, 0, 0); pfkey_remove(nbr); - if (pfkey_establish(nbr, nbrp) == -1) + if (pfkey_establish(conf, nbr) == -1) fatalx("pfkey setup failed"); if (nbr_session_active_role(nbr)) nbr_establish_connection(nbr); @@ -1205,6 +1208,70 @@ merge_l2vpn(struct ldpd_conf *xconf, str l2vpn->br_ifindex = xl->br_ifindex; } +static struct ldp_auth * +auth_find(struct ldpd_conf *conf, const struct ldp_auth *needle) +{ + struct ldp_auth *auth; + + LIST_FOREACH(auth, &conf->auth_list, entry) { + if (needle->md5key_len != auth->md5key_len) + continue; + if (needle->sslen != auth->sslen) + continue; + if (memcmp(needle->md5key, auth->md5key, + needle->md5key_len) != 0) + continue; + if (needle->sslen && memcmp(&needle->ss, &auth->ss, + needle->sslen) != 0) + continue; + + return (auth); + } + + return (NULL); +} + +static void +merge_auths(struct ldpd_conf *conf, struct ldpd_conf *xconf) +{ + struct ldp_auth *auth, *nauth, *xauth; + + /* find deleted auths */ + LIST_FOREACH_SAFE(auth, &conf->auth_list, entry, nauth) { + xauth = auth_find(xconf, auth); + if (xauth == NULL) + continue; + + LIST_REMOVE(auth, entry); + +#ifdef notyet + if (ldpd_process == PROC_LDP_ENGINE) + pfkey_remove(auth); +#endif + + free(auth); + } + + /* find new auths */ + LIST_FOREACH_SAFE(xauth, &xconf->auth_list, entry, nauth) { + LIST_REMOVE(xauth, entry); + + auth = auth_find(conf, xauth); + if (auth == NULL) { + LIST_INSERT_HEAD(&conf->auth_list, xauth, entry); + +#ifdef notyet + if (ldpd_process == PROC_LDP_ENGINE) + pfkey_establish(xauth); +#endif + + continue; + } + + free(xauth); + } +} + struct ldpd_conf * config_new_empty(void) { @@ -1218,6 +1285,7 @@ config_new_empty(void) LIST_INIT(&xconf->tnbr_list); LIST_INIT(&xconf->nbrp_list); LIST_INIT(&xconf->l2vpn_list); + LIST_INIT(&xconf->auth_list); return (xconf); } Index: ldpd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/ldpd.conf.5,v retrieving revision 1.36 diff -u -p -r1.36 ldpd.conf.5 --- ldpd.conf.5 6 Aug 2018 17:25:11 -0000 1.36 +++ ldpd.conf.5 22 Jan 2019 03:33:35 -0000 @@ -72,14 +72,6 @@ and may contain any of those characters. Macro names may not be reserved words (for example, .Ic neighbor ) . Macros are not expanded inside quotes. -.Pp -For example: -.Bd -literal -offset indent -peer1="10.0.1.5" -neighbor $peer1 { - password "openbsd" -} -.Ed .Sh GLOBAL CONFIGURATION Several settings can be configured globally or within a more restricted scope, like per address-family or per interface. @@ -119,6 +111,26 @@ Set the router ID; in combination with l If not specified, the numerically lowest IP address of the router will be used. .Pp .It Xo +.Ic tcp md5sig password Ar secret +.Op Oo Po Ic inet Ns | Ns Ic inet6 Pc Oc Ar address Ns Op / Ns Ar prefix +.Xc +.It Xo +.Ic tcp md5sig key Ar secret +.Op Oo Po Ic inet Ns | Ns Ic inet6 Pc Oc Ar address Ns Op / Ns Ar prefix +.Xc +.It Xo +.Ic no tcp md5sig key Ar secret +.Op Oo Po Ic inet Ns | Ns Ic inet6 Pc Oc Ar address Ns Op / Ns Ar prefix +.Xc +Enable or disable TCP MD5 signatures per RFC 5036. +The shared secret can either be given as a password or hexadecimal key. +An optional address prefix may be specified to scope the key configuration. +.Bd -literal -offset indent +tcp md5sig password mekmitasdigoat +tcp md5sig key deadbeef +.Ed +.Pp +.It Xo .Ic transport-preference .Pq Ic ipv4 Ns | Ns Ic ipv6 .Xc @@ -278,8 +290,6 @@ When GTSM is enabled for this neighbor, a TTL/hop limit of 256 minus this value, ensuring they have not passed through more than the expected number of hops. The default value is 1; valid range is 1\-255. -.It Ic password Ar secret -Enable TCP MD5 signatures per RFC 5036. .El .Sh LAYER 2 VPNS .Xr ldpd 8 Index: ldpd.h =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/ldpd.h,v retrieving revision 1.88 diff -u -p -r1.88 ldpd.h --- ldpd.h 8 Feb 2018 00:17:31 -0000 1.88 +++ ldpd.h 22 Jan 2019 03:33:35 -0000 @@ -128,6 +128,7 @@ enum imsg_type { IMSG_RECONF_L2VPN, IMSG_RECONF_L2VPN_IF, IMSG_RECONF_L2VPN_PW, + IMSG_RECONF_CONF_AUTH, IMSG_RECONF_END }; @@ -300,11 +301,6 @@ struct tnbr { #define F_TNBR_CONFIGURED 0x01 #define F_TNBR_DYNAMIC 0x02 -enum auth_method { - AUTH_NONE, - AUTH_MD5SIG -}; - /* neighbor specific parameters */ struct nbr_params { LIST_ENTRY(nbr_params) entry; @@ -312,11 +308,6 @@ struct nbr_params { uint16_t keepalive; int gtsm_enabled; uint8_t gtsm_hops; - struct { - enum auth_method method; - char md5key[TCP_MD5_KEY_LEN]; - uint8_t md5key_len; - } auth; uint8_t flags; }; #define F_NBRP_KEEPALIVE 0x01 @@ -403,6 +394,19 @@ struct ldpd_af_conf { #define F_LDPD_AF_EXPNULL 0x0004 #define F_LDPD_AF_NO_GTSM 0x0008 +struct ldp_auth { + LIST_ENTRY(ldp_auth) entry; + char md5key[TCP_MD5_KEY_LEN]; + unsigned int md5key_len; + struct sockaddr_storage ss; + socklen_t sslen; + int prefixlen; + uint32_t spi_in; + uint32_t spi_out; +}; + +#define LDP_AUTH_REQUIRED(_a) ((_a)->md5key_len != 0) + struct ldpd_conf { struct in_addr rtr_id; unsigned int rdomain; @@ -412,6 +416,7 @@ struct ldpd_conf { LIST_HEAD(, tnbr) tnbr_list; LIST_HEAD(, nbr_params) nbrp_list; LIST_HEAD(, l2vpn) l2vpn_list; + LIST_HEAD(, ldp_auth) auth_list; uint16_t trans_pref; int flags; }; Index: ldpe.c =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/ldpe.c,v retrieving revision 1.74 diff -u -p -r1.74 ldpe.c --- ldpe.c 4 Mar 2017 00:21:48 -0000 1.74 +++ ldpe.c 22 Jan 2019 03:33:35 -0000 @@ -235,7 +235,6 @@ ldpe_dispatch_main(int fd, short event, static int edisc_socket = -1; static int session_socket = -1; struct nbr *nbr; - struct nbr_params *nbrp; int n, shut = 0; if (event & EV_READ) { @@ -380,8 +379,7 @@ ldpe_dispatch_main(int fd, short event, continue; nbr->laddr = (ldp_af_conf_get(leconf, af))->trans_addr; - nbrp = nbr_params_find(leconf, nbr->id); - if (nbrp && pfkey_establish(nbr, nbrp) == -1) + if (pfkey_establish(nconf, nbr) == -1) fatalx("pfkey setup failed"); if (nbr_session_active_role(nbr)) nbr_establish_connection(nbr); @@ -397,6 +395,7 @@ ldpe_dispatch_main(int fd, short event, LIST_INIT(&nconf->tnbr_list); LIST_INIT(&nconf->nbrp_list); LIST_INIT(&nconf->l2vpn_list); + LIST_INIT(&nconf->auth_list); break; case IMSG_RECONF_IFACE: if ((niface = malloc(sizeof(struct iface))) == NULL) @@ -451,6 +450,19 @@ ldpe_dispatch_main(int fd, short event, npw->l2vpn = nl2vpn; LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry); break; + case IMSG_RECONF_CONF_AUTH: { + struct ldp_auth *auth; + + auth = malloc(sizeof(*auth)); + if (auth == NULL) + fatal(NULL); + + memcpy(auth, imsg.data, sizeof(*auth)); + + LIST_INSERT_HEAD(&nconf->auth_list, auth, entry); + break; + } + case IMSG_RECONF_END: merge_config(leconf, nconf); nconf = NULL; Index: ldpe.h =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/ldpe.h,v retrieving revision 1.75 diff -u -p -r1.75 ldpe.h --- ldpe.h 4 Mar 2017 00:21:48 -0000 1.75 +++ ldpe.h 22 Jan 2019 03:33:35 -0000 @@ -94,13 +94,10 @@ struct nbr { uint16_t keepalive; uint16_t max_pdu_len; - struct { - uint8_t established; - uint32_t spi_in; - uint32_t spi_out; - enum auth_method method; - char md5key[TCP_MD5_KEY_LEN]; - } auth; + uint32_t auth_spi_in; + uint32_t auth_spi_out; + int auth_established; + int flags; }; #define F_NBR_GTSM_NEGOTIATED 0x01 @@ -276,7 +273,7 @@ char *pkt_ptr; /* packet buffer */ /* pfkey.c */ int pfkey_read(int, struct sadb_msg *); -int pfkey_establish(struct nbr *, struct nbr_params *); +int pfkey_establish(struct ldpd_conf *, struct nbr *); int pfkey_remove(struct nbr *); int pfkey_init(void); Index: neighbor.c =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/neighbor.c,v retrieving revision 1.79 diff -u -p -r1.79 neighbor.c --- neighbor.c 4 Mar 2017 00:15:35 -0000 1.79 +++ neighbor.c 22 Jan 2019 03:33:35 -0000 @@ -223,7 +223,6 @@ nbr_new(struct in_addr id, int af, int d uint32_t scope_id) { struct nbr *nbr; - struct nbr_params *nbrp; struct adj *adj; struct pending_conn *pconn; @@ -272,8 +271,7 @@ nbr_new(struct in_addr id, int af, int d evtimer_set(&nbr->init_timeout, nbr_itimeout, nbr); evtimer_set(&nbr->initdelay_timer, nbr_idtimer, nbr); - nbrp = nbr_params_find(leconf, nbr->id); - if (nbrp && pfkey_establish(nbr, nbrp) == -1) + if (pfkey_establish(leconf, nbr) == -1) fatalx("pfkey setup failed"); pconn = pending_conn_find(nbr->af, &nbr->raddr); @@ -581,8 +579,7 @@ nbr_establish_connection(struct nbr *nbr return (-1); } - nbrp = nbr_params_find(leconf, nbr->id); - if (nbrp && nbrp->auth.method == AUTH_MD5SIG) { + if (nbr->auth_established) { if (sysdep.no_pfkey || sysdep.no_md5sig) { log_warnx("md5sig configured but not available"); close(nbr->fd); @@ -610,6 +607,7 @@ nbr_establish_connection(struct nbr *nbr return (-1); } + nbrp = nbr_params_find(leconf, nbr->id); if (nbr_gtsm_check(nbr->fd, nbr, nbrp)) { close(nbr->fd); return (-1); @@ -761,7 +759,6 @@ nbr_params_new(struct in_addr lsr_id) fatal(__func__); nbrp->lsr_id = lsr_id; - nbrp->auth.method = AUTH_NONE; return (nbrp); } Index: packet.c =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/packet.c,v retrieving revision 1.70 diff -u -p -r1.70 packet.c --- packet.c 4 Mar 2017 00:06:10 -0000 1.70 +++ packet.c 22 Jan 2019 03:33:35 -0000 @@ -391,7 +391,7 @@ session_accept_nbr(struct nbr *nbr, int return; } - if (nbrp && nbrp->auth.method == AUTH_MD5SIG) { + if (!LIST_EMPTY(&leconf->auth_list)) { if (sysdep.no_pfkey || sysdep.no_md5sig) { log_warnx("md5sig configured but not available"); close(fd); Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/parse.y,v retrieving revision 1.67 diff -u -p -r1.67 parse.y --- parse.y 1 Nov 2018 00:18:44 -0000 1.67 +++ parse.y 22 Jan 2019 03:33:35 -0000 @@ -1,5 +1,6 @@ /* $OpenBSD: parse.y,v 1.67 2018/11/01 00:18:44 sashan Exp $ */ + /* * Copyright (c) 2013, 2015, 2016 Renato Westphal * Copyright (c) 2004, 2005, 2008 Esben Norby @@ -24,6 +25,8 @@ %{ #include +#include +#include #include #include #include @@ -33,6 +36,8 @@ #include #include #include +#include +#include #include "ldpd.h" #include "ldpe.h" @@ -76,6 +81,7 @@ typedef struct { union { int64_t number; char *string; + struct ldp_auth *auth; } v; int lineno; } YYSTYPE; @@ -107,6 +113,7 @@ static void clear_config(struct ldpd_c static uint32_t get_rtr_id(void); static int get_address(const char *, union ldpd_addr *); static int get_af_address(const char *, int *, union ldpd_addr *); +static int str2key(char *, const char *, int); static struct file *file, *topfile; static struct files files = TAILQ_HEAD_INITIALIZER(files); @@ -135,9 +142,10 @@ static struct config_defaults *defs; %token INTERFACE TNEIGHBOR ROUTERID FIBUPDATE RDOMAIN EXPNULL %token LHELLOHOLDTIME LHELLOINTERVAL %token THELLOHOLDTIME THELLOINTERVAL -%token THELLOACCEPT AF IPV4 IPV6 GTSMENABLE GTSMHOPS +%token THELLOACCEPT AF IPV4 IPV6 INET INET6 GTSMENABLE GTSMHOPS %token KEEPALIVE TRANSADDRESS TRANSPREFERENCE DSCISCOINTEROP -%token NEIGHBOR PASSWORD +%token NEIGHBOR +%token TCP MD5SIG PASSWORD KEY %token L2VPN TYPE VPLS PWTYPE MTU BRIDGE %token ETHERNET ETHERNETTAGGED STATUSTLV CONTROLWORD %token PSEUDOWIRE NEIGHBORID NEIGHBORADDR PWID @@ -148,7 +156,9 @@ static struct config_defaults *defs; %token STRING %token NUMBER %type yesno ldp_af l2vpn_type pw_type +%type optaf optprefixlen %type string +%type auth tcpmd5 optprefix address %% @@ -273,6 +283,9 @@ conf_main : ROUTERID STRING { else conf->flags &= ~F_LDPD_DS_CISCO_INTEROP; } + | auth { + LIST_INSERT_HEAD(&conf->auth_list, $1, entry); + } | af_defaults | iface_defaults | tnbr_defaults @@ -404,6 +417,201 @@ tnbr_defaults : THELLOHOLDTIME NUMBER { } ; +tcpmd5 : TCP MD5SIG PASSWORD STRING { + size_t len; + + $$ = malloc(sizeof(*$$)); + if ($$ == NULL) { + free($4); + yyerror("unable to allocate md5 key"); + YYERROR; + } + + len = strlen($4); + if (len > sizeof($$->md5key)) { + free($$); + free($4); + yyerror("tcp md5sig password too long: " + "max %zu", sizeof($$->md5key)); + YYERROR; + } + + memcpy($$->md5key, $4, len); + $$->md5key_len = len; + + free($4); + } + | TCP MD5SIG KEY STRING { + int len; + + $$ = malloc(sizeof(*$$)); + if ($$ == NULL) { + free($4); + yyerror("unable to allocate md5 key"); + YYERROR; + } + + len = str2key($$->md5key, $4, sizeof($$->md5key)); + if (len == -1) { + free($$); + free($4); + yyerror("invalid hex string"); + YYERROR; + } + if ((size_t)len > sizeof($$->md5key_len)) { + free($$); + free($4); + yyerror("tcp md5sig key too long: %d " + "max %zu", len, sizeof($$->md5key)); + YYERROR; + } + + $$->md5key_len = len; + + free($4); + } + | NO TCP MD5SIG { + $$ = malloc(sizeof(*$$)); + if ($$ == NULL) { + yyerror("unable to allocate no md5 key"); + YYERROR; + } + $$->md5key_len = 0; + } + ; + +optaf : /* empty */ { $$ = AF_UNSPEC; } + | INET { $$ = AF_INET; } + | INET6 { $$ = AF_INET6; } + | ldp_af { $$ = $1; } + ; + +optprefix : optaf string { + char *ch; + int prefix; + struct addrinfo hints, *ai; + int error; + + ch = strchr($2, '/'); + if (ch != NULL) + *ch++ = '\0'; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = $1; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo($2, NULL, &hints, &ai); + if (error != 0) { + yyerror("%s: %s", $2, gai_strerror(error)); + goto free2; + } + + if (ai->ai_addrlen > sizeof($$->ss)) { + yyerror("ad_addrlen too long"); + goto freeai; + } + + switch (ai->ai_family) { + case AF_INET: + prefix = 32; + break; + case AF_INET6: + prefix = 128; + break; + default: + yyerror("unexpected address family"); + goto freeai; + } + + if (ch != NULL) { + const char *errstr = NULL; + + prefix = strtonum(ch, 0, prefix, &errstr); + if (errstr != NULL) { + yyerror("prefix %s: %s", ch, errstr); + goto freeai; + } + } + + $$ = malloc(sizeof(*$$)); + if ($$ == NULL) { + yyerror("unable to allocate address"); + goto freeai; + } + + memcpy(&$$->ss, ai->ai_addr, ai->ai_addrlen); + $$->sslen = ai->ai_addrlen; + $$->prefixlen = prefix; + + freeaddrinfo(ai); + free($2); + break; + +freeai: + freeaddrinfo(ai); +free2: + free($2); + YYERROR; + } + ; + +optprefixlen : /* empty */ { $$ = -1; } + | '/' NUMBER { $$ = $2; } + ; + +optprefix : /* empty */ { + $$ = NULL; + } + | address optprefixlen { + $$ = $1; + $$->prefixlen = $2; + } + ; + +auth : tcpmd5 optprefix { + $$ = $1; + if ($2 != NULL) { + memcpy(&$$->ss, &$2->ss, $2->sslen); + $$->sslen = $2->sslen; + switch ($$->ss.ss_family) { + case AF_INET: + if ($2->prefixlen > 32) { + free($$); + free($2); + yyerror("IPv4 prefix " + "is too long: max 32"); + YYERROR; + } else if ($2->prefixlen == -1) + $$->prefixlen = 32; + else + $$->prefixlen = $2->prefixlen; + break; + case AF_INET6: + if ($2->prefixlen > 128) { + free($$); + free($2); + yyerror("IPv6 prefix " + "is too long: max 128"); + YYERROR; + } else if ($2->prefixlen == -1) + $$->prefixlen = 128; + else + $$->prefixlen = $2->prefixlen; + break; + default: + free($$); + free($2); + yyerror("unhandled address family"); + YYERROR; + } + + free($2); + } else { + $$->sslen = 0; + $$->prefixlen = 0; + } + } + ; + nbr_opts : KEEPALIVE NUMBER { if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) { yyerror("keepalive out of range (%d-%d)", @@ -413,19 +621,6 @@ nbr_opts : KEEPALIVE NUMBER { nbrp->keepalive = $2; nbrp->flags |= F_NBRP_KEEPALIVE; } - | PASSWORD STRING { - if (strlcpy(nbrp->auth.md5key, $2, - sizeof(nbrp->auth.md5key)) >= - sizeof(nbrp->auth.md5key)) { - yyerror("tcp md5sig password too long: max %zu", - sizeof(nbrp->auth.md5key) - 1); - free($2); - YYERROR; - } - nbrp->auth.md5key_len = strlen($2); - nbrp->auth.method = AUTH_MD5SIG; - free($2); - } | GTSMENABLE yesno { nbrp->flags |= F_NBRP_GTSM; nbrp->gtsm_enabled = $2; @@ -835,13 +1030,17 @@ lookup(char *s) {"gtsm-enable", GTSMENABLE}, {"gtsm-hops", GTSMHOPS}, {"include", INCLUDE}, + {"inet", INET}, + {"inet6", INET6}, {"interface", INTERFACE}, {"ipv4", IPV4}, {"ipv6", IPV6}, {"keepalive", KEEPALIVE}, + {"key", KEY}, {"l2vpn", L2VPN}, {"link-hello-holdtime", LHELLOHOLDTIME}, {"link-hello-interval", LHELLOINTERVAL}, + {"md5sig", MD5SIG}, {"mtu", MTU}, {"neighbor", NEIGHBOR}, {"neighbor-addr", NEIGHBORADDR}, @@ -858,6 +1057,7 @@ lookup(char *s) {"targeted-hello-holdtime", THELLOHOLDTIME}, {"targeted-hello-interval", THELLOINTERVAL}, {"targeted-neighbor", TNEIGHBOR}, + {"tcp", TCP}, {"transport-address", TRANSADDRESS}, {"transport-preference", TRANSPREFERENCE}, {"type", TYPE}, @@ -1601,4 +1801,48 @@ get_af_address(const char *s, int *famil } return (-1); +} + +static int +hexchar(int ch) +{ + if (ch >= '0' && ch <= '9') + return (ch - '0'); + if (ch >= 'a' && ch <= 'f') + return (ch - 'a'); + if (ch >= 'A' && ch <= 'F') + return (ch - 'A'); + + return (-1); +} + +static int +str2key(char *dst, const char *src, int dstlen) +{ + int i = 0; + int digit; + + while (*src != '\0') { + digit = hexchar(*src); + if (digit == -1) + return (-1); + + if (i < dstlen) + *dst = digit << 4; + + src++; + if (*src == '\0') + return (-1); + digit = hexchar(*src); + if (digit == -1) + return (-1); + + if (i < dstlen) + *dst |= digit; + + src++; + i++; + } + + return (i); } Index: pfkey.c =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/pfkey.c,v retrieving revision 1.11 diff -u -p -r1.11 pfkey.c --- pfkey.c 18 Apr 2017 02:29:56 -0000 1.11 +++ pfkey.c 22 Jan 2019 03:33:35 -0000 @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -36,7 +37,7 @@ static int pfkey_sa_add(int, union ldpd uint8_t, char *, uint32_t *); static int pfkey_sa_remove(int, union ldpd_addr *, union ldpd_addr *, uint32_t *); -static int pfkey_md5sig_establish(struct nbr *, struct nbr_params *nbrp); +static int pfkey_md5sig_establish(struct nbr *, struct ldp_auth *); static int pfkey_md5sig_remove(struct nbr *); #define PFKEY2_CHUNK sizeof(uint64_t) @@ -367,84 +368,142 @@ pfkey_sa_remove(int af, union ldpd_addr } static int -pfkey_md5sig_establish(struct nbr *nbr, struct nbr_params *nbrp) +pfkey_md5sig_establish(struct nbr *nbr, struct ldp_auth *auth) { sleep(1); - if (!nbr->auth.spi_out) - if (pfkey_sa_add(nbr->af, &nbr->laddr, &nbr->raddr, - nbrp->auth.md5key_len, nbrp->auth.md5key, - &nbr->auth.spi_out) == -1) + if (nbr->auth_spi_out) { + if (pfkey_sa_remove(nbr->af, &nbr->laddr, &nbr->raddr, + &nbr->auth_spi_out) == -1) return (-1); - if (!nbr->auth.spi_in) - if (pfkey_sa_add(nbr->af, &nbr->raddr, &nbr->laddr, - nbrp->auth.md5key_len, nbrp->auth.md5key, - &nbr->auth.spi_in) == -1) + } + if (pfkey_sa_add(nbr->af, &nbr->laddr, &nbr->raddr, + auth->md5key_len, auth->md5key, &nbr->auth_spi_out) == -1) + return (-1); + + if (nbr->auth_spi_in) { + if (pfkey_sa_remove(nbr->af, &nbr->raddr, &nbr->laddr, + &nbr->auth_spi_in) == -1) return (-1); + } + if (pfkey_sa_add(nbr->af, &nbr->raddr, &nbr->laddr, + auth->md5key_len, auth->md5key, &nbr->auth_spi_in) == -1) + return (-1); + + nbr->auth_established = 1; - nbr->auth.established = 1; return (0); } static int pfkey_md5sig_remove(struct nbr *nbr) { - if (nbr->auth.spi_out) + if (nbr->auth_spi_out) { if (pfkey_sa_remove(nbr->af, &nbr->laddr, &nbr->raddr, - &nbr->auth.spi_out) == -1) + &nbr->auth_spi_out) == -1) return (-1); - if (nbr->auth.spi_in) + } + if (nbr->auth_spi_in) { if (pfkey_sa_remove(nbr->af, &nbr->raddr, &nbr->laddr, - &nbr->auth.spi_in) == -1) + &nbr->auth_spi_in) == -1) return (-1); + } - nbr->auth.established = 0; - nbr->auth.spi_in = 0; - nbr->auth.spi_out = 0; - nbr->auth.method = AUTH_NONE; - memset(nbr->auth.md5key, 0, sizeof(nbr->auth.md5key)); + nbr->auth_established = 0; + nbr->auth_spi_in = 0; + nbr->auth_spi_out = 0; return (0); } -int -pfkey_establish(struct nbr *nbr, struct nbr_params *nbrp) +static int +pfkey_match_prefix(const uint32_t *a, const uint32_t *b, int prefix) { - if (nbrp->auth.method == AUTH_NONE) - return (0); + while (prefix >= 32) { + if (*a++ != *b++) + return (0); + prefix -= 32; + } - /* - * make sure we keep copies of everything we need to - * remove SAs and flows later again. - */ - nbr->auth.method = nbrp->auth.method; - - switch (nbr->auth.method) { - case AUTH_MD5SIG: - strlcpy(nbr->auth.md5key, nbrp->auth.md5key, - sizeof(nbr->auth.md5key)); - return (pfkey_md5sig_establish(nbr, nbrp)); - default: - break; + if (prefix) { + uint32_t mask = htonl(~0U << prefix); + if ((*a & mask) != (*b & mask)) + return (0); } - return (0); + return (1); } -int -pfkey_remove(struct nbr *nbr) +#define ss2sin(_ss) ((struct sockaddr_in *)(_ss)) +#define ss2sin6(_ss) ((struct sockaddr_in6 *)(_ss)) + +static int +pkey_match_auth(struct ldp_auth *auth, struct nbr *nbr) { - if (nbr->auth.method == AUTH_NONE || !nbr->auth.established) - return (0); + if (auth->sslen > 0) { + const uint32_t *a, *b; - switch (nbr->auth.method) { - case AUTH_MD5SIG: - return (pfkey_md5sig_remove(nbr)); - default: - break; + assert(auth->prefixlen != -1); + + if (auth->ss.ss_family != nbr->af) + return (0); + + switch (nbr->af) { + case AF_INET: + assert(auth->prefixlen <= 32); + a = (const uint32_t *)&nbr->raddr.v4; + b = (const uint32_t *)&ss2sin(&auth->ss)->sin_addr; + break; + + case AF_INET6: + assert(auth->prefixlen <= 128); + a = (const uint32_t *)&nbr->raddr.v6; + b = (const uint32_t *)&ss2sin6(&auth->ss)->sin6_addr; + break; + } + + if (!pfkey_match_prefix(a, b, auth->prefixlen)) + return (0); } - return (0); + return (1); + +} + +static struct ldp_auth * +pfkey_find_auth(struct ldpd_conf *conf, struct nbr *nbr) +{ + struct ldp_auth *auth, *match = NULL; + + LIST_FOREACH(auth, &conf->auth_list, entry) { + if (!pkey_match_auth(auth, nbr)) + continue; + + if (match == NULL || + match->prefixlen < auth->prefixlen) + match = auth; + } + + return (match); +} + +int +pfkey_establish(struct ldpd_conf *conf, struct nbr *nbr) +{ + struct ldp_auth *auth; + + auth = pfkey_find_auth(conf, nbr); + if (auth == NULL || /* no prefix found */ + auth->md5key_len == 0) /* "no tcpmd5 sig" */ + return (0); + + return (pfkey_md5sig_establish(nbr, auth)); +} + +int +pfkey_remove(struct nbr *nbr) +{ + return (pfkey_md5sig_remove(nbr)); } int Index: printconf.c =================================================================== RCS file: /cvs/src/usr.sbin/ldpd/printconf.c,v retrieving revision 1.27 diff -u -p -r1.27 printconf.c --- printconf.c 3 Mar 2017 23:36:06 -0000 1.27 +++ printconf.c 22 Jan 2019 03:33:35 -0000 @@ -19,8 +19,11 @@ */ #include +#include #include #include +#include +#include #include "ldpd.h" #include "ldpe.h" @@ -132,9 +135,6 @@ print_nbrp(struct nbr_params *nbrp) if (nbrp->flags & F_NBRP_GTSM_HOPS) printf("\tgtsm-hops %u\n", nbrp->gtsm_hops); - if (nbrp->auth.method == AUTH_MD5SIG) - printf("\tpassword XXXXXX\n"); - printf("}\n"); } @@ -184,6 +184,36 @@ print_pw(struct l2vpn_pw *pw) printf("\t}\n"); } +static void +print_auth(struct ldpd_conf *conf) +{ + struct ldp_auth *auth; + + printf("\n"); + + LIST_FOREACH(auth, &conf->auth_list, entry) { + if (auth->md5key_len) + printf("tcp md5sig key XXX"); + else + printf("no tcp md5sig"); + if (auth->sslen) { + char hbuf[NI_MAXHOST]; + int error; + + error = getnameinfo((struct sockaddr *)&auth->ss, + auth->sslen, hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); + if (error != 0) { + errx(1, "getnameinfo: %s", + gai_strerror(error)); + } + + printf(" %s/%d", hbuf, auth->prefixlen); + } + printf("\n"); + } +} + void print_config(struct ldpd_conf *conf) { @@ -191,6 +221,9 @@ print_config(struct ldpd_conf *conf) struct l2vpn *l2vpn; print_mainconf(conf); + + if (!LIST_EMPTY(&conf->auth_list)) + print_auth(conf); if (conf->ipv4.flags & F_LDPD_AF_ENABLED) print_af(AF_INET, conf, &conf->ipv4);