Index | Thread | Search

From:
Claudio Jeker <cjeker@diehard.n-r-g.com>
Subject:
bgpd: add infrastructure to support rtr sessions with tcp md5 and ipsec
To:
tech@openbsd.org
Date:
Wed, 2 Oct 2024 14:53:05 +0200

Download raw body.

Thread
This diff adds the infrastructure to support tcp md5 and ipsec
authentication options for rtr sessions.

I did not include the parse.y and printconf bits yet since those are just
a lot of noise. In other words the pfkey calls in here are currently NOPs.

To properly support tcp md5 the parent needs to know when a session is
closed, so this adds a new IMSG for that and keeps the connect_elm struct
for open sockets on its own list.
I do not expect more than a handful of rtr sessions configured so a linear
list should be fine.

-- 
:wq Claudio

Index: bgpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v
diff -u -p -r1.269 bgpd.c
--- bgpd.c	1 Oct 2024 11:49:24 -0000	1.269
+++ bgpd.c	2 Oct 2024 12:45:53 -0000
@@ -55,6 +55,7 @@ int		imsg_send_sockets(struct imsgbuf *,
 		    struct imsgbuf *);
 void		bgpd_rtr_connect(struct rtr_config *);
 void		bgpd_rtr_connect_done(int, struct bgpd_config *);
+void		bgpd_rtr_close(uint32_t);
 
 int			 cflags;
 volatile sig_atomic_t	 mrtdump;
@@ -71,12 +72,15 @@ char			*rcname;
 
 struct connect_elm {
 	TAILQ_ENTRY(connect_elm)	entry;
+	struct auth_state		auth_state;
 	uint32_t			id;
 	int				fd;
 };
 
 TAILQ_HEAD(, connect_elm)	connect_queue = \
-				    TAILQ_HEAD_INITIALIZER(connect_queue);
+				    TAILQ_HEAD_INITIALIZER(connect_queue),
+				socket_queue = \
+				    TAILQ_HEAD_INITIALIZER(socket_queue);
 u_int				connect_cnt;
 #define MAX_CONNECT_CNT		32
 
@@ -657,7 +661,7 @@ send_config(struct bgpd_config *conf)
 		if (p->reconf_action == RECONF_REINIT)
 			if (pfkey_establish(&p->auth_state, &p->auth_conf,
 			    session_localaddr(p), &p->conf.remote_addr) == -1)
-				log_peer_warnx(&p->conf, "pfkey setup failed");
+				log_peer_warnx(&p->conf, "auth setup failed");
 	}
 
 	/* networks go via kroute to the RDE */
@@ -1057,17 +1061,25 @@ dispatch_imsg(struct imsgbuf *imsgbuf, i
 			if (idx != PFD_PIPE_RTR) {
 				log_warnx("connect request not from RTR");
 			} else {
+				uint32_t rtrid = imsg_get_id(&imsg);
 				SIMPLEQ_FOREACH(r, &conf->rtrs, entry) {
-					if (imsg_get_id(&imsg) == r->id)
+					if (rtrid == r->id)
 						break;
 				}
 				if (r == NULL)
-					log_warnx("unknown rtr id %d",
-					    imsg_get_id(&imsg));
+					log_warnx("unknown rtr id %d", rtrid);
 				else
 					bgpd_rtr_connect(r);
 			}
 			break;
+		case IMSG_SOCKET_CLOSE:
+			if (idx != PFD_PIPE_RTR) {
+				log_warnx("connect request not from RTR");
+			} else {
+				uint32_t rtrid = imsg_get_id(&imsg);
+				bgpd_rtr_close(rtrid);
+			}
+			break;
 		case IMSG_CTL_SHOW_RTR:
 			if (idx == PFD_PIPE_SESSION) {
 				SIMPLEQ_FOREACH(r, &conf->rtrs, entry) {
@@ -1377,13 +1389,16 @@ bgpd_rtr_connect(struct rtr_config *r)
 		return;
 	}
 
+	if (pfkey_establish(&ce->auth_state, &r->auth,
+	    &r->local_addr, &r->remote_addr) == -1)
+		log_warnx("rtr %s: pfkey setup failed", r->descr);
+
 	ce->id = r->id;
 	ce->fd = socket(aid2af(r->remote_addr.aid),
 	    SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_TCP);
 	if (ce->fd == -1) {
 		log_warn("rtr %s", r->descr);
-		free(ce);
-		return;
+		goto fail;
 	}
 
 	switch (r->remote_addr.aid) {
@@ -1409,13 +1424,14 @@ bgpd_rtr_connect(struct rtr_config *r)
 		return;
 	}
 
+	if (tcp_md5_set(ce->fd, &r->auth, &r->remote_addr) == -1)
+		log_warn("rtr %s: setting md5sig", r->descr);
+
 	if ((sa = addr2sa(&r->local_addr, 0, &len)) != NULL) {
 		if (bind(ce->fd, sa, len) == -1) {
 			log_warn("rtr %s: bind to %s", r->descr,
 			    log_addr(&r->local_addr));
-			close(ce->fd);
-			free(ce);
-			return;
+			goto fail;
 		}
 	}
 
@@ -1424,9 +1440,7 @@ bgpd_rtr_connect(struct rtr_config *r)
 		if (errno != EINPROGRESS) {
 			log_warn("rtr %s: connect to %s:%u", r->descr,
 			    log_addr(&r->remote_addr), r->remote_port);
-			close(ce->fd);
-			free(ce);
-			return;
+			goto fail;
 		}
 		TAILQ_INSERT_TAIL(&connect_queue, ce, entry);
 		connect_cnt++;
@@ -1434,6 +1448,12 @@ bgpd_rtr_connect(struct rtr_config *r)
 	}
 
 	imsg_compose(ibuf_rtr, IMSG_SOCKET_CONN, ce->id, 0, ce->fd, NULL, 0);
+	TAILQ_INSERT_TAIL(&socket_queue, ce, entry);
+	return;
+
+ fail:
+	if (ce->fd != -1)
+		close(ce->fd);
 	free(ce);
 }
 
@@ -1478,10 +1498,25 @@ bgpd_rtr_connect_done(int fd, struct bgp
 	}
 
 	imsg_compose(ibuf_rtr, IMSG_SOCKET_CONN, ce->id, 0, ce->fd, NULL, 0);
-	free(ce);
+	TAILQ_INSERT_TAIL(&socket_queue, ce, entry);
 	return;
 
 fail:
 	close(fd);
 	free(ce);
+}
+
+void
+bgpd_rtr_close(uint32_t id)
+{
+	struct connect_elm *ce;
+
+	TAILQ_FOREACH(ce, &socket_queue, entry) {
+		if (ce->id == id) {
+			pfkey_remove(&ce->auth_state);
+			TAILQ_REMOVE(&socket_queue, ce, entry);
+			free(ce);
+			return;
+		}
+	}
 }
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
diff -u -p -r1.497 bgpd.h
--- bgpd.h	1 Oct 2024 11:49:24 -0000	1.497
+++ bgpd.h	1 Oct 2024 13:08:48 -0000
@@ -569,6 +569,7 @@ enum rtr_error {
 struct rtr_config {
 	SIMPLEQ_ENTRY(rtr_config)	entry;
 	char				descr[PEER_DESCR_LEN];
+	struct auth_config		auth;
 	struct bgpd_addr		remote_addr;
 	struct bgpd_addr		local_addr;
 	uint32_t			id;
@@ -643,6 +644,7 @@ enum imsg_type {
 	IMSG_FLOWSPEC_FLUSH,
 	IMSG_FILTER_SET,
 	IMSG_SOCKET_CONN,
+	IMSG_SOCKET_CLOSE,
 	IMSG_SOCKET_CONN_CTL,
 	IMSG_SOCKET_CONN_RTR,
 	IMSG_RECONF_CONF,
Index: rtr_proto.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rtr_proto.c,v
diff -u -p -r1.40 rtr_proto.c
--- rtr_proto.c	10 Sep 2024 08:41:13 -0000	1.40
+++ rtr_proto.c	26 Sep 2024 19:00:21 -0000
@@ -1130,6 +1130,7 @@ rtr_fsm(struct rtr_session *rs, enum rtr
 			rs->r.wpos = 0;
 			close(rs->fd);
 			rs->fd = -1;
+			rtr_imsg_compose(IMSG_SOCKET_CLOSE, rs->id, 0, NULL, 0);
 		}
 		/* try to reopen session */
 		if (!rs->errored)