local-address is one of those values that need to be set in some cases but
is not very flexible to use. This diff tries to change this a bit.
It allows to set the local-address for both IPv4 and IPv6 at the same time
and also allows to unset a previously set local-address. For example:
group IBGP {
local-address 192.0.2.1
local-address 2001:db8:abcd::1
neighbor 192.0.2.2 { remote-as $AS }
neighbor 2001:db8:abcd::2 { remote-as $AS }
# reset the local-address for whatever reason
neighbor 192.0.2.3 {
no local-address
remote-as $AS
}
}
As usual setting a local-address on the neighbor will override the group
config. I think for IBGP and multihop sessions this can simplify the
config a fair bit. In my case this will collaps IPv4 and IPv6 specific
groups back together since the only reason they are split is because of
local-address.
What do other bgpd user think?
--
:wq Claudio
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.401
diff -u -p -r1.401 bgpd.h
--- bgpd.h 14 Feb 2020 13:54:31 -0000 1.401
+++ bgpd.h 22 Apr 2020 15:50:46 -0000
@@ -365,7 +365,8 @@ struct capabilities {
struct peer_config {
struct bgpd_addr remote_addr;
- struct bgpd_addr local_addr;
+ struct bgpd_addr local_addr_v4;
+ struct bgpd_addr local_addr_v6;
struct peer_auth auth;
struct capabilities capabilities;
char group[PEER_DESCR_LEN];
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.405
diff -u -p -r1.405 parse.y
--- parse.y 16 Mar 2020 14:47:30 -0000 1.405
+++ parse.y 23 Apr 2020 07:51:25 -0000
@@ -1260,8 +1260,27 @@ peeropts : REMOTEAS as4number {
free($2);
}
| LOCALADDR address {
- memcpy(&curpeer->conf.local_addr, &$2,
- sizeof(curpeer->conf.local_addr));
+ if ($2.aid == AID_INET)
+ memcpy(&curpeer->conf.local_addr_v4, &$2,
+ sizeof(curpeer->conf.local_addr_v4));
+ else if ($2.aid == AID_INET6)
+ memcpy(&curpeer->conf.local_addr_v6, &$2,
+ sizeof(curpeer->conf.local_addr_v6));
+ else {
+ yyerror("Unsupported address family %s for "
+ "local-addr", aid2str($2.aid));
+ YYERROR;
+ }
+ }
+ | yesno LOCALADDR {
+ if ($1) {
+ yyerror("bad local-address definition");
+ YYERROR;
+ }
+ memset(&curpeer->conf.local_addr_v4, 0,
+ sizeof(curpeer->conf.local_addr_v4));
+ memset(&curpeer->conf.local_addr_v6, 0,
+ sizeof(curpeer->conf.local_addr_v6));
}
| MULTIHOP NUMBER {
if ($2 < 2 || $2 > 255) {
@@ -4176,11 +4195,17 @@ str2key(char *s, char *dest, size_t max_
int
neighbor_consistent(struct peer *p)
{
- /* local-address and peer's address: same address family */
- if (p->conf.local_addr.aid &&
- p->conf.local_addr.aid != p->conf.remote_addr.aid) {
- yyerror("local-address and neighbor address "
- "must be of the same address family");
+ struct bgpd_addr *local_addr;
+
+ switch (p->conf.remote_addr.aid) {
+ case AID_INET:
+ local_addr = &p->conf.local_addr_v4;
+ break;
+ case AID_INET6:
+ local_addr = &p->conf.local_addr_v6;
+ break;
+ default:
+ yyerror("Bad address family for remote-addr");
return (-1);
}
@@ -4189,7 +4214,7 @@ neighbor_consistent(struct peer *p)
p->conf.auth.method == AUTH_IPSEC_IKE_AH ||
p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP ||
p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) &&
- !p->conf.local_addr.aid) {
+ local_addr->aid == AID_UNSPEC) {
yyerror("neighbors with any form of IPsec configured "
"need local-address to be specified");
return (-1);
Index: pfkey.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/pfkey.c,v
retrieving revision 1.60
diff -u -p -r1.60 pfkey.c
--- pfkey.c 1 Oct 2019 11:05:30 -0000 1.60
+++ pfkey.c 22 Apr 2020 16:08:33 -0000
@@ -55,6 +55,18 @@ int pfkey_send(int, uint8_t, uint8_t, ui
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
pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
struct bgpd_addr *src, struct bgpd_addr *dst, u_int32_t spi,
@@ -530,12 +542,12 @@ pfkey_md5sig_establish(struct peer *p)
u_int32_t spi_out = 0;
u_int32_t spi_in = 0;
- if (pfkey_sa_add(&p->conf.local_addr, &p->conf.remote_addr,
+ if (pfkey_sa_add(pfkey_localaddr(p), &p->conf.remote_addr,
p->conf.auth.md5key_len, p->conf.auth.md5key,
&spi_out) == -1)
goto fail;
- if (pfkey_sa_add(&p->conf.remote_addr, &p->conf.local_addr,
+ if (pfkey_sa_add(&p->conf.remote_addr, pfkey_localaddr(p),
p->conf.auth.md5key_len, p->conf.auth.md5key,
&spi_in) == -1)
goto fail;
@@ -582,6 +594,7 @@ static int
pfkey_ipsec_establish(struct peer *p)
{
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) {
@@ -601,7 +614,7 @@ pfkey_ipsec_establish(struct peer *p)
satype = p->auth.method == AUTH_IPSEC_MANUAL_ESP ?
SADB_SATYPE_ESP : SADB_SATYPE_AH;
if (pfkey_send(pfkey_fd, satype, SADB_ADD, 0,
- &p->conf.local_addr, &p->conf.remote_addr,
+ local_addr, &p->conf.remote_addr,
p->conf.auth.spi_out,
p->conf.auth.auth_alg_out,
p->conf.auth.auth_keylen_out,
@@ -614,7 +627,7 @@ pfkey_ipsec_establish(struct peer *p)
if (pfkey_reply(pfkey_fd, NULL) == -1)
goto fail_key;
if (pfkey_send(pfkey_fd, satype, SADB_ADD, 0,
- &p->conf.remote_addr, &p->conf.local_addr,
+ &p->conf.remote_addr, local_addr,
p->conf.auth.spi_in,
p->conf.auth.auth_alg_in,
p->conf.auth.auth_keylen_in,
@@ -632,25 +645,25 @@ pfkey_ipsec_establish(struct peer *p)
}
if (pfkey_flow(pfkey_fd, satype, SADB_X_ADDFLOW, IPSP_DIRECTION_OUT,
- &p->conf.local_addr, &p->conf.remote_addr, 0, BGP_PORT) == -1)
+ local_addr, &p->conf.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,
- &p->conf.local_addr, &p->conf.remote_addr, BGP_PORT, 0) == -1)
+ local_addr, &p->conf.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, &p->conf.local_addr, 0, BGP_PORT) == -1)
+ &p->conf.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, &p->conf.local_addr, BGP_PORT, 0) == -1)
+ &p->conf.remote_addr, local_addr, BGP_PORT, 0) == -1)
goto fail_flow;
if (pfkey_reply(pfkey_fd, NULL) == -1)
goto fail_flow;
@@ -768,7 +781,7 @@ pfkey_establish(struct peer *p)
* remote_addr cannot change, so no copy, SPI are
* handled by the method specific functions.
*/
- memcpy(&p->auth.local_addr, &p->conf.local_addr,
+ memcpy(&p->auth.local_addr, pfkey_localaddr(p),
sizeof(p->auth.local_addr));
p->auth.method = p->conf.auth.method;
Index: printconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
retrieving revision 1.141
diff -u -p -r1.141 printconf.c
--- printconf.c 24 Jan 2020 05:44:05 -0000 1.141
+++ printconf.c 22 Apr 2020 16:09:18 -0000
@@ -608,8 +608,12 @@ print_peer(struct peer_config *p, struct
printf("%s\tmultihop %u\n", c, p->distance);
if (p->passive)
printf("%s\tpassive\n", c);
- if (p->local_addr.aid)
- printf("%s\tlocal-address %s\n", c, log_addr(&p->local_addr));
+ if (p->local_addr_v4.aid)
+ printf("%s\tlocal-address %s\n", c,
+ log_addr(&p->local_addr_v4));
+ if (p->local_addr_v6.aid)
+ printf("%s\tlocal-address %s\n", c,
+ log_addr(&p->local_addr_v6));
if (p->max_prefix) {
printf("%s\tmax-prefix %u", c, p->max_prefix);
if (p->max_prefix_restart)
Index: session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.399
diff -u -p -r1.399 session.c
--- session.c 12 Feb 2020 10:33:56 -0000 1.399
+++ session.c 22 Apr 2020 15:54:22 -0000
@@ -1039,6 +1039,7 @@ int
session_connect(struct peer *peer)
{
struct sockaddr *sa;
+ struct bgpd_addr *bind_addr = NULL;
socklen_t sa_len;
/*
@@ -1066,8 +1067,16 @@ session_connect(struct peer *peer)
tcp_md5_set(peer->fd, peer);
peer->wbuf.fd = peer->fd;
- /* if update source is set we need to bind() */
- if ((sa = addr2sa(&peer->conf.local_addr, 0, &sa_len)) != NULL) {
+ /* 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;
+ }
+ if (bind_addr && (sa = addr2sa(bind_addr, 0, &sa_len)) != NULL) {
if (bind(peer->fd, sa, sa_len) == -1) {
log_peer_warn(&peer->conf, "session_connect bind");
bgp_fsm(peer, EVNT_CON_OPENFAIL);
Index: util.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/util.c,v
retrieving revision 1.52
diff -u -p -r1.52 util.c
--- util.c 12 Feb 2020 10:33:56 -0000 1.52
+++ util.c 22 Apr 2020 15:54:02 -0000
@@ -844,7 +844,7 @@ addr2sa(struct bgpd_addr *addr, u_int16_
struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
- if (addr->aid == AID_UNSPEC)
+ if (addr == NULL || addr->aid == AID_UNSPEC)
return (NULL);
bzero(&ss, sizeof(ss));