From d762911438b0f2269d31deb8a37b9427b23c929f Mon Sep 17 00:00:00 2001 From: claudio Date: Tue, 1 Oct 2024 11:49:24 +0000 Subject: [PATCH] Rework the pfkey and tcp md5 API to not depend on struct peer. Instead use struct auth_config and struct auth_state in the pfkey calls and those tcp_md5 calls where it matters. This is preparation work to allow RTR to use TCP MD5 as well. OK tb@ --- usr.sbin/bgpd/bgpd.c | 13 +- usr.sbin/bgpd/bgpd.h | 6 +- usr.sbin/bgpd/config.c | 8 +- usr.sbin/bgpd/control.c | 29 +++-- usr.sbin/bgpd/parse.y | 96 +++++++------- usr.sbin/bgpd/pfkey.c | 254 ++++++++++++++++++-------------------- usr.sbin/bgpd/printconf.c | 76 ++++++------ usr.sbin/bgpd/session.c | 54 +++++--- usr.sbin/bgpd/session.h | 32 +++-- 9 files changed, 293 insertions(+), 275 deletions(-) diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index 572551ce4d8..671fb065662 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.268 2024/09/30 09:42:24 claudio Exp $ */ +/* $OpenBSD: bgpd.c,v 1.269 2024/10/01 11:49:24 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -467,7 +467,7 @@ BROKEN if (pledge("stdio rpath wpath cpath fattr unix route recvfd sendfd", pftable_clear_all(); RB_FOREACH(p, peer_head, &conf->peers) - pfkey_remove(p); + pfkey_remove(&p->auth_state); while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) { SIMPLEQ_REMOVE_HEAD(&ribnames, entry); @@ -651,9 +651,12 @@ send_config(struct bgpd_config *conf) if (imsg_compose(ibuf_se, IMSG_RECONF_PEER, p->conf.id, 0, -1, &p->conf, sizeof(p->conf)) == -1) return (-1); + if (pfkey_send_conf(ibuf_se, p->conf.id, &p->auth_conf) == -1) + return (-1); if (p->reconf_action == RECONF_REINIT) - if (pfkey_establish(p) == -1) + 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"); } @@ -943,7 +946,9 @@ dispatch_imsg(struct imsgbuf *imsgbuf, int idx, struct bgpd_config *conf) } p = getpeerbyid(conf, imsg_get_id(&imsg)); if (p != NULL) { - if (pfkey_establish(p) == -1) + 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"); } diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index c558d636b44..43322c14a75 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.496 2024/09/04 15:06:36 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.497 2024/10/01 11:49:24 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -379,7 +379,7 @@ enum auth_enc_alg { AUTH_EALG_AES, }; -struct peer_auth { +struct auth_config { char md5key[TCP_MD5_KEY_LEN]; char auth_key_in[IPSEC_AUTH_KEY_LEN]; char auth_key_out[IPSEC_AUTH_KEY_LEN]; @@ -452,7 +452,6 @@ struct peer_config { struct bgpd_addr remote_addr; struct bgpd_addr local_addr_v4; struct bgpd_addr local_addr_v6; - struct peer_auth auth; struct capabilities capabilities; struct addpath_eval eval; char group[PEER_DESCR_LEN]; @@ -649,6 +648,7 @@ enum imsg_type { IMSG_RECONF_CONF, IMSG_RECONF_RIB, IMSG_RECONF_PEER, + IMSG_RECONF_PEER_AUTH, IMSG_RECONF_FILTER, IMSG_RECONF_LISTENER, IMSG_RECONF_CTRL, diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c index 94efad738b8..4821dea4aaf 100644 --- a/usr.sbin/bgpd/config.c +++ b/usr.sbin/bgpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.111 2024/09/04 13:30:10 claudio Exp $ */ +/* $OpenBSD: config.c,v 1.112 2024/10/01 11:49:24 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer @@ -440,8 +440,8 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf) np = getpeerbyid(conf, p->conf.id); if (np != NULL) { np->reconf_action = RECONF_KEEP; - /* copy the auth state since parent uses it */ - np->auth = p->auth; + /* keep the auth state since parent needs it */ + np->auth_state = p->auth_state; RB_REMOVE(peer_head, &xconf->peers, p); free(p); @@ -467,7 +467,7 @@ free_deleted_peers(struct bgpd_config *conf) RB_FOREACH_SAFE(p, peer_head, &conf->peers, nextp) { if (p->reconf_action == RECONF_DELETE) { /* peer no longer exists, clear pfkey state */ - pfkey_remove(p); + pfkey_remove(&p->auth_state); RB_REMOVE(peer_head, &conf->peers, p); free(p); } diff --git a/usr.sbin/bgpd/control.c b/usr.sbin/bgpd/control.c index 2ef1221e456..b474a48fc1c 100644 --- a/usr.sbin/bgpd/control.c +++ b/usr.sbin/bgpd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.118 2024/08/20 11:59:39 claudio Exp $ */ +/* $OpenBSD: control.c,v 1.119 2024/10/01 11:49:24 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -544,6 +544,7 @@ control_imsg_relay(struct imsg *imsg, struct peer *p) /* special handling for peers since only the stats are sent from RDE */ if (type == IMSG_CTL_SHOW_NEIGHBOR) { struct rde_peer_stats stats; + struct peer peer; if (p == NULL) { log_warnx("%s: no such peer: id=%u", __func__, @@ -554,20 +555,22 @@ control_imsg_relay(struct imsg *imsg, struct peer *p) log_warnx("%s: imsg_get_data", __func__); return (0); } - p->stats.prefix_cnt = stats.prefix_cnt; - p->stats.prefix_out_cnt = stats.prefix_out_cnt; - p->stats.prefix_rcvd_update = stats.prefix_rcvd_update; - p->stats.prefix_rcvd_withdraw = stats.prefix_rcvd_withdraw; - p->stats.prefix_rcvd_eor = stats.prefix_rcvd_eor; - p->stats.prefix_sent_update = stats.prefix_sent_update; - p->stats.prefix_sent_withdraw = stats.prefix_sent_withdraw; - p->stats.prefix_sent_eor = stats.prefix_sent_eor; - p->stats.pending_update = stats.pending_update; - p->stats.pending_withdraw = stats.pending_withdraw; - p->stats.msg_queue_len = msgbuf_queuelen(&p->wbuf); + peer = *p; + explicit_bzero(&peer.auth_conf, sizeof(peer.auth_conf)); + peer.stats.prefix_cnt = stats.prefix_cnt; + peer.stats.prefix_out_cnt = stats.prefix_out_cnt; + peer.stats.prefix_rcvd_update = stats.prefix_rcvd_update; + peer.stats.prefix_rcvd_withdraw = stats.prefix_rcvd_withdraw; + peer.stats.prefix_rcvd_eor = stats.prefix_rcvd_eor; + peer.stats.prefix_sent_update = stats.prefix_sent_update; + peer.stats.prefix_sent_withdraw = stats.prefix_sent_withdraw; + peer.stats.prefix_sent_eor = stats.prefix_sent_eor; + peer.stats.pending_update = stats.pending_update; + peer.stats.pending_withdraw = stats.pending_withdraw; + peer.stats.msg_queue_len = msgbuf_queuelen(&p->wbuf); return imsg_compose(&c->imsgbuf, type, 0, pid, -1, - p, sizeof(*p)); + &peer, sizeof(peer)); } /* if command finished no need to send exit message */ diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index c2f24cc9158..166c0e79438 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.468 2024/09/20 02:00:46 jsg Exp $ */ +/* $OpenBSD: parse.y,v 1.469 2024/10/01 11:49:24 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -2076,59 +2076,59 @@ peeropts : REMOTEAS as4number { curpeer->conf.max_out_prefix_restart = $4; } | TCP MD5SIG PASSWORD string { - if (curpeer->conf.auth.method) { + if (curpeer->auth_conf.method) { yyerror("auth method cannot be redefined"); free($4); YYERROR; } - if (strlcpy(curpeer->conf.auth.md5key, $4, - sizeof(curpeer->conf.auth.md5key)) >= - sizeof(curpeer->conf.auth.md5key)) { + if (strlcpy(curpeer->auth_conf.md5key, $4, + sizeof(curpeer->auth_conf.md5key)) >= + sizeof(curpeer->auth_conf.md5key)) { yyerror("tcp md5sig password too long: max %zu", - sizeof(curpeer->conf.auth.md5key) - 1); + sizeof(curpeer->auth_conf.md5key) - 1); free($4); YYERROR; } - curpeer->conf.auth.method = AUTH_MD5SIG; - curpeer->conf.auth.md5key_len = strlen($4); + curpeer->auth_conf.method = AUTH_MD5SIG; + curpeer->auth_conf.md5key_len = strlen($4); free($4); } | TCP MD5SIG KEY string { - if (curpeer->conf.auth.method) { + if (curpeer->auth_conf.method) { yyerror("auth method cannot be redefined"); free($4); YYERROR; } - if (str2key($4, curpeer->conf.auth.md5key, - sizeof(curpeer->conf.auth.md5key)) == -1) { + if (str2key($4, curpeer->auth_conf.md5key, + sizeof(curpeer->auth_conf.md5key)) == -1) { free($4); YYERROR; } - curpeer->conf.auth.method = AUTH_MD5SIG; - curpeer->conf.auth.md5key_len = strlen($4) / 2; + curpeer->auth_conf.method = AUTH_MD5SIG; + curpeer->auth_conf.md5key_len = strlen($4) / 2; free($4); } | IPSEC espah IKE { - if (curpeer->conf.auth.method) { + if (curpeer->auth_conf.method) { yyerror("auth method cannot be redefined"); YYERROR; } if ($2) - curpeer->conf.auth.method = AUTH_IPSEC_IKE_ESP; + curpeer->auth_conf.method = AUTH_IPSEC_IKE_ESP; else - curpeer->conf.auth.method = AUTH_IPSEC_IKE_AH; + curpeer->auth_conf.method = AUTH_IPSEC_IKE_AH; } | IPSEC espah inout SPI NUMBER STRING STRING encspec { enum auth_alg auth_alg; uint8_t keylen; - if (curpeer->conf.auth.method && - (((curpeer->conf.auth.spi_in && $3 == 1) || - (curpeer->conf.auth.spi_out && $3 == 0)) || - ($2 == 1 && curpeer->conf.auth.method != + if (curpeer->auth_conf.method && + (((curpeer->auth_conf.spi_in && $3 == 1) || + (curpeer->auth_conf.spi_out && $3 == 0)) || + ($2 == 1 && curpeer->auth_conf.method != AUTH_IPSEC_MANUAL_ESP) || - ($2 == 0 && curpeer->conf.auth.method != + ($2 == 0 && curpeer->auth_conf.method != AUTH_IPSEC_MANUAL_AH))) { yyerror("auth method cannot be redefined"); free($6); @@ -2158,7 +2158,7 @@ peeropts : REMOTEAS as4number { } if ($2) - curpeer->conf.auth.method = + curpeer->auth_conf.method = AUTH_IPSEC_MANUAL_ESP; else { if ($8.enc_alg) { @@ -2167,7 +2167,7 @@ peeropts : REMOTEAS as4number { free($7); YYERROR; } - curpeer->conf.auth.method = + curpeer->auth_conf.method = AUTH_IPSEC_MANUAL_AH; } @@ -2178,37 +2178,37 @@ peeropts : REMOTEAS as4number { } if ($3 == 1) { - if (str2key($7, curpeer->conf.auth.auth_key_in, - sizeof(curpeer->conf.auth.auth_key_in)) == + if (str2key($7, curpeer->auth_conf.auth_key_in, + sizeof(curpeer->auth_conf.auth_key_in)) == -1) { free($7); YYERROR; } - curpeer->conf.auth.spi_in = $5; - curpeer->conf.auth.auth_alg_in = auth_alg; - curpeer->conf.auth.enc_alg_in = $8.enc_alg; - memcpy(&curpeer->conf.auth.enc_key_in, + curpeer->auth_conf.spi_in = $5; + curpeer->auth_conf.auth_alg_in = auth_alg; + curpeer->auth_conf.enc_alg_in = $8.enc_alg; + memcpy(&curpeer->auth_conf.enc_key_in, &$8.enc_key, - sizeof(curpeer->conf.auth.enc_key_in)); - curpeer->conf.auth.enc_keylen_in = + sizeof(curpeer->auth_conf.enc_key_in)); + curpeer->auth_conf.enc_keylen_in = $8.enc_key_len; - curpeer->conf.auth.auth_keylen_in = keylen; + curpeer->auth_conf.auth_keylen_in = keylen; } else { - if (str2key($7, curpeer->conf.auth.auth_key_out, - sizeof(curpeer->conf.auth.auth_key_out)) == + if (str2key($7, curpeer->auth_conf.auth_key_out, + sizeof(curpeer->auth_conf.auth_key_out)) == -1) { free($7); YYERROR; } - curpeer->conf.auth.spi_out = $5; - curpeer->conf.auth.auth_alg_out = auth_alg; - curpeer->conf.auth.enc_alg_out = $8.enc_alg; - memcpy(&curpeer->conf.auth.enc_key_out, + curpeer->auth_conf.spi_out = $5; + curpeer->auth_conf.auth_alg_out = auth_alg; + curpeer->auth_conf.enc_alg_out = $8.enc_alg; + memcpy(&curpeer->auth_conf.enc_key_out, &$8.enc_key, - sizeof(curpeer->conf.auth.enc_key_out)); - curpeer->conf.auth.enc_keylen_out = + sizeof(curpeer->auth_conf.enc_key_out)); + curpeer->auth_conf.enc_keylen_out = $8.enc_key_len; - curpeer->conf.auth.auth_keylen_out = keylen; + curpeer->auth_conf.auth_keylen_out = keylen; } free($7); } @@ -5073,10 +5073,10 @@ neighbor_consistent(struct peer *p) } /* with any form of ipsec local-address is required */ - if ((p->conf.auth.method == AUTH_IPSEC_IKE_ESP || - p->conf.auth.method == AUTH_IPSEC_IKE_AH || - p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP || - p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) && + if ((p->auth_conf.method == AUTH_IPSEC_IKE_ESP || + p->auth_conf.method == AUTH_IPSEC_IKE_AH || + p->auth_conf.method == AUTH_IPSEC_MANUAL_ESP || + p->auth_conf.method == AUTH_IPSEC_MANUAL_AH) && local_addr->aid == AID_UNSPEC) { yyerror("neighbors with any form of IPsec configured " "need local-address to be specified"); @@ -5084,9 +5084,9 @@ neighbor_consistent(struct peer *p) } /* with static keying we need both directions */ - if ((p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP || - p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) && - (!p->conf.auth.spi_in || !p->conf.auth.spi_out)) { + if ((p->auth_conf.method == AUTH_IPSEC_MANUAL_ESP || + p->auth_conf.method == AUTH_IPSEC_MANUAL_AH) && + (!p->auth_conf.spi_in || !p->auth_conf.spi_out)) { yyerror("with manual keyed IPsec, SPIs and keys " "for both directions are required"); return (-1); diff --git a/usr.sbin/bgpd/pfkey.c b/usr.sbin/bgpd/pfkey.c index 7918775978e..d300e99d335 100644 --- a/usr.sbin/bgpd/pfkey.c +++ b/usr.sbin/bgpd/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.68 2022/11/07 22:39:13 mbuhl Exp $ */ +/* $OpenBSD: pfkey.c,v 1.69 2024/10/01 11:49:24 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -45,31 +45,19 @@ static uint32_t sadb_msg_seq = 0; static uint32_t pid = 0; /* should pid_t but pfkey needs uint32_t */ static int pfkey_fd; -int pfkey_reply(int, uint32_t *); -int pfkey_send(int, uint8_t, uint8_t, uint8_t, - struct bgpd_addr *, struct bgpd_addr *, - uint32_t, uint8_t, int, char *, uint8_t, int, char *, - uint16_t, uint16_t); +static int pfkey_reply(int, uint32_t *); +static int pfkey_send(int, uint8_t, uint8_t, uint8_t, + const struct bgpd_addr *, const struct bgpd_addr *, + uint32_t, uint8_t, int, char *, uint8_t, int, char *, + uint16_t, uint16_t); #define pfkey_flow(fd, satype, cmd, dir, from, to, sport, dport) \ pfkey_send(fd, satype, cmd, dir, from, to, \ 0, 0, 0, NULL, 0, 0, NULL, sport, dport) -static struct bgpd_addr * -pfkey_localaddr(struct peer *p) -{ - switch (p->conf.remote_addr.aid) { - case AID_INET: - return &p->conf.local_addr_v4; - case AID_INET6: - return &p->conf.local_addr_v6; - } - fatalx("Unknown AID in pfkey_localaddr"); -} - -int +static int pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir, - struct bgpd_addr *src, struct bgpd_addr *dst, uint32_t spi, + const struct bgpd_addr *src, const struct bgpd_addr *dst, uint32_t spi, uint8_t aalg, int alen, char *akey, uint8_t ealg, int elen, char *ekey, uint16_t sport, uint16_t dport) { @@ -447,7 +435,7 @@ pfkey_read(int sd, struct sadb_msg *h) return (1); } -int +static int pfkey_reply(int sd, uint32_t *spi) { struct sadb_msg hdr, *msg; @@ -511,8 +499,8 @@ pfkey_reply(int sd, uint32_t *spi) } static int -pfkey_sa_add(struct bgpd_addr *src, struct bgpd_addr *dst, uint8_t keylen, - char *key, uint32_t *spi) +pfkey_sa_add(const struct bgpd_addr *src, const struct bgpd_addr *dst, + uint8_t keylen, char *key, uint32_t *spi) { if (pfkey_send(pfkey_fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_GETSPI, 0, src, dst, 0, 0, 0, NULL, 0, 0, NULL, 0, 0) == -1) @@ -528,7 +516,8 @@ pfkey_sa_add(struct bgpd_addr *src, struct bgpd_addr *dst, uint8_t keylen, } static int -pfkey_sa_remove(struct bgpd_addr *src, struct bgpd_addr *dst, uint32_t *spi) +pfkey_sa_remove(const struct bgpd_addr *src, const struct bgpd_addr *dst, + uint32_t *spi) { if (pfkey_send(pfkey_fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_DELETE, 0, src, dst, *spi, 0, 0, NULL, 0, 0, NULL, 0, 0) == -1) @@ -540,56 +529,54 @@ pfkey_sa_remove(struct bgpd_addr *src, struct bgpd_addr *dst, uint32_t *spi) } static int -pfkey_md5sig_establish(struct peer *p) +pfkey_md5sig_establish(struct auth_state *as, struct auth_config *auth, + const struct bgpd_addr *local_addr, const struct bgpd_addr *remote_addr) { uint32_t spi_out = 0; uint32_t spi_in = 0; - if (pfkey_sa_add(pfkey_localaddr(p), &p->conf.remote_addr, - p->conf.auth.md5key_len, p->conf.auth.md5key, - &spi_out) == -1) + if (pfkey_sa_add(local_addr, remote_addr, + auth->md5key_len, auth->md5key, &spi_out) == -1) goto fail; - if (pfkey_sa_add(&p->conf.remote_addr, pfkey_localaddr(p), - p->conf.auth.md5key_len, p->conf.auth.md5key, - &spi_in) == -1) + if (pfkey_sa_add(remote_addr, local_addr, + auth->md5key_len, auth->md5key, &spi_in) == -1) goto fail; /* cleanup old flow if one was present */ - if (p->auth.established) { - if (pfkey_remove(p) == -1) + if (as->established) { + if (pfkey_remove(as) == -1) return (-1); } - p->auth.established = 1; - p->auth.spi_out = spi_out; - p->auth.spi_in = spi_in; + as->established = 1; + as->method = auth->method; + as->local_addr = *local_addr; + as->remote_addr = *remote_addr; + as->spi_out = spi_out; + as->spi_in = spi_in; return (0); fail: - log_peer_warn(&p->conf, "failed to insert md5sig"); return (-1); } static int -pfkey_md5sig_remove(struct peer *p) +pfkey_md5sig_remove(struct auth_state *as) { - if (p->auth.spi_out) - if (pfkey_sa_remove(&p->auth.local_addr, &p->conf.remote_addr, - &p->auth.spi_out) == -1) + if (as->spi_out) + if (pfkey_sa_remove(&as->local_addr, &as->remote_addr, + &as->spi_out) == -1) goto fail; - if (p->auth.spi_in) - if (pfkey_sa_remove(&p->conf.remote_addr, &p->auth.local_addr, - &p->auth.spi_in) == -1) + if (as->spi_in) + if (pfkey_sa_remove(&as->remote_addr, &as->local_addr, + &as->spi_in) == -1) goto fail; - p->auth.established = 0; - p->auth.spi_out = 0; - p->auth.spi_in = 0; + explicit_bzero(as, sizeof(*as)); return (0); fail: - log_peer_warn(&p->conf, "failed to remove md5sig"); return (-1); } @@ -620,18 +607,18 @@ pfkey_enc_alg(enum auth_enc_alg alg) } static int -pfkey_ipsec_establish(struct peer *p) +pfkey_ipsec_establish(struct auth_state *as, struct auth_config *auth, + const struct bgpd_addr *local_addr, const struct bgpd_addr *remote_addr) { uint8_t satype = SADB_SATYPE_ESP; - struct bgpd_addr *local_addr = pfkey_localaddr(p); /* cleanup first, unlike in the TCP MD5 case */ - if (p->auth.established) { - if (pfkey_remove(p) == -1) + if (as->established) { + if (pfkey_remove(as) == -1) return (-1); } - switch (p->auth.method) { + switch (auth->method) { case AUTH_IPSEC_IKE_ESP: satype = SADB_SATYPE_ESP; break; @@ -640,30 +627,30 @@ pfkey_ipsec_establish(struct peer *p) break; case AUTH_IPSEC_MANUAL_ESP: case AUTH_IPSEC_MANUAL_AH: - satype = p->auth.method == AUTH_IPSEC_MANUAL_ESP ? + satype = auth->method == AUTH_IPSEC_MANUAL_ESP ? SADB_SATYPE_ESP : SADB_SATYPE_AH; if (pfkey_send(pfkey_fd, satype, SADB_ADD, 0, - local_addr, &p->conf.remote_addr, - p->conf.auth.spi_out, - pfkey_auth_alg(p->conf.auth.auth_alg_out), - p->conf.auth.auth_keylen_out, - p->conf.auth.auth_key_out, - pfkey_enc_alg(p->conf.auth.enc_alg_out), - p->conf.auth.enc_keylen_out, - p->conf.auth.enc_key_out, + local_addr, remote_addr, + auth->spi_out, + pfkey_auth_alg(auth->auth_alg_out), + auth->auth_keylen_out, + auth->auth_key_out, + pfkey_enc_alg(auth->enc_alg_out), + auth->enc_keylen_out, + auth->enc_key_out, 0, 0) == -1) goto fail_key; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_key; if (pfkey_send(pfkey_fd, satype, SADB_ADD, 0, - &p->conf.remote_addr, local_addr, - p->conf.auth.spi_in, - pfkey_auth_alg(p->conf.auth.auth_alg_in), - p->conf.auth.auth_keylen_in, - p->conf.auth.auth_key_in, - pfkey_enc_alg(p->conf.auth.enc_alg_in), - p->conf.auth.enc_keylen_in, - p->conf.auth.enc_key_in, + remote_addr, local_addr, + auth->spi_in, + pfkey_auth_alg(auth->auth_alg_in), + auth->auth_keylen_in, + auth->auth_key_in, + pfkey_enc_alg(auth->enc_alg_in), + auth->enc_keylen_in, + auth->enc_key_in, 0, 0) == -1) goto fail_key; if (pfkey_reply(pfkey_fd, NULL) == -1) @@ -674,49 +661,52 @@ pfkey_ipsec_establish(struct peer *p) } if (pfkey_flow(pfkey_fd, satype, SADB_X_ADDFLOW, IPSP_DIRECTION_OUT, - local_addr, &p->conf.remote_addr, 0, BGP_PORT) == -1) + local_addr, remote_addr, 0, BGP_PORT) == -1) goto fail_flow; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_flow; if (pfkey_flow(pfkey_fd, satype, SADB_X_ADDFLOW, IPSP_DIRECTION_OUT, - local_addr, &p->conf.remote_addr, BGP_PORT, 0) == -1) + local_addr, remote_addr, BGP_PORT, 0) == -1) goto fail_flow; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_flow; if (pfkey_flow(pfkey_fd, satype, SADB_X_ADDFLOW, IPSP_DIRECTION_IN, - &p->conf.remote_addr, local_addr, 0, BGP_PORT) == -1) + remote_addr, local_addr, 0, BGP_PORT) == -1) goto fail_flow; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_flow; if (pfkey_flow(pfkey_fd, satype, SADB_X_ADDFLOW, IPSP_DIRECTION_IN, - &p->conf.remote_addr, local_addr, BGP_PORT, 0) == -1) + remote_addr, local_addr, BGP_PORT, 0) == -1) goto fail_flow; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_flow; /* save SPI so that they can be removed later on */ - p->auth.spi_in = p->conf.auth.spi_in; - p->auth.spi_out = p->conf.auth.spi_out; - p->auth.established = 1; + as->established = 1; + as->method = auth->method; + as->local_addr = *local_addr; + as->remote_addr = *remote_addr; + as->spi_in = auth->spi_in; + as->spi_out = auth->spi_out; return (0); fail_key: - log_peer_warn(&p->conf, "failed to insert ipsec key"); + log_warn("failed to insert ipsec key"); return (-1); fail_flow: - log_peer_warn(&p->conf, "failed to insert ipsec flow"); + log_warn("failed to insert ipsec flow"); return (-1); } static int -pfkey_ipsec_remove(struct peer *p) +pfkey_ipsec_remove(struct auth_state *as) { uint8_t satype; - switch (p->auth.method) { + switch (as->method) { case AUTH_IPSEC_IKE_ESP: satype = SADB_SATYPE_ESP; break; @@ -725,20 +715,18 @@ pfkey_ipsec_remove(struct peer *p) break; case AUTH_IPSEC_MANUAL_ESP: case AUTH_IPSEC_MANUAL_AH: - satype = p->auth.method == AUTH_IPSEC_MANUAL_ESP ? + satype = as->method == AUTH_IPSEC_MANUAL_ESP ? SADB_SATYPE_ESP : SADB_SATYPE_AH; if (pfkey_send(pfkey_fd, satype, SADB_DELETE, 0, - &p->auth.local_addr, &p->conf.remote_addr, - p->auth.spi_out, 0, 0, NULL, 0, 0, NULL, - 0, 0) == -1) + &as->local_addr, &as->remote_addr, + as->spi_out, 0, 0, NULL, 0, 0, NULL, 0, 0) == -1) goto fail_key; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_key; if (pfkey_send(pfkey_fd, satype, SADB_DELETE, 0, - &p->conf.remote_addr, &p->auth.local_addr, - p->auth.spi_in, 0, 0, NULL, 0, 0, NULL, - 0, 0) == -1) + &as->remote_addr, &as->local_addr, + as->spi_in, 0, 0, NULL, 0, 0, NULL, 0, 0) == -1) goto fail_key; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_key; @@ -748,88 +736,75 @@ pfkey_ipsec_remove(struct peer *p) } if (pfkey_flow(pfkey_fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_OUT, - &p->auth.local_addr, &p->conf.remote_addr, 0, BGP_PORT) == -1) + &as->local_addr, &as->remote_addr, 0, BGP_PORT) == -1) goto fail_flow; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_flow; if (pfkey_flow(pfkey_fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_OUT, - &p->auth.local_addr, &p->conf.remote_addr, BGP_PORT, 0) == -1) + &as->local_addr, &as->remote_addr, BGP_PORT, 0) == -1) goto fail_flow; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_flow; if (pfkey_flow(pfkey_fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_IN, - &p->conf.remote_addr, &p->auth.local_addr, 0, BGP_PORT) == -1) + &as->remote_addr, &as->local_addr, 0, BGP_PORT) == -1) goto fail_flow; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_flow; if (pfkey_flow(pfkey_fd, satype, SADB_X_DELFLOW, IPSP_DIRECTION_IN, - &p->conf.remote_addr, &p->auth.local_addr, BGP_PORT, 0) == -1) + &as->remote_addr, &as->local_addr, BGP_PORT, 0) == -1) goto fail_flow; if (pfkey_reply(pfkey_fd, NULL) == -1) goto fail_flow; - p->auth.established = 0; - p->auth.spi_out = 0; - p->auth.spi_in = 0; + explicit_bzero(as, sizeof(*as)); return (0); fail_key: - log_peer_warn(&p->conf, "failed to remove ipsec key"); + log_warn("failed to remove ipsec key"); return (-1); fail_flow: - log_peer_warn(&p->conf, "failed to remove ipsec flow"); + log_warn("failed to remove ipsec flow"); return (-1); } int -pfkey_establish(struct peer *p) +pfkey_establish(struct auth_state *as, struct auth_config *auth, + const struct bgpd_addr *local_addr, const struct bgpd_addr *remote_addr) { int rv; - switch (p->conf.auth.method) { + switch (auth->method) { case AUTH_NONE: rv = 0; - if (p->auth.established) - rv = pfkey_remove(p); + if (as->established) + rv = pfkey_remove(as); break; case AUTH_MD5SIG: - rv = pfkey_md5sig_establish(p); + rv = pfkey_md5sig_establish(as, auth, local_addr, remote_addr); break; default: - rv = pfkey_ipsec_establish(p); + rv = pfkey_ipsec_establish(as, auth, local_addr, remote_addr); break; } - /* - * make sure we keep copies of everything we need to - * remove SAs and flows later again, even if the - * info in p->conf changed due to reload. - * We need: SPIs, method, local_addr, remote_addr. - * remote_addr cannot change, so no copy, SPI are - * handled by the method specific functions. - */ - memcpy(&p->auth.local_addr, pfkey_localaddr(p), - sizeof(p->auth.local_addr)); - p->auth.method = p->conf.auth.method; - return (rv); } int -pfkey_remove(struct peer *p) +pfkey_remove(struct auth_state *as) { - if (p->auth.established == 0) + if (as->established == 0) return (0); - switch (p->auth.method) { + switch (as->method) { case AUTH_NONE: return (0); case AUTH_MD5SIG: - return (pfkey_md5sig_remove(p)); + return (pfkey_md5sig_remove(as)); default: - return (pfkey_ipsec_remove(p)); + return (pfkey_ipsec_remove(as)); } } @@ -847,26 +822,40 @@ pfkey_init(void) return (pfkey_fd); } +int +pfkey_send_conf(struct imsgbuf *imsgbuf, uint32_t id, struct auth_config *auth) +{ + /* SE only needs the auth method */ + return imsg_compose(imsgbuf, IMSG_RECONF_PEER_AUTH, id, 0, -1, + &auth->method, sizeof(auth->method)); +} + +int +pfkey_recv_conf(struct peer *p, struct imsg *imsg) +{ + struct auth_config *auth = &p->auth_conf; + + return imsg_get_data(imsg, &auth->method, sizeof(auth->method)); +} + /* verify that connection is using TCP MD5UM if required by config */ int -tcp_md5_check(int fd, struct peer *p) +tcp_md5_check(int fd, struct auth_config *auth) { socklen_t len; int opt; - if (p->conf.auth.method == AUTH_MD5SIG) { + if (auth->method == AUTH_MD5SIG) { if (sysdep.no_md5sig) { - log_peer_warnx(&p->conf, - "md5sig configured but not available"); + errno = ENOPROTOOPT; return -1; } len = sizeof(opt); if (getsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt, &len) == -1) - fatal("getsockopt TCP_MD5SIG"); + return -1; if (!opt) { /* non-md5'd connection! */ - log_peer_warnx(&p->conf, - "connection attempt without md5 signature"); + errno = ECONNREFUSED; return -1; } } @@ -875,21 +864,18 @@ tcp_md5_check(int fd, struct peer *p) /* enable or set TCP MD5SIG on a new client connection */ int -tcp_md5_set(int fd, struct peer *p) +tcp_md5_set(int fd, struct auth_config *auth, struct bgpd_addr *remote_addr) { int opt = 1; - if (p->conf.auth.method == AUTH_MD5SIG) { + if (auth->method == AUTH_MD5SIG) { if (sysdep.no_md5sig) { - log_peer_warnx(&p->conf, - "md5sig configured but not available"); + errno = ENOPROTOOPT; return -1; } if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, - &opt, sizeof(opt)) == -1) { - log_peer_warn(&p->conf, "setsockopt md5sig"); + &opt, sizeof(opt)) == -1) return -1; - } } return 0; } diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index 8aeeeeeee65..e34380ffd38 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.174 2024/08/14 19:09:51 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.175 2024/10/01 11:49:24 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -45,8 +45,7 @@ void print_originsets(struct prefixset_head *); void print_roa(struct roa_tree *); void print_aspa(struct aspa_tree *); void print_rtrs(struct rtr_config_head *); -void print_peer(struct peer_config *, struct bgpd_config *, - const char *); +void print_peer(struct peer *, struct bgpd_config *, const char *); const char *print_auth_alg(enum auth_alg); const char *print_enc_alg(enum auth_enc_alg); void print_announce(struct peer_config *, const char *); @@ -729,10 +728,12 @@ print_rtrs(struct rtr_config_head *rh) } void -print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c) +print_peer(struct peer *peer, struct bgpd_config *conf, const char *c) { - char *method; - struct in_addr ina; + struct in_addr ina; + char *method; + struct peer_config *p = &peer->conf; + struct auth_config *auth = &peer->auth_conf; if ((p->remote_addr.aid == AID_INET && p->remote_masklen != 32) || (p->remote_addr.aid == AID_INET6 && p->remote_masklen != 128)) @@ -831,30 +832,30 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c) if (p->flags & PEERFLAG_LOG_UPDATES) printf("%s\tlog updates\n", c); - if (p->auth.method == AUTH_MD5SIG) + if (auth->method == AUTH_MD5SIG) printf("%s\ttcp md5sig\n", c); - else if (p->auth.method == AUTH_IPSEC_MANUAL_ESP || - p->auth.method == AUTH_IPSEC_MANUAL_AH) { - if (p->auth.method == AUTH_IPSEC_MANUAL_ESP) + else if (auth->method == AUTH_IPSEC_MANUAL_ESP || + auth->method == AUTH_IPSEC_MANUAL_AH) { + if (auth->method == AUTH_IPSEC_MANUAL_ESP) method = "esp"; else method = "ah"; printf("%s\tipsec %s in spi %u %s XXXXXX", c, method, - p->auth.spi_in, print_auth_alg(p->auth.auth_alg_in)); - if (p->auth.enc_alg_in) - printf(" %s XXXXXX", print_enc_alg(p->auth.enc_alg_in)); + auth->spi_in, print_auth_alg(auth->auth_alg_in)); + if (auth->enc_alg_in) + printf(" %s XXXXXX", print_enc_alg(auth->enc_alg_in)); printf("\n"); printf("%s\tipsec %s out spi %u %s XXXXXX", c, method, - p->auth.spi_out, print_auth_alg(p->auth.auth_alg_out)); - if (p->auth.enc_alg_out) + auth->spi_out, print_auth_alg(auth->auth_alg_out)); + if (auth->enc_alg_out) printf(" %s XXXXXX", - print_enc_alg(p->auth.enc_alg_out)); + print_enc_alg(auth->enc_alg_out)); printf("\n"); - } else if (p->auth.method == AUTH_IPSEC_IKE_AH) + } else if (auth->method == AUTH_IPSEC_IKE_AH) printf("%s\tipsec ah ike\n", c); - else if (p->auth.method == AUTH_IPSEC_IKE_ESP) + else if (auth->method == AUTH_IPSEC_IKE_ESP) printf("%s\tipsec esp ike\n", c); if (p->ttlsec) @@ -1196,39 +1197,36 @@ print_mrt(struct bgpd_config *conf, uint32_t pid, uint32_t gid, void print_groups(struct bgpd_config *conf) { - struct peer_config **peerlist; - struct peer *p; - u_int peer_cnt, i; - uint32_t prev_groupid; - const char *tab = "\t"; - const char *nada = ""; - const char *c; + struct peer **peerlist; + struct peer *p; + u_int peer_cnt, i; + uint32_t prev_groupid; + const char *c; peer_cnt = 0; RB_FOREACH(p, peer_head, &conf->peers) peer_cnt++; - - if ((peerlist = calloc(peer_cnt, sizeof(struct peer_config *))) == NULL) + if ((peerlist = calloc(peer_cnt, sizeof(*peerlist))) == NULL) fatal("print_groups calloc"); - i = 0; RB_FOREACH(p, peer_head, &conf->peers) - peerlist[i++] = &p->conf; + peerlist[i++] = p; - qsort(peerlist, peer_cnt, sizeof(struct peer_config *), peer_compare); + qsort(peerlist, peer_cnt, sizeof(*peerlist), peer_compare); prev_groupid = 0; for (i = 0; i < peer_cnt; i++) { - if (peerlist[i]->groupid) { - c = tab; - if (peerlist[i]->groupid != prev_groupid) { + if (peerlist[i]->conf.groupid) { + c = "\t"; + if (peerlist[i]->conf.groupid != prev_groupid) { if (prev_groupid) printf("}\n\n"); - printf("group \"%s\" {\n", peerlist[i]->group); - prev_groupid = peerlist[i]->groupid; + printf("group \"%s\" {\n", + peerlist[i]->conf.group); + prev_groupid = peerlist[i]->conf.groupid; } } else - c = nada; + c = ""; print_peer(peerlist[i], conf, c); } @@ -1242,13 +1240,13 @@ print_groups(struct bgpd_config *conf) int peer_compare(const void *aa, const void *bb) { - const struct peer_config * const *a; - const struct peer_config * const *b; + const struct peer * const *a; + const struct peer * const *b; a = aa; b = bb; - return ((*a)->groupid - (*b)->groupid); + return ((*a)->conf.groupid - (*b)->conf.groupid); } void diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index c176edb6797..a4234006a93 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.482 2024/09/09 12:59:49 claudio Exp $ */ +/* $OpenBSD: session.c,v 1.483 2024/10/01 11:49:24 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer @@ -1032,14 +1032,15 @@ session_accept(int listenfd) } open: - if (p->conf.auth.method != AUTH_NONE && sysdep.no_pfkey) { + if (p->auth_conf.method != AUTH_NONE && sysdep.no_pfkey) { log_peer_warnx(&p->conf, "ipsec or md5sig configured but not available"); close(connfd); return; } - if (tcp_md5_check(connfd, p) == -1) { + if (tcp_md5_check(connfd, &p->auth_conf) == -1) { + log_peer_warn(&p->conf, "check md5sig"); close(connfd); return; } @@ -1066,7 +1067,7 @@ int session_connect(struct peer *peer) { struct sockaddr *sa; - struct bgpd_addr *bind_addr = NULL; + struct bgpd_addr *bind_addr; socklen_t sa_len; /* @@ -1084,25 +1085,20 @@ session_connect(struct peer *peer) return (-1); } - if (peer->conf.auth.method != AUTH_NONE && sysdep.no_pfkey) { + if (peer->auth_conf.method != AUTH_NONE && sysdep.no_pfkey) { log_peer_warnx(&peer->conf, "ipsec or md5sig configured but not available"); bgp_fsm(peer, EVNT_CON_OPENFAIL); return (-1); } - tcp_md5_set(peer->fd, peer); + if (tcp_md5_set(peer->fd, &peer->auth_conf, + &peer->conf.remote_addr) == -1) + log_peer_warn(&peer->conf, "setting md5sig"); peer->wbuf.fd = peer->fd; /* if local-address is set we need to bind() */ - switch (peer->conf.remote_addr.aid) { - case AID_INET: - bind_addr = &peer->conf.local_addr_v4; - break; - case AID_INET6: - bind_addr = &peer->conf.local_addr_v6; - break; - } + bind_addr = session_localaddr(peer); if ((sa = addr2sa(bind_addr, 0, &sa_len)) != NULL) { if (bind(peer->fd, sa, sa_len) == -1) { log_peer_warn(&peer->conf, "session_connect bind"); @@ -3003,6 +2999,16 @@ session_dispatch_imsg(struct imsgbuf *imsgbuf, int idx, u_int *listener_cnt) if (RB_INSERT(peer_head, &nconf->peers, p) != NULL) fatalx("%s: peer tree is corrupt", __func__); break; + case IMSG_RECONF_PEER_AUTH: + if (idx != PFD_PIPE_MAIN) + fatalx("reconf request not from parent"); + if ((p = getpeerbyid(nconf, peerid)) == NULL) { + log_warnx("no such peer: id=%u", peerid); + break; + } + if (pfkey_recv_conf(p, &imsg) == -1) + fatal("pfkey_recv_conf"); + break; case IMSG_RECONF_LISTENER: if (idx != PFD_PIPE_MAIN) fatalx("reconf request not from parent"); @@ -3641,6 +3647,18 @@ session_stop(struct peer *peer, uint8_t subcode, const char *reason) bgp_fsm(peer, EVNT_STOP); } +struct bgpd_addr * +session_localaddr(struct peer *p) +{ + switch (p->conf.remote_addr.aid) { + case AID_INET: + return &p->conf.local_addr_v4; + case AID_INET6: + return &p->conf.local_addr_v6; + } + fatalx("Unknown AID in %s", __func__); +} + void merge_peers(struct bgpd_config *c, struct bgpd_config *nc) { @@ -3657,10 +3675,10 @@ merge_peers(struct bgpd_config *c, struct bgpd_config *nc) } /* peer no longer uses TCP MD5SIG so deconfigure */ - if (p->conf.auth.method == AUTH_MD5SIG && - np->conf.auth.method != AUTH_MD5SIG) + if (p->auth_conf.method == AUTH_MD5SIG && + np->auth_conf.method != AUTH_MD5SIG) tcp_md5_del_listener(c, p); - else if (np->conf.auth.method == AUTH_MD5SIG) + else if (np->auth_conf.method == AUTH_MD5SIG) tcp_md5_add_listener(c, np); memcpy(&p->conf, &np->conf, sizeof(p->conf)); @@ -3706,7 +3724,7 @@ merge_peers(struct bgpd_config *c, struct bgpd_config *nc) RB_REMOVE(peer_head, &nc->peers, np); if (RB_INSERT(peer_head, &c->peers, np) != NULL) fatalx("%s: peer tree is corrupt", __func__); - if (np->conf.auth.method == AUTH_MD5SIG) + if (np->auth_conf.method == AUTH_MD5SIG) tcp_md5_add_listener(c, np); } } diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h index 12e871eef4d..38c624cb8e3 100644 --- a/usr.sbin/bgpd/session.h +++ b/usr.sbin/bgpd/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.173 2024/09/04 13:30:10 claudio Exp $ */ +/* $OpenBSD: session.h,v 1.174 2024/10/01 11:49:24 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -163,6 +163,15 @@ struct peer_stats { char last_reason[REASON_LEN]; }; +struct auth_state { + struct bgpd_addr local_addr; + struct bgpd_addr remote_addr; + uint32_t spi_in; + uint32_t spi_out; + enum auth_method method; + uint8_t established; +}; + enum Timer { Timer_None, Timer_ConnectRetry, @@ -197,13 +206,8 @@ struct peer { struct capabilities peer; struct capabilities neg; } capa; - struct { - struct bgpd_addr local_addr; - uint32_t spi_in; - uint32_t spi_out; - enum auth_method method; - uint8_t established; - } auth; + struct auth_state auth_state; + struct auth_config auth_conf; struct bgpd_addr local; struct bgpd_addr local_alt; struct bgpd_addr remote; @@ -278,11 +282,14 @@ void mrt_done(struct mrt *); /* pfkey.c */ struct sadb_msg; int pfkey_read(int, struct sadb_msg *); -int pfkey_establish(struct peer *); -int pfkey_remove(struct peer *); +int pfkey_establish(struct auth_state *, struct auth_config *, + const struct bgpd_addr *, const struct bgpd_addr *); +int pfkey_remove(struct auth_state *); int pfkey_init(void); -int tcp_md5_check(int, struct peer *); -int tcp_md5_set(int, struct peer *); +int pfkey_send_conf(struct imsgbuf *, uint32_t, struct auth_config *); +int pfkey_recv_conf(struct peer *, struct imsg *); +int tcp_md5_check(int, struct auth_config *); +int tcp_md5_set(int, struct auth_config *, struct bgpd_addr *); int tcp_md5_prep_listener(struct listen_addr *, struct peer_head *); void tcp_md5_add_listener(struct bgpd_config *, struct peer *); void tcp_md5_del_listener(struct bgpd_config *, struct peer *); @@ -334,6 +341,7 @@ int imsg_ctl_parent(struct imsg *); int imsg_ctl_rde(struct imsg *); int imsg_ctl_rde_msg(int, uint32_t, pid_t); void session_stop(struct peer *, uint8_t, const char *); +struct bgpd_addr *session_localaddr(struct peer *); /* timer.c */ struct timer *timer_get(struct timer_head *, enum Timer); -- 2.20.1