currently ldpd only lets you specify md5 params with neighbors (not
targeted neighbors). this is awkward is you want to peer with
arbitrary hosts on a network since you'll have a to generate a lot of
config for each potential peer on that net.

both cisco and juniper let you set up keys for prefixes. this diff
follows their lead and moves tcpmd5 config out of neighbors and up to
the global scope. to work in my test environment, my config now looks
like this:

        # global configuration
        router-id 192.168.0.25
        tcp md5sig password p6zFE8f794c7NaKG inet 192.168.0.0/24

        address-family ipv4 {
                # explicit-null yes
                # keepalive 120
                # targeted-hello-accept yes
                # transport-address 10.0.0.1

                interface vmx1
        }

you can then punch holes in this if you want with "no tcp md5sig" lines.

thoughts? ok?

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 <[email protected]>
  * Copyright (c) 2004, 2005, 2008 Esben Norby <[email protected]>
@@ -24,6 +25,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 +36,8 @@
 #include <limits.h>
 #include <stdio.h>
 #include <syslog.h>
+#include <errno.h>
+#include <netdb.h>
 
 #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 <v.string>      STRING
 %token <v.number>      NUMBER
 %type  <v.number>      yesno ldp_af l2vpn_type pw_type
+%type  <v.number>      optaf optprefixlen
 %type  <v.string>      string
+%type  <v.auth>        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 <sys/types.h>
+#include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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 <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,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);

Reply via email to