BGP: Implement extended optional parameters length
Extends BGP options/capabilities data length to 16bit, to avoid issues with too many capabilities. See draft-ietf-idr-ext-opt-param-07
This commit is contained in:
parent
a297a4f044
commit
524d253853
3 changed files with 71 additions and 23 deletions
|
@ -38,7 +38,7 @@ struct align_probe { char x; long int y; };
|
||||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
|
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
|
||||||
#define BYTES(n) ((((uint) (n)) + 7) / 8)
|
#define BYTES(n) ((((uint) (n)) + 7) / 8)
|
||||||
#define CALL(fn, args...) ({ if (fn) fn(args); })
|
#define CALL(fn, args...) ({ if (fn) fn(args); })
|
||||||
#define ADVANCE(w, r, l) ({ r -= l; w += l; })
|
#define ADVANCE(w, r, l) ({ r -= (l); w += (l); })
|
||||||
|
|
||||||
static inline int uint_cmp(uint i1, uint i2)
|
static inline int uint_cmp(uint i1, uint i2)
|
||||||
{ return (int)(i1 > i2) - (int)(i1 < i2); }
|
{ return (int)(i1 > i2) - (int)(i1 < i2); }
|
||||||
|
|
|
@ -100,6 +100,7 @@
|
||||||
* RFC 8203 - BGP Administrative Shutdown Communication
|
* RFC 8203 - BGP Administrative Shutdown Communication
|
||||||
* RFC 8212 - Default EBGP Route Propagation Behavior without Policies
|
* RFC 8212 - Default EBGP Route Propagation Behavior without Policies
|
||||||
* draft-ietf-idr-bgp-extended-messages-27
|
* draft-ietf-idr-bgp-extended-messages-27
|
||||||
|
* draft-ietf-idr-ext-opt-param-07
|
||||||
* draft-uttaro-idr-bgp-persistence-04
|
* draft-uttaro-idr-bgp-persistence-04
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -294,8 +294,8 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that max length is ~ 22+21*af_count. With max 12 channels that is
|
* Note that max length is ~ 22+21*af_count. With max 12 channels that is
|
||||||
* 274. Option limit is 253 and buffer size is 4096, so we cannot overflow
|
* 274. We are limited just by buffer size (4096, minus header), as we support
|
||||||
* unless we add new capabilities or more AFs. XXXXX
|
* extended optional parameres. Therefore, we have enough space for expansion.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WALK_AF_CAPS(caps, ac)
|
WALK_AF_CAPS(caps, ac)
|
||||||
|
@ -411,7 +411,7 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, int len)
|
bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, int len)
|
||||||
{
|
{
|
||||||
struct bgp_proto *p = conn->bgp;
|
struct bgp_proto *p = conn->bgp;
|
||||||
|
@ -577,11 +577,11 @@ bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
bgp_error(conn, 2, 0, NULL, 0);
|
bgp_error(conn, 2, 0, NULL, 0);
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -621,36 +621,62 @@ bgp_check_capabilities(struct bgp_conn *conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bgp_read_options(struct bgp_conn *conn, byte *pos, int len)
|
bgp_read_options(struct bgp_conn *conn, byte *pos, uint len, uint rest)
|
||||||
{
|
{
|
||||||
struct bgp_proto *p = conn->bgp;
|
struct bgp_proto *p = conn->bgp;
|
||||||
struct bgp_caps *caps;
|
struct bgp_caps *caps;
|
||||||
int ol;
|
int ext = 0;
|
||||||
|
|
||||||
|
/* Handle extended length (draft-ietf-idr-ext-opt-param-07) */
|
||||||
|
if ((len > 0) && (rest > 0) && (pos[0] == 255))
|
||||||
|
{
|
||||||
|
if (rest < 3)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* Update pos/len to describe optional data */
|
||||||
|
len = get_u16(pos+1);
|
||||||
|
ext = 1;
|
||||||
|
pos += 3;
|
||||||
|
rest -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that optional data fits into OPEN packet */
|
||||||
|
if (len > rest)
|
||||||
|
goto err;
|
||||||
|
|
||||||
/* Max number of announced AFIs is limited by max option length (255) */
|
/* Max number of announced AFIs is limited by max option length (255) */
|
||||||
caps = alloca(sizeof(struct bgp_caps) + 64 * sizeof(struct bgp_af_caps));
|
caps = alloca(sizeof(struct bgp_caps) + 64 * sizeof(struct bgp_af_caps));
|
||||||
memset(caps, 0, sizeof(struct bgp_caps));
|
memset(caps, 0, sizeof(struct bgp_caps));
|
||||||
|
|
||||||
|
/* Length of option parameter header */
|
||||||
|
uint hlen = ext ? 3 : 2;
|
||||||
|
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
if ((len < 2) || (len < (2 + pos[1])))
|
if (len < hlen)
|
||||||
{ bgp_error(conn, 2, 0, NULL, 0); return -1; }
|
goto err;
|
||||||
|
|
||||||
ol = pos[1];
|
uint otype = get_u8(pos);
|
||||||
if (pos[0] == 2)
|
uint olen = ext ? get_u16(pos+1) : get_u8(pos+1);
|
||||||
|
|
||||||
|
if (len < (hlen + olen))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (otype == 2)
|
||||||
{
|
{
|
||||||
/* BGP capabilities, RFC 5492 */
|
/* BGP capabilities, RFC 5492 */
|
||||||
if (p->cf->capabilities)
|
if (p->cf->capabilities)
|
||||||
bgp_read_capabilities(conn, caps, pos + 2, ol);
|
if (bgp_read_capabilities(conn, caps, pos + hlen, olen) < 0)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Unknown option */
|
/* Unknown option */
|
||||||
bgp_error(conn, 2, 4, pos, ol); /* FIXME: ol or ol+2 ? */
|
bgp_error(conn, 2, 4, pos, hlen + olen);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ADVANCE(pos, len, 2 + ol);
|
ADVANCE(pos, len, hlen + olen);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint n = sizeof(struct bgp_caps) + caps->af_count * sizeof(struct bgp_af_caps);
|
uint n = sizeof(struct bgp_caps) + caps->af_count * sizeof(struct bgp_af_caps);
|
||||||
|
@ -658,6 +684,10 @@ bgp_read_options(struct bgp_conn *conn, byte *pos, int len)
|
||||||
memcpy(conn->remote_caps, caps, n);
|
memcpy(conn->remote_caps, caps, n);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
bgp_error(conn, 2, 0, NULL, 0);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte *
|
static byte *
|
||||||
|
@ -676,12 +706,29 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
|
||||||
if (p->cf->capabilities)
|
if (p->cf->capabilities)
|
||||||
{
|
{
|
||||||
/* Prepare local_caps and write capabilities to buffer */
|
/* Prepare local_caps and write capabilities to buffer */
|
||||||
byte *end = bgp_write_capabilities(conn, buf+12);
|
byte *pos = buf+12;
|
||||||
uint len = end - (buf+12);
|
byte *end = bgp_write_capabilities(conn, pos);
|
||||||
|
uint len = end - pos;
|
||||||
|
|
||||||
buf[9] = len + 2; /* Optional parameters length */
|
if (len < 254)
|
||||||
buf[10] = 2; /* Option 2: Capability list */
|
{
|
||||||
buf[11] = len; /* Option data length */
|
buf[9] = len + 2; /* Optional parameters length */
|
||||||
|
buf[10] = 2; /* Option 2: Capability list */
|
||||||
|
buf[11] = len; /* Option data length */
|
||||||
|
}
|
||||||
|
else /* draft-ietf-idr-ext-opt-param-07 */
|
||||||
|
{
|
||||||
|
/* Move capabilities 4 B forward */
|
||||||
|
memmove(buf + 16, pos, len);
|
||||||
|
pos = buf + 16;
|
||||||
|
end = pos + len;
|
||||||
|
|
||||||
|
buf[9] = 255; /* Non-ext OP length, fake */
|
||||||
|
buf[10] = 255; /* Non-ext OP type, signals extended length */
|
||||||
|
put_u16(buf+11, len + 3); /* Extended optional parameters length */
|
||||||
|
buf[13] = 2; /* Option 2: Capability list */
|
||||||
|
put_u16(buf+14, len); /* Option extended data length */
|
||||||
|
}
|
||||||
|
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
@ -705,8 +752,8 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
|
||||||
if (conn->state != BS_OPENSENT)
|
if (conn->state != BS_OPENSENT)
|
||||||
{ bgp_error(conn, 5, fsm_err_subcode[conn->state], NULL, 0); return; }
|
{ bgp_error(conn, 5, fsm_err_subcode[conn->state], NULL, 0); return; }
|
||||||
|
|
||||||
/* Check message contents */
|
/* Check message length */
|
||||||
if (len < 29 || len != 29 + (uint) pkt[28])
|
if (len < 29)
|
||||||
{ bgp_error(conn, 1, 2, pkt+16, 2); return; }
|
{ bgp_error(conn, 1, 2, pkt+16, 2); return; }
|
||||||
|
|
||||||
if (pkt[19] != BGP_VERSION)
|
if (pkt[19] != BGP_VERSION)
|
||||||
|
@ -717,7 +764,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
|
||||||
id = get_u32(pkt+24);
|
id = get_u32(pkt+24);
|
||||||
BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%R)", asn, hold, id);
|
BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%R)", asn, hold, id);
|
||||||
|
|
||||||
if (bgp_read_options(conn, pkt+29, pkt[28]) < 0)
|
if (bgp_read_options(conn, pkt+29, pkt[28], len-29) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (hold > 0 && hold < 3)
|
if (hold > 0 && hold < 3)
|
||||||
|
|
Loading…
Reference in a new issue