diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2019-01-23 02:02:05 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2019-01-23 02:02:05 +0000 |
commit | db99c13617616f7d7f4e5df6a6affbed0e23ffe8 (patch) | |
tree | 640352a306b1953089fb42e99cb346347e983ee7 /usr.sbin/ldpd | |
parent | 2cf7d1cce3e05ed9fe7e441d335c8db2c502acbe (diff) |
rework how tcp md5 signatures are configured.
previously ldpd only allowed tcp md5 to be configured against a
neighbor (by ldp router id), but other vendors supported configuring
tcp md5sig by prefix as well as neighbor. this reworks the config
so auth is maintained globally as a list of prefixes that you do
and do not want to do tcp md5sig auth with.
the config statements look more like what is in bgpd.conf now too.
an example of the new config for interoperating with my baby cisco
test network:
on ios:
mpls ldp password required for MPLS
mpls ldp password option 1 for MPLS key-chain LDPAUTH
key chain LDPAUTH
key 1
key-string secret
interface Loopback0
ip address 192.168.0.0 255.255.255.255
end
ip prefix-list MPLS seq 5 permit 192.168.0.0/24
ip access-list standard MPLS
mpls ldp router-id Loopback0 force
and in ldpd.conf:
router-id 192.168.0.25
tcp md5sig password secret 192.168.0.0/24
address-family ipv4 { interface vmx1 }
this still supports specifying tcp md5sig on neighbors, but that
is syntactic sugar around adding entries to the list of auths.
ok (and lots of help from) claudio@
Diffstat (limited to 'usr.sbin/ldpd')
-rw-r--r-- | usr.sbin/ldpd/lde.c | 15 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.c | 80 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.conf.5 | 41 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.h | 24 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.c | 20 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.h | 15 | ||||
-rw-r--r-- | usr.sbin/ldpd/neighbor.c | 11 | ||||
-rw-r--r-- | usr.sbin/ldpd/packet.c | 4 | ||||
-rw-r--r-- | usr.sbin/ldpd/parse.y | 180 | ||||
-rw-r--r-- | usr.sbin/ldpd/pfkey.c | 99 | ||||
-rw-r--r-- | usr.sbin/ldpd/printconf.c | 36 |
11 files changed, 399 insertions, 126 deletions
diff --git a/usr.sbin/ldpd/lde.c b/usr.sbin/ldpd/lde.c index e6b45719700..1bfd701a390 100644 --- a/usr.sbin/ldpd/lde.c +++ b/usr.sbin/ldpd/lde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lde.c,v 1.73 2017/03/04 00:15:35 renato Exp $ */ +/* $OpenBSD: lde.c,v 1.74 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> @@ -480,6 +480,7 @@ lde_dispatch_parent(int fd, short event, void *bula) 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, void *bula) 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; diff --git a/usr.sbin/ldpd/ldpd.c b/usr.sbin/ldpd/ldpd.c index 901df833a91..7425d2030e5 100644 --- a/usr.sbin/ldpd/ldpd.c +++ b/usr.sbin/ldpd/ldpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpd.c,v 1.62 2017/03/03 23:36:06 renato Exp $ */ +/* $OpenBSD: ldpd.c,v 1.63 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> @@ -60,6 +60,7 @@ static void merge_nbrps(struct ldpd_conf *, struct ldpd_conf *); 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 *xconf) 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, struct ldpd_conf *xconf) 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, struct ldpd_conf *xconf) 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, struct ldpd_conf *xconf) 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, struct ldpd_conf *xconf) 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,62 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) 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) { + in_addr_t mask; + if (needle->md5key_len != auth->md5key_len) + continue; + if (needle->idlen != auth->idlen) + continue; + + if (memcmp(needle->md5key, auth->md5key, + needle->md5key_len) != 0) + continue; + + mask = prefixlen2mask(auth->idlen); + if ((needle->id.s_addr & mask) != (auth->id.s_addr & mask)) + 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); + + 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); + continue; + } + + free(xauth); + } +} + struct ldpd_conf * config_new_empty(void) { @@ -1218,6 +1277,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); } diff --git a/usr.sbin/ldpd/ldpd.conf.5 b/usr.sbin/ldpd/ldpd.conf.5 index c9d7706702c..2c797649be6 100644 --- a/usr.sbin/ldpd/ldpd.conf.5 +++ b/usr.sbin/ldpd/ldpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ldpd.conf.5,v 1.36 2018/08/06 17:25:11 mestre Exp $ +.\" $OpenBSD: ldpd.conf.5,v 1.37 2019/01/23 02:02:04 dlg Exp $ .\" .\" Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> .\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -19,7 +19,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 6 2018 $ +.Dd $Mdocdate: January 23 2019 $ .Dt LDPD.CONF 5 .Os .Sh NAME @@ -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,27 @@ Set the router ID; in combination with labelspace it forms the LSR-ID. If not specified, the numerically lowest IP address of the router will be used. .Pp .It Xo +.Ic tcp md5sig password Ar secret +.Op Ar lsr-id Ns Op / Ns Ar prefix +.Xc +.It Xo +.Ic tcp md5sig key Ar secret +.Op Ar lsr-id Ns Op / Ns Ar prefix +.Xc +.It Xo +.Ic no tcp md5sig +.Op Ar lsr-id 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 prefix may be specified to scope the key configuration to a +set of neighbors with the specified LSR-IDs. +.Bd -literal -offset indent +tcp md5sig password mekmitasdigoat 192.168.0.0/24 +no tcp md5sig 192.168.0.25 +.Ed +.Pp +.It Xo .Ic transport-preference .Pq Ic ipv4 Ns | Ns Ic ipv6 .Xc @@ -278,8 +291,12 @@ When GTSM is enabled for this neighbor, incoming packets are required to have 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. +.It Ic tcp md5sig password Ar secret +Enable TCP MD5 signatures per RFC 5036 with the specified password. +.It Ic tcp md5sig key Ar secret +Enable TCP MD5 signatures per RFC 5036 with the specified hexadecimal key. +.It Ic no tcp md5sig +Disable the use of TCP MD5 signatures. .El .Sh LAYER 2 VPNS .Xr ldpd 8 diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h index 6280bde5588..6d2f15c29e0 100644 --- a/usr.sbin/ldpd/ldpd.h +++ b/usr.sbin/ldpd/ldpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpd.h,v 1.88 2018/02/08 00:17:31 claudio Exp $ */ +/* $OpenBSD: ldpd.h,v 1.89 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> @@ -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,16 @@ 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 in_addr id; + int idlen; +}; + +#define LDP_AUTH_REQUIRED(_a) ((_a)->md5key_len != 0) + struct ldpd_conf { struct in_addr rtr_id; unsigned int rdomain; @@ -412,6 +413,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; }; diff --git a/usr.sbin/ldpd/ldpe.c b/usr.sbin/ldpd/ldpe.c index b30ab0f3c96..79084baea1f 100644 --- a/usr.sbin/ldpd/ldpe.c +++ b/usr.sbin/ldpd/ldpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.c,v 1.74 2017/03/04 00:21:48 renato Exp $ */ +/* $OpenBSD: ldpe.c,v 1.75 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> @@ -235,7 +235,6 @@ ldpe_dispatch_main(int fd, short event, void *bula) 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, void *bula) 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, void *bula) 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, void *bula) 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; diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h index 569e8ffc8bc..a4ad7de0440 100644 --- a/usr.sbin/ldpd/ldpe.h +++ b/usr.sbin/ldpd/ldpe.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.h,v 1.75 2017/03/04 00:21:48 renato Exp $ */ +/* $OpenBSD: ldpe.h,v 1.76 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> @@ -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); diff --git a/usr.sbin/ldpd/neighbor.c b/usr.sbin/ldpd/neighbor.c index 37d7260fcfb..e41b922b403 100644 --- a/usr.sbin/ldpd/neighbor.c +++ b/usr.sbin/ldpd/neighbor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: neighbor.c,v 1.79 2017/03/04 00:15:35 renato Exp $ */ +/* $OpenBSD: neighbor.c,v 1.80 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> @@ -223,7 +223,6 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr, 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 ds_tlv, union ldpd_addr *addr, 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); } diff --git a/usr.sbin/ldpd/packet.c b/usr.sbin/ldpd/packet.c index 1e03a09bcee..09c83469778 100644 --- a/usr.sbin/ldpd/packet.c +++ b/usr.sbin/ldpd/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.70 2017/03/04 00:06:10 renato Exp $ */ +/* $OpenBSD: packet.c,v 1.71 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> @@ -391,7 +391,7 @@ session_accept_nbr(struct nbr *nbr, int fd) 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); diff --git a/usr.sbin/ldpd/parse.y b/usr.sbin/ldpd/parse.y index bfcca083172..4128ba94af8 100644 --- a/usr.sbin/ldpd/parse.y +++ b/usr.sbin/ldpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.67 2018/11/01 00:18:44 sashan Exp $ */ +/* $OpenBSD: parse.y,v 1.68 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2013, 2015, 2016 Renato Westphal <renato@openbsd.org> @@ -24,6 +24,8 @@ %{ #include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> #include <arpa/inet.h> #include <ctype.h> #include <err.h> @@ -33,6 +35,8 @@ #include <limits.h> #include <stdio.h> #include <syslog.h> +#include <errno.h> +#include <netdb.h> #include "ldpd.h" #include "ldpe.h" @@ -76,6 +80,7 @@ typedef struct { union { int64_t number; char *string; + struct ldp_auth *auth; } v; int lineno; } YYSTYPE; @@ -107,6 +112,7 @@ static void clear_config(struct ldpd_conf *xconf); 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 +141,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 @@ -149,6 +156,7 @@ static struct config_defaults *defs; %token <v.number> NUMBER %type <v.number> yesno ldp_af l2vpn_type pw_type %type <v.string> string +%type <v.auth> auth tcpmd5 optnbrprefix %% @@ -273,6 +281,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 +415,103 @@ tnbr_defaults : THELLOHOLDTIME NUMBER { } ; +tcpmd5 : TCP MD5SIG PASSWORD STRING { + size_t len; + + $$ = calloc(1, 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; + + $$ = calloc(1, 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 { + $$ = calloc(1, sizeof(*$$)); + if ($$ == NULL) { + yyerror("unable to allocate no md5 key"); + YYERROR; + } + $$->md5key_len = 0; + } + ; + +optnbrprefix : STRING { + $$ = calloc(1, sizeof(*$$)); + if ($$ == NULL) { + yyerror("unable to allocate auth"); + free($1); + YYERROR; + } + + $$->idlen = inet_net_pton(AF_INET, $1, + &$$->id, sizeof($$->id)); + if ($$->idlen == -1) { + yyerror("%s: %s", $1, strerror(errno)); + free($1); + YYERROR; + } + } + | /* empty */ { + $$ = NULL; + } + ; + +auth : tcpmd5 optnbrprefix { + $$ = $1; + if ($2 != NULL) { + $$->id = $2->id; + $$->idlen = $2->idlen; + free($2); + } else { + $$->id.s_addr = 0; + $$->idlen = 0; + } + } + ; + nbr_opts : KEEPALIVE NUMBER { if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) { yyerror("keepalive out of range (%d-%d)", @@ -413,18 +521,11 @@ 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); + | tcpmd5 { + /* this is syntactic sugar... */ + $1->id = nbrp->lsr_id; + $1->idlen = 32; + LIST_INSERT_HEAD(&conf->auth_list, $1, entry); } | GTSMENABLE yesno { nbrp->flags |= F_NBRP_GTSM; @@ -835,13 +936,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 +963,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}, @@ -1602,3 +1708,47 @@ get_af_address(const char *s, int *family, union ldpd_addr *addr) 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); +} diff --git a/usr.sbin/ldpd/pfkey.c b/usr.sbin/ldpd/pfkey.c index 8e56c138b6e..0af77a85af4 100644 --- a/usr.sbin/ldpd/pfkey.c +++ b/usr.sbin/ldpd/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.11 2017/04/18 02:29:56 deraadt Exp $ */ +/* $OpenBSD: pfkey.c,v 1.12 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -36,7 +36,7 @@ static int pfkey_sa_add(int, union ldpd_addr *, union ldpd_addr *, 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 +367,81 @@ pfkey_sa_remove(int af, union ldpd_addr *src, union ldpd_addr *dst, } 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) - 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) - return (-1); + pfkey_md5sig_remove(nbr); + + if (pfkey_sa_add(nbr->af, &nbr->laddr, &nbr->raddr, + auth->md5key_len, auth->md5key, &nbr->auth_spi_out) == -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 struct ldp_auth * +pfkey_find_auth(struct ldpd_conf *conf, struct nbr *nbr) { - if (nbrp->auth.method == AUTH_NONE) - return (0); + struct ldp_auth *auth, *match = NULL; - /* - * 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; + LIST_FOREACH(auth, &conf->auth_list, entry) { + in_addr_t mask = prefixlen2mask(auth->idlen); + if ((auth->id.s_addr & mask) != (nbr->id.s_addr & mask)) + continue; + + if (match == NULL || + match->idlen < auth->idlen) + match = auth; } - return (0); + return (match); } int -pfkey_remove(struct nbr *nbr) +pfkey_establish(struct ldpd_conf *conf, struct nbr *nbr) { - if (nbr->auth.method == AUTH_NONE || !nbr->auth.established) - return (0); + struct ldp_auth *auth = NULL; - switch (nbr->auth.method) { - case AUTH_MD5SIG: - return (pfkey_md5sig_remove(nbr)); - default: - break; - } + auth = pfkey_find_auth(conf, nbr); + if (auth == NULL || /* no policy */ + auth->md5key_len == 0) /* "no tcpmd5 sig" */ + return (0); + + return (pfkey_md5sig_establish(nbr, auth)); +} - return (0); +int +pfkey_remove(struct nbr *nbr) +{ + return (pfkey_md5sig_remove(nbr)); } int diff --git a/usr.sbin/ldpd/printconf.c b/usr.sbin/ldpd/printconf.c index e39b43f8336..b622e54d03b 100644 --- a/usr.sbin/ldpd/printconf.c +++ b/usr.sbin/ldpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.27 2017/03/03 23:36:06 renato Exp $ */ +/* $OpenBSD: printconf.c,v 1.28 2019/01/23 02:02:04 dlg Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> @@ -19,8 +19,11 @@ */ #include <sys/types.h> +#include <sys/socket.h> #include <arpa/inet.h> #include <stdio.h> +#include <netdb.h> +#include <err.h> #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,31 @@ 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->idlen) { + char hbuf[NI_MAXHOST]; + + if (inet_net_ntop(AF_INET, &auth->id, auth->idlen, + hbuf, sizeof(hbuf)) == NULL) + err(1, "inet_net_ntop"); + + printf(" %s", hbuf); + } + printf("\n"); + } +} + void print_config(struct ldpd_conf *conf) { @@ -192,6 +217,9 @@ print_config(struct ldpd_conf *conf) 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); if (conf->ipv6.flags & F_LDPD_AF_ENABLED) |