summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrenato <renato@openbsd.org>2015-07-19 21:01:56 +0000
committerrenato <renato@openbsd.org>2015-07-19 21:01:56 +0000
commit627846caf8baf851ed48eed111b4a2c8dcf64351 (patch)
treee477183921b71ba6938bd9da502025eff89fb117
parentRework label mapping algorithms to be more in line with the RFC. (diff)
downloadwireguard-openbsd-627846caf8baf851ed48eed111b4a2c8dcf64351.tar.xz
wireguard-openbsd-627846caf8baf851ed48eed111b4a2c8dcf64351.zip
Implement md5 authentication support.
ok claudio@
-rw-r--r--usr.sbin/ldpd/Makefile4
-rw-r--r--usr.sbin/ldpd/ldpd.conf.524
-rw-r--r--usr.sbin/ldpd/ldpd.h21
-rw-r--r--usr.sbin/ldpd/ldpe.c33
-rw-r--r--usr.sbin/ldpd/ldpe.h28
-rw-r--r--usr.sbin/ldpd/neighbor.c61
-rw-r--r--usr.sbin/ldpd/packet.c26
-rw-r--r--usr.sbin/ldpd/parse.y78
-rw-r--r--usr.sbin/ldpd/pfkey.c470
-rw-r--r--usr.sbin/ldpd/printconf.c22
10 files changed, 745 insertions, 22 deletions
diff --git a/usr.sbin/ldpd/Makefile b/usr.sbin/ldpd/Makefile
index 3ccc3e7b136..44324444e04 100644
--- a/usr.sbin/ldpd/Makefile
+++ b/usr.sbin/ldpd/Makefile
@@ -1,9 +1,9 @@
-# $OpenBSD: Makefile,v 1.5 2013/06/04 02:25:28 claudio Exp $
+# $OpenBSD: Makefile,v 1.6 2015/07/19 21:01:56 renato Exp $
PROG= ldpd
SRCS= accept.c adjacency.c address.c control.c hello.c init.c interface.c \
keepalive.c kroute.c labelmapping.c lde.c lde_lib.c ldpd.c ldpe.c \
- log.c neighbor.c notification.c packet.c parse.y printconf.c
+ log.c neighbor.c notification.c packet.c parse.y printconf.c pfkey.c
MAN= ldpd.8 ldpd.conf.5
diff --git a/usr.sbin/ldpd/ldpd.conf.5 b/usr.sbin/ldpd/ldpd.conf.5
index fc765bf3758..0a4bace9a70 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.15 2015/07/19 20:50:03 renato Exp $
+.\" $OpenBSD: ldpd.conf.5,v 1.16 2015/07/19 21:01:56 renato Exp $
.\"
.\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
.\" Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
@@ -31,7 +31,7 @@ daemon implements the Label Distribution Protocol as described in RFC 5036.
.Sh SECTIONS
The
.Nm
-config file is divided into four main sections.
+config file is divided into five main sections.
.Bl -tag -width xxxx
.It Sy Macros
User-defined variables may be defined and used later, simplifying the
@@ -43,6 +43,8 @@ Global settings for
Interface-specific parameters.
.It Sy Targeted Neighbors Configuration
Targeted neighbor specific parameters.
+.It Sy Neighbors Configuration
+Neighbor-specific parameters.
.El
.Sh MACROS
Much like
@@ -139,6 +141,24 @@ The default value is 45.
Set the hello interval in seconds.
The default value is 5; valid range is 1\-65535.
.El
+.Sh NEIGHBORS
+The
+.Ic neighbor
+section allows for the configuration of neighbor-specific parameters. Note,
+however, that
+.Xr ldpd 8
+uses the hello discovery mechanism to discover its neighbors. Without an
+underlying adjacency these commands have no effect.
+.Bd -literal -offset indent
+neighbor A.B.C.D {
+}
+.Ed
+.Pp
+Neighbor-specific parameters are listed below.
+.Bl -tag -width Ds
+.It Ic password Ar secret
+Enable TCP MD5 signatures per RFC 5036.
+.El
.Sh FILES
.Bl -tag -width "/etc/ldpd.conf" -compact
.It Pa /etc/ldpd.conf
diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h
index ed600251b57..c99784e9fbd 100644
--- a/usr.sbin/ldpd/ldpd.h
+++ b/usr.sbin/ldpd/ldpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpd.h,v 1.48 2015/07/19 20:54:17 renato Exp $ */
+/* $OpenBSD: ldpd.h,v 1.49 2015/07/19 21:01:56 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -37,6 +37,8 @@
#define LDPD_SOCKET "/var/run/ldpd.sock"
#define LDPD_USER "_ldpd"
+#define TCP_MD5_KEY_LEN 80
+
#define NBR_IDSELF 1
#define NBR_CNTSTART (NBR_IDSELF + 1)
@@ -219,6 +221,22 @@ struct tnbr {
};
#define F_TNBR_CONFIGURED 0x01
+enum auth_method {
+ AUTH_NONE,
+ AUTH_MD5SIG,
+};
+
+/* neighbor specific parameters */
+struct nbr_params {
+ LIST_ENTRY(nbr_params) entry;
+ struct in_addr addr;
+ struct {
+ enum auth_method method;
+ char md5key[TCP_MD5_KEY_LEN];
+ u_int8_t md5key_len;
+ } auth;
+};
+
/* ldp_conf */
enum {
PROC_MAIN,
@@ -238,6 +256,7 @@ struct ldpd_conf {
LIST_HEAD(, iface) iface_list;
LIST_HEAD(, if_addr) addr_list;
LIST_HEAD(, tnbr) tnbr_list;
+ LIST_HEAD(, nbr_params) nbrp_list;
u_int32_t opts;
#define LDPD_OPT_VERBOSE 0x00000001
diff --git a/usr.sbin/ldpd/ldpe.c b/usr.sbin/ldpd/ldpe.c
index d7b4172c760..c4413c164d7 100644
--- a/usr.sbin/ldpd/ldpe.c
+++ b/usr.sbin/ldpd/ldpe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpe.c,v 1.31 2015/07/19 20:54:17 renato Exp $ */
+/* $OpenBSD: ldpe.c,v 1.32 2015/07/19 21:01:56 renato Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -22,6 +22,7 @@
#include <sys/socket.h>
#include <sys/queue.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <net/if_types.h>
#include <stdlib.h>
@@ -51,6 +52,8 @@ void ldpe_shutdown(void);
struct ldpd_conf *leconf = NULL, *nconf;
struct imsgev *iev_main;
struct imsgev *iev_lde;
+struct event pfkey_ev;
+struct ldpd_sysdep sysdep;
/* ARGSUSED */
void
@@ -77,6 +80,7 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2],
struct event ev_sigint, ev_sigterm;
struct sockaddr_in disc_addr, sess_addr;
pid_t pid;
+ int pfkeysock, opt;
switch (pid = fork()) {
case -1:
@@ -92,6 +96,8 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2],
setproctitle("ldp engine");
ldpd_process = PROC_LDP_ENGINE;
+ pfkeysock = pfkey_init(&sysdep);
+
/* create ldpd control socket outside chroot */
if (control_init() == -1)
fatalx("control socket setup failed");
@@ -171,6 +177,16 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2],
if (listen(xconf->ldp_session_socket, LDP_BACKLOG) == -1)
fatal("error in listen on session socket");
+ opt = 1;
+ if (setsockopt(xconf->ldp_session_socket, IPPROTO_TCP, TCP_MD5SIG,
+ &opt, sizeof(opt)) == -1) {
+ if (errno == ENOPROTOOPT) { /* system w/o md5sig */
+ log_warnx("md5sig not available, disabling");
+ sysdep.no_md5sig = 1;
+ } else
+ fatal("setsockopt TCP_MD5SIG");
+ }
+
/* set some defaults */
if (if_set_tos(xconf->ldp_session_socket,
IPTOS_PREC_INTERNETCONTROL) == -1)
@@ -225,6 +241,10 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2],
iev_main->handler, iev_main);
event_add(&iev_main->ev, NULL);
+ event_set(&pfkey_ev, pfkeysock, EV_READ | EV_PERSIST,
+ ldpe_dispatch_pfkey, NULL);
+ event_add(&pfkey_ev, NULL);
+
event_set(&leconf->disc_ev, leconf->ldp_discovery_socket,
EV_READ|EV_PERSIST, disc_recv_packet, NULL);
event_add(&leconf->disc_ev, NULL);
@@ -574,6 +594,17 @@ ldpe_dispatch_lde(int fd, short event, void *bula)
}
}
+/* ARGSUSED */
+void
+ldpe_dispatch_pfkey(int fd, short event, void *bula)
+{
+ if (event & EV_READ) {
+ if (pfkey_read(fd, NULL) == -1) {
+ fatal("pfkey_read failed, exiting...");
+ }
+ }
+}
+
u_int32_t
ldpe_router_id(void)
{
diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h
index 65c98a4979d..e5dca3462fb 100644
--- a/usr.sbin/ldpd/ldpe.h
+++ b/usr.sbin/ldpd/ldpe.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpe.h,v 1.35 2015/04/04 15:09:47 renato Exp $ */
+/* $OpenBSD: ldpe.h,v 1.36 2015/07/19 21:01:56 renato Exp $ */
/*
* Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
@@ -26,6 +26,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
+#include <net/pfkeyv2.h>
TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns;
@@ -82,6 +83,15 @@ struct nbr {
int state;
int idtimer_cnt;
u_int16_t keepalive;
+
+ struct {
+ u_int8_t established;
+ struct in_addr local_addr;
+ u_int32_t spi_in;
+ u_int32_t spi_out;
+ enum auth_method method;
+ char md5key[TCP_MD5_KEY_LEN];
+ } auth;
};
struct mapping_entry {
@@ -89,6 +99,11 @@ struct mapping_entry {
struct map map;
};
+struct ldpd_sysdep {
+ u_int8_t no_pfkey;
+ u_int8_t no_md5sig;
+};
+
/* accept.c */
void accept_init(void);
int accept_add(int, void (*)(int, short, void *), void *);
@@ -128,6 +143,7 @@ int recv_labelmessage(struct nbr *, char *, u_int16_t, u_int16_t);
pid_t ldpe(struct ldpd_conf *, int[2], int[2], int[2]);
void ldpe_dispatch_main(int, short, void *);
void ldpe_dispatch_lde(int, short, void *);
+void ldpe_dispatch_pfkey(int, short, void *);
int ldpe_imsg_compose_parent(int, pid_t, void *, u_int16_t);
int ldpe_imsg_compose_lde(int, u_int32_t, pid_t, void *,
u_int16_t);
@@ -199,6 +215,10 @@ void nbr_mapping_add(struct nbr *, struct mapping_head *,
struct map *);
void mapping_list_clr(struct mapping_head *);
+
+struct nbr_params *nbr_params_new(struct in_addr);
+struct nbr_params *nbr_params_find(struct in_addr);
+
struct ctl_nbr *nbr_to_ctl(struct nbr *);
void ldpe_nbr_ctl(struct ctl_conn *);
@@ -219,4 +239,10 @@ void session_shutdown(struct nbr *, u_int32_t, u_int32_t, u_int32_t);
char *pkt_ptr; /* packet buffer */
+/* pfkey.c */
+int pfkey_read(int, struct sadb_msg *);
+int pfkey_establish(struct nbr *, struct nbr_params *);
+int pfkey_remove(struct nbr *);
+int pfkey_init(struct ldpd_sysdep *);
+
#endif /* _LDPE_H_ */
diff --git a/usr.sbin/ldpd/neighbor.c b/usr.sbin/ldpd/neighbor.c
index 849516860a1..99b291e3ad5 100644
--- a/usr.sbin/ldpd/neighbor.c
+++ b/usr.sbin/ldpd/neighbor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: neighbor.c,v 1.46 2015/07/19 20:50:03 renato Exp $ */
+/* $OpenBSD: neighbor.c,v 1.47 2015/07/19 21:01:56 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -23,6 +23,7 @@
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <net/if.h>
@@ -72,7 +73,8 @@ struct nbr_pid_head nbrs_by_pid = RB_INITIALIZER(&nbrs_by_pid);
u_int32_t peercnt = NBR_CNTSTART;
-extern struct ldpd_conf *leconf;
+extern struct ldpd_conf *leconf;
+extern struct ldpd_sysdep sysdep;
struct {
int state;
@@ -208,7 +210,8 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event)
struct nbr *
nbr_new(struct in_addr id, struct in_addr addr)
{
- struct nbr *nbr;
+ struct nbr *nbr;
+ struct nbr_params *nbrp;
log_debug("nbr_new: LSR ID %s", inet_ntoa(id));
@@ -240,6 +243,12 @@ nbr_new(struct in_addr id, struct in_addr addr)
evtimer_set(&nbr->keepalive_timer, nbr_ktimer, nbr);
evtimer_set(&nbr->initdelay_timer, nbr_idtimer, nbr);
+ /* init pfkey - remove old if any, load new ones */
+ pfkey_remove(nbr);
+ nbrp = nbr_params_find(nbr->addr);
+ if (nbrp && pfkey_establish(nbr, nbrp) == -1)
+ fatalx("pfkey setup failed");
+
return (nbr);
}
@@ -249,6 +258,7 @@ nbr_del(struct nbr *nbr)
log_debug("nbr_del: LSR ID %s", inet_ntoa(nbr->id));
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
+ pfkey_remove(nbr);
if (event_pending(&nbr->ev_connect, EV_WRITE, NULL))
event_del(&nbr->ev_connect);
@@ -465,9 +475,11 @@ nbr_connect_cb(int fd, short event, void *arg)
int
nbr_establish_connection(struct nbr *nbr)
{
- struct sockaddr_in local_sa;
- struct sockaddr_in remote_sa;
+ struct sockaddr_in local_sa;
+ struct sockaddr_in remote_sa;
struct adj *adj;
+ struct nbr_params *nbrp;
+ int opt = 1;
nbr->fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
if (nbr->fd == -1) {
@@ -476,6 +488,19 @@ nbr_establish_connection(struct nbr *nbr)
return (-1);
}
+ nbrp = nbr_params_find(nbr->addr);
+ if (nbrp && nbrp->auth.method == AUTH_MD5SIG) {
+ if (sysdep.no_pfkey || sysdep.no_md5sig) {
+ log_warnx("md5sig configured but not available");
+ return (-1);
+ }
+ if (setsockopt(nbr->fd, IPPROTO_TCP, TCP_MD5SIG,
+ &opt, sizeof(opt)) == -1) {
+ log_warn("setsockopt md5sig");
+ return (-1);
+ }
+ }
+
bzero(&local_sa, sizeof(local_sa));
local_sa.sin_family = AF_INET;
local_sa.sin_port = htons(0);
@@ -562,6 +587,32 @@ mapping_list_clr(struct mapping_head *mh)
}
}
+struct nbr_params *
+nbr_params_new(struct in_addr addr)
+{
+ struct nbr_params *nbrp;
+
+ if ((nbrp = calloc(1, sizeof(*nbrp))) == NULL)
+ fatal("nbr_params_new");
+
+ nbrp->addr.s_addr = addr.s_addr;
+ nbrp->auth.method = AUTH_NONE;
+
+ return (nbrp);
+}
+
+struct nbr_params *
+nbr_params_find(struct in_addr addr)
+{
+ struct nbr_params *nbrp;
+
+ LIST_FOREACH(nbrp, &leconf->nbrp_list, entry)
+ if (nbrp->addr.s_addr == addr.s_addr)
+ return (nbrp);
+
+ return (NULL);
+}
+
struct ctl_nbr *
nbr_to_ctl(struct nbr *nbr)
{
diff --git a/usr.sbin/ldpd/packet.c b/usr.sbin/ldpd/packet.c
index aeafa9e40a8..6ed78055cfc 100644
--- a/usr.sbin/ldpd/packet.c
+++ b/usr.sbin/ldpd/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.38 2015/04/04 15:04:49 renato Exp $ */
+/* $OpenBSD: packet.c,v 1.39 2015/07/19 21:01:56 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -23,6 +23,7 @@
#include <netinet/in.h>
#include <netinet/ip.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <net/if_dl.h>
#include <fcntl.h>
@@ -39,6 +40,7 @@
#include "ldpe.h"
extern struct ldpd_conf *leconf;
+extern struct ldpd_sysdep sysdep;
struct iface *disc_find_iface(unsigned int, struct in_addr);
ssize_t session_get_pdu(struct ibuf_read *, char **);
@@ -266,6 +268,8 @@ session_accept(int fd, short event, void *bula)
struct sockaddr_in src;
int newfd;
socklen_t len = sizeof(src);
+ struct nbr_params *nbrp;
+ int opt;
if (!(event & EV_READ))
return;
@@ -286,6 +290,26 @@ session_accept(int fd, short event, void *bula)
return;
}
+ nbrp = nbr_params_find(src.sin_addr);
+ if (nbrp && nbrp->auth.method == AUTH_MD5SIG) {
+ if (sysdep.no_pfkey || sysdep.no_md5sig) {
+ log_warnx("md5sig configured but not available");
+ close(newfd);
+ return;
+ }
+
+ len = sizeof(opt);
+ if (getsockopt(newfd, IPPROTO_TCP, TCP_MD5SIG,
+ &opt, &len) == -1)
+ fatal("getsockopt TCP_MD5SIG");
+ if (!opt) { /* non-md5'd connection! */
+ log_warnx(
+ "connection attempt without md5 signature");
+ close(newfd);
+ return;
+ }
+ }
+
tcp_new(newfd, NULL);
}
diff --git a/usr.sbin/ldpd/parse.y b/usr.sbin/ldpd/parse.y
index 4a6a9f40d9a..904141bbdf1 100644
--- a/usr.sbin/ldpd/parse.y
+++ b/usr.sbin/ldpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.24 2015/07/19 20:50:03 renato Exp $ */
+/* $OpenBSD: parse.y,v 1.25 2015/07/19 21:01:56 renato Exp $ */
/*
* Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
@@ -85,8 +85,9 @@ int host(const char *, struct in_addr *, struct in_addr *);
static struct ldpd_conf *conf;
static int errors = 0;
-struct iface *iface = NULL;
-struct tnbr *tnbr = NULL;
+struct iface *iface = NULL;
+struct tnbr *tnbr = NULL;
+struct nbr_params *nbrp = NULL;
struct config_defaults {
u_int16_t lhello_holdtime;
@@ -100,8 +101,9 @@ struct config_defaults ifacedefs;
struct config_defaults tnbrdefs;
struct config_defaults *defs;
-struct iface *conf_get_if(struct kif *);
-struct tnbr *conf_get_tnbr(struct in_addr);
+struct iface *conf_get_if(struct kif *);
+struct tnbr *conf_get_tnbr(struct in_addr);
+struct nbr_params *conf_get_nbrp(struct in_addr);
typedef struct {
union {
@@ -118,6 +120,7 @@ typedef struct {
%token THELLOHOLDTIME THELLOINTERVAL
%token THELLOACCEPT
%token KEEPALIVE
+%token NEIGHBOR PASSWORD
%token EXTTAG
%token YES NO
%token ERROR
@@ -134,6 +137,7 @@ grammar : /* empty */
| grammar varset '\n'
| grammar interface '\n'
| grammar tneighbor '\n'
+ | grammar neighbor '\n'
| grammar error '\n' { file->errors++; }
;
@@ -238,6 +242,21 @@ tnbr_defaults : THELLOHOLDTIME NUMBER {
}
;
+nbr_opts : 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);
+ }
+ ;
+
optnl : '\n' optnl
|
;
@@ -321,6 +340,35 @@ tneighboropts_l : tneighboropts_l tnbr_defaults nl
| tnbr_defaults optnl
;
+neighbor : NEIGHBOR STRING {
+ struct in_addr addr;
+
+ if (inet_aton($2, &addr) == 0) {
+ yyerror(
+ "error parsing neighbor address");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+
+ nbrp = conf_get_nbrp(addr);
+ if (nbrp == NULL)
+ YYERROR;
+ LIST_INSERT_HEAD(&conf->nbrp_list, nbrp, entry);
+ } neighbor_block {
+ nbrp = NULL;
+ }
+ ;
+
+neighbor_block : '{' optnl neighboropts_l '}'
+ | '{' optnl '}'
+ | /* nothing */
+ ;
+
+neighboropts_l : neighboropts_l nbr_opts nl
+ | nbr_opts optnl
+ ;
+
%%
struct keywords {
@@ -361,7 +409,9 @@ lookup(char *s)
{"keepalive", KEEPALIVE},
{"link-hello-holdtime", LHELLOHOLDTIME},
{"link-hello-interval", LHELLOINTERVAL},
+ {"neighbor", NEIGHBOR},
{"no", NO},
+ {"password", PASSWORD},
{"router-id", ROUTERID},
{"targeted-hello-accept", THELLOACCEPT},
{"targeted-hello-holdtime", THELLOHOLDTIME},
@@ -853,6 +903,24 @@ conf_get_tnbr(struct in_addr addr)
return (t);
}
+struct nbr_params *
+conf_get_nbrp(struct in_addr addr)
+{
+ struct nbr_params *n;
+
+ LIST_FOREACH(n, &conf->nbrp_list, entry) {
+ if (n->addr.s_addr == addr.s_addr) {
+ yyerror("neighbor %s already configured",
+ inet_ntoa(addr));
+ return (NULL);
+ }
+ }
+
+ n = nbr_params_new(addr);
+
+ return (n);
+}
+
void
clear_config(struct ldpd_conf *xconf)
{
diff --git a/usr.sbin/ldpd/pfkey.c b/usr.sbin/ldpd/pfkey.c
new file mode 100644
index 00000000000..0a846905ed2
--- /dev/null
+++ b/usr.sbin/ldpd/pfkey.c
@@ -0,0 +1,470 @@
+/* $OpenBSD: pfkey.c,v 1.1 2015/07/19 21:01:56 renato Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ * Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <net/pfkeyv2.h>
+#include <netinet/ip_ipsp.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ldpd.h"
+#include "ldpe.h"
+#include "log.h"
+
+#define PFKEY2_CHUNK sizeof(u_int64_t)
+#define ROUNDUP(x) (((x) + (PFKEY2_CHUNK - 1)) & ~(PFKEY2_CHUNK - 1))
+#define IOV_CNT 20
+
+static u_int32_t sadb_msg_seq = 0;
+static u_int32_t pid = 0; /* should pid_t but pfkey needs u_int32_t */
+static int fd;
+
+int pfkey_reply(int, u_int32_t *);
+int pfkey_send(int, uint8_t, uint8_t, uint8_t,
+ struct in_addr *, struct in_addr *,
+ u_int32_t, uint8_t, int, char *, uint8_t, int, char *,
+ uint16_t, uint16_t);
+int pfkey_sa_add(struct in_addr *, struct in_addr *, u_int8_t, char *,
+ u_int32_t *);
+int pfkey_sa_remove(struct in_addr *, struct in_addr *, u_int32_t *);
+
+int pfkey_md5sig_establish(struct nbr *, struct nbr_params *nbrp);
+int pfkey_md5sig_remove(struct nbr *);
+
+static struct sockaddr *
+addr2sa(struct in_addr *addr)
+{
+ static struct sockaddr_storage ss;
+ struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
+
+ bzero(&ss, sizeof(ss));
+ sa_in->sin_family = AF_INET;
+ sa_in->sin_len = sizeof(struct sockaddr_in);
+ sa_in->sin_addr.s_addr = addr->s_addr;
+ sa_in->sin_port = htons(0);
+
+ return ((struct sockaddr *)&ss);
+}
+
+int
+pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
+ struct in_addr *src, struct in_addr *dst, u_int32_t spi,
+ uint8_t aalg, int alen, char *akey, uint8_t ealg, int elen, char *ekey,
+ uint16_t sport, uint16_t dport)
+{
+ struct sadb_msg smsg;
+ struct sadb_sa sa;
+ struct sadb_address sa_src, sa_dst;
+ struct sadb_key sa_akey, sa_ekey;
+ struct sadb_spirange sa_spirange;
+ struct iovec iov[IOV_CNT];
+ ssize_t n;
+ int len = 0;
+ int iov_cnt;
+ struct sockaddr_storage ssrc, sdst, smask, dmask;
+ struct sockaddr *saptr;
+
+ if (!pid)
+ pid = getpid();
+
+ /* we need clean sockaddr... no ports set */
+ bzero(&ssrc, sizeof(ssrc));
+ bzero(&smask, sizeof(smask));
+ if ((saptr = addr2sa(src)))
+ memcpy(&ssrc, saptr, sizeof(ssrc));
+ memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8);
+ smask.ss_family = ssrc.ss_family;
+ smask.ss_len = ssrc.ss_len;
+
+ bzero(&sdst, sizeof(sdst));
+ bzero(&dmask, sizeof(dmask));
+ if ((saptr = addr2sa(dst)))
+ memcpy(&sdst, saptr, sizeof(sdst));
+ memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8);
+ dmask.ss_family = sdst.ss_family;
+ dmask.ss_len = sdst.ss_len;
+
+ bzero(&smsg, sizeof(smsg));
+ smsg.sadb_msg_version = PF_KEY_V2;
+ smsg.sadb_msg_seq = ++sadb_msg_seq;
+ smsg.sadb_msg_pid = pid;
+ smsg.sadb_msg_len = sizeof(smsg) / 8;
+ smsg.sadb_msg_type = mtype;
+ smsg.sadb_msg_satype = satype;
+
+ switch (mtype) {
+ case SADB_GETSPI:
+ bzero(&sa_spirange, sizeof(sa_spirange));
+ sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8;
+ sa_spirange.sadb_spirange_min = 0x100;
+ sa_spirange.sadb_spirange_max = 0xffffffff;
+ sa_spirange.sadb_spirange_reserved = 0;
+ break;
+ case SADB_ADD:
+ case SADB_UPDATE:
+ case SADB_DELETE:
+ bzero(&sa, sizeof(sa));
+ sa.sadb_sa_exttype = SADB_EXT_SA;
+ sa.sadb_sa_len = sizeof(sa) / 8;
+ sa.sadb_sa_replay = 0;
+ sa.sadb_sa_spi = spi;
+ sa.sadb_sa_state = SADB_SASTATE_MATURE;
+ break;
+ }
+
+ bzero(&sa_src, sizeof(sa_src));
+ sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+ sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8;
+
+ bzero(&sa_dst, sizeof(sa_dst));
+ sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+ sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8;
+
+ sa.sadb_sa_auth = aalg;
+ sa.sadb_sa_encrypt = SADB_X_EALG_AES; /* XXX */
+
+ switch (mtype) {
+ case SADB_ADD:
+ case SADB_UPDATE:
+ bzero(&sa_akey, sizeof(sa_akey));
+ sa_akey.sadb_key_exttype = SADB_EXT_KEY_AUTH;
+ sa_akey.sadb_key_len = (sizeof(sa_akey) +
+ ((alen + 7) / 8) * 8) / 8;
+ sa_akey.sadb_key_bits = 8 * alen;
+
+ bzero(&sa_ekey, sizeof(sa_ekey));
+ sa_ekey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
+ sa_ekey.sadb_key_len = (sizeof(sa_ekey) +
+ ((elen + 7) / 8) * 8) / 8;
+ sa_ekey.sadb_key_bits = 8 * elen;
+
+ break;
+ }
+
+ iov_cnt = 0;
+
+ /* msghdr */
+ iov[iov_cnt].iov_base = &smsg;
+ iov[iov_cnt].iov_len = sizeof(smsg);
+ iov_cnt++;
+
+ switch (mtype) {
+ case SADB_ADD:
+ case SADB_UPDATE:
+ case SADB_DELETE:
+ /* SA hdr */
+ iov[iov_cnt].iov_base = &sa;
+ iov[iov_cnt].iov_len = sizeof(sa);
+ smsg.sadb_msg_len += sa.sadb_sa_len;
+ iov_cnt++;
+ break;
+ case SADB_GETSPI:
+ /* SPI range */
+ iov[iov_cnt].iov_base = &sa_spirange;
+ iov[iov_cnt].iov_len = sizeof(sa_spirange);
+ smsg.sadb_msg_len += sa_spirange.sadb_spirange_len;
+ iov_cnt++;
+ break;
+ }
+
+ /* dest addr */
+ iov[iov_cnt].iov_base = &sa_dst;
+ iov[iov_cnt].iov_len = sizeof(sa_dst);
+ iov_cnt++;
+ iov[iov_cnt].iov_base = &sdst;
+ iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len);
+ smsg.sadb_msg_len += sa_dst.sadb_address_len;
+ iov_cnt++;
+
+ /* src addr */
+ iov[iov_cnt].iov_base = &sa_src;
+ iov[iov_cnt].iov_len = sizeof(sa_src);
+ iov_cnt++;
+ iov[iov_cnt].iov_base = &ssrc;
+ iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len);
+ smsg.sadb_msg_len += sa_src.sadb_address_len;
+ iov_cnt++;
+
+ switch (mtype) {
+ case SADB_ADD:
+ case SADB_UPDATE:
+ if (alen) {
+ /* auth key */
+ iov[iov_cnt].iov_base = &sa_akey;
+ iov[iov_cnt].iov_len = sizeof(sa_akey);
+ iov_cnt++;
+ iov[iov_cnt].iov_base = akey;
+ iov[iov_cnt].iov_len = ((alen + 7) / 8) * 8;
+ smsg.sadb_msg_len += sa_akey.sadb_key_len;
+ iov_cnt++;
+ }
+ if (elen) {
+ /* encryption key */
+ iov[iov_cnt].iov_base = &sa_ekey;
+ iov[iov_cnt].iov_len = sizeof(sa_ekey);
+ iov_cnt++;
+ iov[iov_cnt].iov_base = ekey;
+ iov[iov_cnt].iov_len = ((elen + 7) / 8) * 8;
+ smsg.sadb_msg_len += sa_ekey.sadb_key_len;
+ iov_cnt++;
+ }
+ break;
+ }
+
+ len = smsg.sadb_msg_len * 8;
+ do {
+ n = writev(sd, iov, iov_cnt);
+ } while (n == -1 && (errno == EAGAIN || errno == EINTR));
+
+ if (n == -1) {
+ log_warn("writev (%d/%d)", iov_cnt, len);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+pfkey_read(int sd, struct sadb_msg *h)
+{
+ struct sadb_msg hdr;
+
+ if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) {
+ if (errno == EAGAIN || errno == EINTR)
+ return (0);
+ log_warn("pfkey peek");
+ return (-1);
+ }
+
+ /* XXX: Only one message can be outstanding. */
+ if (hdr.sadb_msg_seq == sadb_msg_seq &&
+ hdr.sadb_msg_pid == pid) {
+ if (h)
+ bcopy(&hdr, h, sizeof(hdr));
+ return (0);
+ }
+
+ /* not ours, discard */
+ if (read(sd, &hdr, sizeof(hdr)) == -1) {
+ if (errno == EAGAIN || errno == EINTR)
+ return (0);
+ log_warn("pfkey read");
+ return (-1);
+ }
+
+ return (1);
+}
+
+int
+pfkey_reply(int sd, u_int32_t *spip)
+{
+ struct sadb_msg hdr, *msg;
+ struct sadb_ext *ext;
+ struct sadb_sa *sa;
+ u_int8_t *data;
+ ssize_t len;
+ int rv;
+
+ do {
+ rv = pfkey_read(sd, &hdr);
+ if (rv == -1)
+ return (-1);
+ } while (rv);
+
+ if (hdr.sadb_msg_errno != 0) {
+ errno = hdr.sadb_msg_errno;
+ if (errno == ESRCH)
+ return (0);
+ else {
+ log_warn("pfkey");
+ return (-1);
+ }
+ }
+ if ((data = reallocarray(NULL, hdr.sadb_msg_len, PFKEY2_CHUNK)) == NULL) {
+ log_warn("pfkey malloc");
+ return (-1);
+ }
+ len = hdr.sadb_msg_len * PFKEY2_CHUNK;
+ if (read(sd, data, len) != len) {
+ log_warn("pfkey read");
+ bzero(data, len);
+ free(data);
+ return (-1);
+ }
+
+ if (hdr.sadb_msg_type == SADB_GETSPI) {
+ if (spip == NULL) {
+ bzero(data, len);
+ free(data);
+ return (0);
+ }
+
+ msg = (struct sadb_msg *)data;
+ for (ext = (struct sadb_ext *)(msg + 1);
+ (size_t)((u_int8_t *)ext - (u_int8_t *)msg) <
+ msg->sadb_msg_len * PFKEY2_CHUNK;
+ ext = (struct sadb_ext *)((u_int8_t *)ext +
+ ext->sadb_ext_len * PFKEY2_CHUNK)) {
+ if (ext->sadb_ext_type == SADB_EXT_SA) {
+ sa = (struct sadb_sa *) ext;
+ *spip = sa->sadb_sa_spi;
+ break;
+ }
+ }
+ }
+ bzero(data, len);
+ free(data);
+ return (0);
+}
+
+int
+pfkey_sa_add(struct in_addr *src, struct in_addr *dst, u_int8_t keylen,
+ char *key, u_int32_t *spi)
+{
+ if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_GETSPI, 0,
+ src, dst, 0, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0)
+ return (-1);
+ if (pfkey_reply(fd, spi) < 0)
+ return (-1);
+ if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_UPDATE, 0,
+ src, dst, *spi, 0, keylen, key, 0, 0, NULL, 0, 0) < 0)
+ return (-1);
+ if (pfkey_reply(fd, NULL) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+pfkey_sa_remove(struct in_addr *src, struct in_addr *dst, u_int32_t *spi)
+{
+ if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_DELETE, 0,
+ src, dst, *spi, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0)
+ return (-1);
+ if (pfkey_reply(fd, NULL) < 0)
+ return (-1);
+ *spi = 0;
+ return (0);
+}
+
+int
+pfkey_md5sig_establish(struct nbr *nbr, struct nbr_params *nbrp)
+{
+ sleep(1);
+
+ if (!nbr->auth.spi_out)
+ if (pfkey_sa_add(&nbr->auth.local_addr, &nbr->addr,
+ nbrp->auth.md5key_len, nbrp->auth.md5key,
+ &nbr->auth.spi_out) == -1)
+ return (-1);
+ if (!nbr->auth.spi_in)
+ if (pfkey_sa_add(&nbr->addr, &nbr->auth.local_addr,
+ nbrp->auth.md5key_len, nbrp->auth.md5key,
+ &nbr->auth.spi_in) == -1)
+ return (-1);
+
+ nbr->auth.established = 1;
+ return (0);
+}
+
+int
+pfkey_md5sig_remove(struct nbr *nbr)
+{
+ if (nbr->auth.spi_out)
+ if (pfkey_sa_remove(&nbr->auth.local_addr, &nbr->addr,
+ &nbr->auth.spi_out) == -1)
+ return (-1);
+ if (nbr->auth.spi_in)
+ if (pfkey_sa_remove(&nbr->addr, &nbr->auth.local_addr,
+ &nbr->auth.spi_in) == -1)
+ return (-1);
+
+ nbr->auth.established = 0;
+ nbr->auth.local_addr.s_addr = 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));
+
+ return (0);
+}
+
+int
+pfkey_establish(struct nbr *nbr, struct nbr_params *nbrp)
+{
+ if (nbrp->auth.method == AUTH_NONE)
+ return (0);
+
+ /*
+ * make sure we keep copies of everything we need to
+ * remove SAs and flows later again.
+ */
+ nbr->auth.local_addr.s_addr = ldpe_router_id();
+ 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));
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+pfkey_remove(struct nbr *nbr)
+{
+ if (nbr->auth.method == AUTH_NONE || !nbr->auth.established)
+ return (0);
+
+ switch (nbr->auth.method) {
+ case AUTH_MD5SIG:
+ return (pfkey_md5sig_remove(nbr));
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+pfkey_init(struct ldpd_sysdep *sysdep)
+{
+ if ((fd = socket(PF_KEY, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
+ PF_KEY_V2)) == -1) {
+ if (errno == EPROTONOSUPPORT) {
+ log_warnx("PF_KEY not available, disabling ipsec");
+ sysdep->no_pfkey = 1;
+ return (-1);
+ } else
+ fatal("pfkey setup failed");
+ }
+ return (fd);
+}
diff --git a/usr.sbin/ldpd/printconf.c b/usr.sbin/ldpd/printconf.c
index 626b6745359..6a89d813a77 100644
--- a/usr.sbin/ldpd/printconf.c
+++ b/usr.sbin/ldpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.8 2015/07/19 20:50:03 renato Exp $ */
+/* $OpenBSD: printconf.c,v 1.9 2015/07/19 21:01:56 renato Exp $ */
/*
* Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
@@ -30,7 +30,8 @@
void print_mainconf(struct ldpd_conf *);
void print_iface(struct iface *);
-void print_tnbr(struct tnbr *tnbr);
+void print_tnbr(struct tnbr *);
+void print_nbrp(struct nbr_params *);
void
print_mainconf(struct ldpd_conf *conf)
@@ -69,10 +70,20 @@ print_tnbr(struct tnbr *tnbr)
}
void
+print_nbrp(struct nbr_params *nbrp)
+{
+ printf("\nneighbor %s {\n", inet_ntoa(nbrp->addr));
+ if (nbrp->auth.method == AUTH_MD5SIG)
+ printf("\tpassword XXXXXX\n");
+ printf("}\n");
+}
+
+void
print_config(struct ldpd_conf *conf)
{
- struct iface *iface;
- struct tnbr *tnbr;
+ struct iface *iface;
+ struct tnbr *tnbr;
+ struct nbr_params *nbrp;
print_mainconf(conf);
printf("\n");
@@ -82,4 +93,7 @@ print_config(struct ldpd_conf *conf)
printf("\n");
LIST_FOREACH(tnbr, &conf->tnbr_list, entry)
print_tnbr(tnbr);
+ printf("\n");
+ LIST_FOREACH(nbrp, &conf->nbrp_list, entry)
+ print_nbrp(nbrp);
}