Claudio Jeker(cje...@diehard.n-r-g.com) on 2018.07.21 22:31:24 +0200:
> This adds the missing parser for messages aka updates.
> It is reusing some of bgpd's functions which I already moved to util.c for
> that and reimplements a few other bits. It also extends the current
> attribute printing code to support all attributes even those that are not
> seen in the ususal show rib case.
> 
> With this it is possible to look at mrt dump files bgpd (or other bgp
> speakers) are producing and printing their content. For me this is a good
> debugging tool since it will print more information (e.g. when handling
> notifications).
> 
> There are a few things in the output I would like to do better but I think
> those can follow once this is committed.

ok, but see whitespace issue below

> -- 
> :wq Claudio
> 
> 
> Index: bgpctl.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
> retrieving revision 1.207
> diff -u -p -r1.207 bgpctl.c
> --- bgpctl.c  20 Jul 2018 12:49:49 -0000      1.207
> +++ bgpctl.c  21 Jul 2018 08:39:20 -0000
> @@ -1434,15 +1434,112 @@ show_rib_detail(struct ctl_show_rib *r, 
>           fmt_timeframe_core(now), EOL0(flag0));
>  }
>  
> +static const char *
> +print_attr(u_int8_t type, u_int8_t flags)
> +{
> +#define CHECK_FLAGS(s, t, m)    \
> +        if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1
   ^ spaces/tab

> +
> +     static char cstr[48];
> +     int pflags = 0;
> +
> +     switch (type) {
> +     case ATTR_ORIGIN:
> +             CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
> +             strlcpy(cstr, "Origin", sizeof(cstr));
> +             break;
> +     case ATTR_ASPATH:
> +             CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
> +             strlcpy(cstr, "AS-Path", sizeof(cstr));
> +             break;
> +     case ATTR_AS4_PATH:
> +             CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
> +             strlcpy(cstr, "AS4-Path", sizeof(cstr));
> +             break;
> +     case ATTR_NEXTHOP:
> +             CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
> +             strlcpy(cstr, "Nexthop", sizeof(cstr));
> +             break;
> +     case ATTR_MED:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
> +             strlcpy(cstr, "Med", sizeof(cstr));
> +             break;
> +     case ATTR_LOCALPREF:
> +             CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
> +             strlcpy(cstr, "Localpref", sizeof(cstr));
> +             break;
> +     case ATTR_ATOMIC_AGGREGATE:
> +             CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0);
> +             strlcpy(cstr, "Atomic Aggregate", sizeof(cstr));
> +             break;
> +     case ATTR_AGGREGATOR:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
> +             strlcpy(cstr, "Aggregator", sizeof(cstr));
> +             break;
> +     case ATTR_AS4_AGGREGATOR:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
> +             strlcpy(cstr, "AS4-Aggregator", sizeof(cstr));
> +             break;
> +     case ATTR_COMMUNITIES:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
> +             strlcpy(cstr, "Communities", sizeof(cstr));
> +             break;
> +     case ATTR_ORIGINATOR_ID:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
> +             strlcpy(cstr, "Originator Id", sizeof(cstr));
> +             break;
> +     case ATTR_CLUSTER_LIST:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
> +             strlcpy(cstr, "Cluster Id List", sizeof(cstr));
> +             break;
> +     case ATTR_MP_REACH_NLRI:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
> +             strlcpy(cstr, "MP Reach NLRI", sizeof(cstr));
> +             break;
> +     case ATTR_MP_UNREACH_NLRI:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL, 0);
> +             strlcpy(cstr, "MP Unreach NLRI", sizeof(cstr));
> +             break;
> +     case ATTR_EXT_COMMUNITIES:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
> +             strlcpy(cstr, "Ext. Communities", sizeof(cstr));
> +             break;
> +     case ATTR_LARGE_COMMUNITIES:
> +             CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL);
> +             strlcpy(cstr, "Large Communities", sizeof(cstr));
> +             break;
> +     default:
> +             /* ignore unknown attributes */
> +             snprintf(cstr, sizeof(cstr), "Unknown Attribute #%u", type);
> +             pflags = 1;
> +             break;
> +     }
> +     if (pflags) {
> +             strlcat(cstr, " flags [", sizeof(cstr));
> +             if (flags & ATTR_OPTIONAL)
> +                     strlcat(cstr, "O", sizeof(cstr));
> +             if (flags & ATTR_TRANSITIVE)
> +                     strlcat(cstr, "T", sizeof(cstr));
> +             if (flags & ATTR_PARTIAL)
> +                     strlcat(cstr, "P", sizeof(cstr));
> +             strlcat(cstr, "]", sizeof(cstr));
> +     }
> +     return (cstr);
> +
> +#undef CHECK_FLAGS
> +}
> +
>  void
>  show_attr(void *b, u_int16_t len, int flag0)
>  {
> -     char            *data = b;
> +     u_char          *data = b, *path;
>       struct in_addr   id;
> +     struct bgpd_addr prefix;
> +     char            *aspath;
>       u_int32_t        as;
> -     u_int16_t        alen, ioff;
> -     u_int8_t         flags, type;
> -     int              i;
> +     u_int16_t        alen, ioff, short_as, afi;
> +     u_int8_t         flags, type, safi, aid, prefixlen;
> +     int              i, pos, e2, e4;
>  
>       if (len < 3)
>               errx(1, "show_attr: too short bgp attr");
> @@ -1468,66 +1565,179 @@ show_attr(void *b, u_int16_t len, int fl
>       if (alen > len)
>               errx(1, "show_attr: bad length");
>  
> +     printf("    %s: ", print_attr(type, flags));
> +
>       switch (type) {
> -     case ATTR_COMMUNITIES:
> -             printf("    Communities: ");
> -             show_community(data, alen);
> -             printf("%c", EOL0(flag0));
> +     case ATTR_ORIGIN:
> +             if (alen == 1)
> +                     printf("%u", *data);
> +             else
> +                     printf("bad length");
>               break;
> -     case ATTR_LARGE_COMMUNITIES:
> -             printf("    Large Communities: ");
> -             show_large_community(data, alen);
> -             printf("%c", EOL0(flag0));
> +     case ATTR_ASPATH:
> +     case ATTR_AS4_PATH:
> +             /* prefer 4-byte AS here */
> +             e4 = aspath_verify(data, alen, 1);
> +             e2 = aspath_verify(data, alen, 0);
> +             if (e4 == 0 || e4 == AS_ERR_SOFT) {
> +                     path = data;
> +             } else if (e2 == 0 || e2 == AS_ERR_SOFT) {
> +                     path = aspath_inflate(data, alen, &alen);
> +                     if (path == NULL)
> +                             errx(1, "aspath_inflate failed");
> +             } else {
> +                     printf("bad AS-Path");
> +                     break;
> +             }
> +             if (aspath_asprint(&aspath, path, alen) == -1)
> +                     err(1, NULL);
> +             printf("%s", aspath);
> +             free(aspath);
> +             if (path != data)
> +                     free(path);
> +             break;
> +     case ATTR_NEXTHOP:
> +             if (alen == 4) {
> +                     memcpy(&id, data, sizeof(id));
> +                     printf("%s", inet_ntoa(id));
> +             } else
> +                     printf("bad length");
> +             break;
> +     case ATTR_MED:
> +     case ATTR_LOCALPREF:
> +             if (alen == 4) {
> +                     u_int32_t val;
> +                     memcpy(&val, data, sizeof(val));
> +                     val = ntohl(val);
> +                     printf("%u", val);
> +             } else
> +                     printf("bad length");
>               break;
>       case ATTR_AGGREGATOR:
> -             memcpy(&as, data, sizeof(as));
> -             memcpy(&id, data + sizeof(as), sizeof(id));
> -             printf("    Aggregator: %s [%s]%c",
> -                 log_as(ntohl(as)), inet_ntoa(id), EOL0(flag0));
> +     case ATTR_AS4_AGGREGATOR:
> +             if (alen == 8) {
> +                     memcpy(&as, data, sizeof(as));
> +                     memcpy(&id, data + sizeof(as), sizeof(id));
> +                     as = ntohl(as);
> +             } else if (alen == 6) {
> +                     memcpy(&short_as, data, sizeof(short_as));
> +                     memcpy(&id, data + sizeof(short_as), sizeof(id));
> +                     as = ntohs(short_as);
> +             } else {
> +                     printf("bad length");
> +                     break;
> +             }
> +             printf("%s [%s]", log_as(as), inet_ntoa(id));
> +             break;
> +     case ATTR_COMMUNITIES:
> +             show_community(data, alen);
>               break;
>       case ATTR_ORIGINATOR_ID:
>               memcpy(&id, data, sizeof(id));
> -             printf("    Originator Id: %s%c", inet_ntoa(id), EOL0(flag0));
> +             printf("%s", inet_ntoa(id));
>               break;
>       case ATTR_CLUSTER_LIST:
> -             printf("    Cluster ID List:");
>               for (ioff = 0; ioff + sizeof(id) <= alen;
>                   ioff += sizeof(id)) {
>                       memcpy(&id, data + ioff, sizeof(id));
>                       printf(" %s", inet_ntoa(id));
>               }
> -             printf("%c", EOL0(flag0));
> +             break;
> +     case ATTR_MP_REACH_NLRI:
> +     case ATTR_MP_UNREACH_NLRI:
> +             if (alen < 3) {
> + bad_len:
> +                     printf("bad length");
> +                     break;
> +             }
> +             memcpy(&afi, data, 2);
> +             data += 2;
> +             alen -= 2;
> +             afi = ntohs(afi);
> +             safi = *data++;
> +             alen--;
> +
> +             if (afi2aid(afi, safi, &aid) == -1) {
> +                     printf("bad AFI/SAFI pair");
> +                     break;
> +             }
> +             printf(" %s", aid2str(aid));
> +
> +             if (type == ATTR_MP_REACH_NLRI) {
> +                     struct bgpd_addr nexthop;
> +                     u_int8_t nhlen;
> +                     if (len == 0)
> +                             goto bad_len;
> +                     nhlen = *data++;
> +                     alen--;
> +                     if (nhlen > len)
> +                             goto bad_len;
> +                     bzero(&nexthop, sizeof(nexthop));
> +                     switch (aid) {
> +                     case AID_INET6:
> +                             nexthop.aid = aid;
> +                             if (nhlen != 16 && nhlen != 32)
> +                                     goto bad_len;
> +                             memcpy(&nexthop.v6.s6_addr, data, 16);
> +                             break;
> +                     case AID_VPN_IPv4:
> +                             if (nhlen != 12)
> +                                     goto bad_len;
> +                             nexthop.aid = AID_INET;
> +                             memcpy(&nexthop.v4, data + sizeof(u_int64_t),
> +                                 sizeof(nexthop.v4));
> +                     default:
> +                             printf("unhandled AID #%u", aid);
> +                             goto done;
> +                     }
> +                     /* ignore reserved (old SNPA) field as per RFC4760 */
> +                     data += nhlen + 1;
> +                     alen -= nhlen + 1;
> +
> +                     printf(" nexthop: %s", log_addr(&nexthop));
> +             }
> +
> +             while (alen > 0) {
> +                     switch (aid) {
> +                     case AID_INET6:
> +                             pos = nlri_get_prefix6(data, alen, &prefix,
> +                                 &prefixlen);
> +                             break;
> +                     case AID_VPN_IPv4:
> +                             pos = nlri_get_vpn4(data, alen, &prefix,
> +                                 &prefixlen, 1);
> +                             break;
> +                     default:
> +                             printf("unhandled AID #%u", aid);
> +                             goto done;
> +                     }
> +                     if (pos == -1) {
> +                             printf("bad %s prefix", aid2str(aid));
> +                             break;
> +                     }
> +                     printf(" %s/%u", log_addr(&prefix), prefixlen);
> +                     data += pos;
> +                     alen -= pos;
> +             }
>               break;
>       case ATTR_EXT_COMMUNITIES:
> -             printf("    Ext. communities: ");
>               show_ext_community(data, alen);
> -             printf("%c", EOL0(flag0));
>               break;
> -     case ATTR_ATOMIC_AGGREGATE:
> -             /* ignore */
> +     case ATTR_LARGE_COMMUNITIES:
> +             show_large_community(data, alen);
>               break;
> +     case ATTR_ATOMIC_AGGREGATE:
>       default:
> -             /* ignore unknown attributes */
> -             printf("    Unknown Attribute #%u", type);
> -             if (flags) {
> -                     printf(" flags [");
> -                     if (flags & ATTR_OPTIONAL)
> -                             printf("O");
> -                     if (flags & ATTR_TRANSITIVE)
> -                             printf("T");
> -                     if (flags & ATTR_PARTIAL)
> -                             printf("P");
> -                     printf("]");
> -             }
>               printf(" len %u", alen);
>               if (alen) {
>                       printf(":");
>                       for (i=0; i < alen; i++)
> -                             printf(" %02x", *(data+i) & 0xFF);
> +                             printf(" %02x", *(data+i));
>               }
> -             printf("%c", EOL0(flag0));
>               break;
>       }
> + done:
> +     printf("%c", EOL0(flag0));
>  }
>  
>  void
> @@ -2045,16 +2255,457 @@ show_mrt_state(struct mrt_bgp_state *ms,
>           statenames[ms->old_state], statenames[ms->new_state]);
>  }
>  
> +static void
> +print_afi(u_char *p, u_int8_t len)
> +{
> +     u_int16_t afi;
> +     u_int8_t safi, aid;
> +
> +     if (len != 4) {
> +             printf("bad length");
> +             return;
> +     }
> +
> +     /* afi, 2 byte */
> +     memcpy(&afi, p, sizeof(afi));
> +     afi = ntohs(afi);
> +     p += 2;
> +     /* reserved, 1 byte */
> +     p += 1;
> +     /* safi, 1 byte */
> +     memcpy(&safi, p, sizeof(safi));
> +     if (afi2aid(afi, safi, &aid) == -1)
> +             printf("unkown afi %u safi %u", afi, safi);
> +     else
> +             printf("%s", aid2str(aid));
> +}
> +
> +static void
> +print_capability(u_int8_t capa_code, u_char *p, u_int8_t len)
> +{
> +     switch (capa_code) {
> +     case CAPA_MP:
> +             printf("multiprotocol capability: ");
> +             print_afi(p, len);
> +             break;
> +     case CAPA_REFRESH:
> +             printf("route refresh capability");
> +             break;
> +     case CAPA_RESTART:
> +             printf("graceful restart capability");
> +             /* XXX there is more needed here */
> +             break;
> +     case CAPA_AS4BYTE:
> +             printf("4-byte AS num capability: ");
> +             if (len == 4) {
> +                     u_int32_t as;
> +                     memcpy(&as, p, sizeof(as));
> +                     as = ntohl(as);
> +                     printf("AS %u", as);
> +             } else
> +                     printf("bad length");
> +             break;
> +     default:
> +             printf("unknown capability %u length %u", capa_code, len);
> +             break;
> +     }
> +}
> +
> +static void
> +print_notification(u_int8_t errcode, u_int8_t subcode)
> +{
> +     const char *suberrname = NULL;
> +     int uk = 0;
> +
> +     switch (errcode) {
> +     case ERR_HEADER:
> +             if (subcode >= sizeof(suberr_header_names)/sizeof(char *))
> +                     uk = 1;
> +             else
> +                     suberrname = suberr_header_names[subcode];
> +             break;
> +     case ERR_OPEN:
> +             if (subcode >= sizeof(suberr_open_names)/sizeof(char *))
> +                     uk = 1;
> +             else
> +                     suberrname = suberr_open_names[subcode];
> +             break;
> +     case ERR_UPDATE:
> +             if (subcode >= sizeof(suberr_update_names)/sizeof(char *))
> +                     uk = 1;
> +             else
> +                     suberrname = suberr_update_names[subcode];
> +             break;
> +     case ERR_CEASE:
> +             if (subcode >= sizeof(suberr_cease_names)/sizeof(char *))
> +                     uk = 1;
> +             else
> +                     suberrname = suberr_cease_names[subcode];
> +             break;
> +     case ERR_HOLDTIMEREXPIRED:
> +             if (subcode != 0)
> +                     uk = 1;
> +             break;
> +     case ERR_FSM:
> +             if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *))
> +                     uk = 1;
> +             else
> +                     suberrname = suberr_fsm_names[subcode];
> +             break;
> +     default:
> +             printf("unknown errcode %u, subcode %u",
> +                 errcode, subcode);
> +             return;
> +     }
> +
> +     if (uk)
> +             printf("%s, unknown subcode %u", errnames[errcode], subcode);
> +     else {
> +             if (suberrname == NULL)
> +                     printf("%s", errnames[errcode]);
> +             else
> +                     printf("%s, %s", errnames[errcode], suberrname);
> +     }
> +}
> +
> +static int
> +show_mrt_capabilities(u_char *p, u_int16_t len)
> +{
> +     u_int16_t totlen = len;
> +     u_int8_t capa_code, capa_len;
> +
> +     while (len > 2) {
> +             memcpy(&capa_code, p, sizeof(capa_code));
> +             p += sizeof(capa_code);
> +             len -= sizeof(capa_code);
> +             memcpy(&capa_len, p, sizeof(capa_len));
> +             p += sizeof(capa_len);
> +             len -= sizeof(capa_len);
> +             if (len < capa_len) {
> +                     printf("capa_len %u exceeds remaining length",
> +                         capa_len);
> +                     return (-1);
> +             }
> +             printf("\n        ");
> +             print_capability(capa_code, p, capa_len);
> +             p += capa_len;
> +             len -= capa_len;
> +     }
> +     if (len != 0) {
> +             printf("length missmatch while capability parsing");
> +             return (-1);
> +     }
> +     return (totlen);
> +}
> +
> +static void
> +show_mrt_open(u_char *p, u_int16_t len)
> +{
> +     u_int8_t version, optparamlen;
> +     u_int16_t short_as, holdtime;
> +     struct in_addr bgpid;
> +
> +     /* length check up to optparamlen already happened */
> +     memcpy(&version, p, sizeof(version));
> +     p += sizeof(version);
> +     len -= sizeof(version);
> +     memcpy(&short_as, p, sizeof(short_as));
> +     p += sizeof(short_as);
> +     len -= sizeof(short_as);
> +     short_as = ntohs(short_as);
> +     memcpy(&holdtime, p, sizeof(holdtime));
> +     holdtime = ntohs(holdtime);
> +     p += sizeof(holdtime);
> +     len -= sizeof(holdtime);
> +     memcpy(&bgpid, p, sizeof(bgpid));
> +     p += sizeof(bgpid);
> +     len -= sizeof(bgpid);
> +     memcpy(&optparamlen, p, sizeof(optparamlen));
> +     p += sizeof(optparamlen);
> +     len -= sizeof(optparamlen);
> +
> +     printf("\n    ");
> +     printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u",
> +         version, short_as, holdtime, inet_ntoa(bgpid), optparamlen);
> +     if (optparamlen != len) {
> +             printf("optional parameter length mismatch");
> +             return;
> +     }
> +     while (len > 2) {
> +             u_int8_t op_type, op_len;
> +             int r;
> +
> +             memcpy(&op_type, p, sizeof(op_type));
> +             p += sizeof(op_type);
> +             len -= sizeof(op_type);
> +             memcpy(&op_len, p, sizeof(op_len));
> +             p += sizeof(op_len);
> +             len -= sizeof(op_len);
> +
> +             printf("\n    ");
> +             switch (op_type) {
> +             case OPT_PARAM_CAPABILITIES:
> +                     printf("Capabilities: size %u", op_len);
> +                     r = show_mrt_capabilities(p, op_len);
> +                     if (r == -1)
> +                             return;
> +                     p += r;
> +                     len -= r;
> +                     break;
> +             case OPT_PARAM_AUTH:
> +             default:
> +                     printf("unsupported optional parameter: type %u",
> +                         op_type);
> +                     return;
> +             }
> +     }
> +     if (len != 0) {
> +             printf("optional parameter encoding error");
> +             return;
> +     }
> +}
> +
> +static void
> +show_mrt_notification(u_char *p, u_int16_t len)
> +{
> +     u_int16_t i;
> +     u_int8_t errcode, subcode, shutcomm_len;
> +     char shutcomm[SHUT_COMM_LEN];
> +
> +     memcpy(&errcode, p, sizeof(errcode));
> +     p += sizeof(errcode);
> +     len -= sizeof(errcode);
> +
> +     memcpy(&subcode, p, sizeof(subcode));
> +     p += sizeof(subcode);
> +     len -= sizeof(subcode);
> +
> +     printf("\n    ");
> +     print_notification(errcode, subcode);
> +
> +     if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN ||
> +         subcode == ERR_CEASE_ADMIN_RESET)) {
> +             if (len >= sizeof(shutcomm_len)) {
> +                     memcpy(&shutcomm_len, p, sizeof(shutcomm_len));
> +                     p += sizeof(shutcomm_len);
> +                     len -= sizeof(shutcomm_len);
> +                     if(len < shutcomm_len) {
> +                             printf("truncated shutdown reason");
> +                             return;
> +                     }
> +                     if (shutcomm_len > (SHUT_COMM_LEN-1)) {
> +                             printf("overly long shutdown reason");
> +                             return;
> +                     }
> +                     memcpy(shutcomm, p, shutcomm_len);
> +                     shutcomm[shutcomm_len] = '\0';
> +                     printf("shutdown reason: \"%s\"",
> +                         log_shutcomm(shutcomm));
> +                     p += shutcomm_len;
> +                     len -= shutcomm_len;
> +             }
> +     }
> +     if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) {
> +             int r;
> +
> +             r = show_mrt_capabilities(p, len);
> +             if (r == -1)
> +                     return;
> +             p += r;
> +             len -= r;
> +     }
> +
> +     if (len > 0) {
> +             printf("\n    additional data %u bytes", len);
> +             for (i = 0; i < len; i++) {
> +                     if (i % 16 == 0)
> +                             printf("\n    ");
> +                     if (i % 8 == 0)
> +                             printf("   ");
> +                     printf(" %02X", *p++);
> +             }
> +     }
> +}
> +
> +static void
> +show_mrt_update(u_char *p, u_int16_t len)
> +{
> +     struct bgpd_addr prefix;
> +     int pos;
> +     u_int16_t wlen, alen;
> +     u_int8_t prefixlen;
> +
> +     if (len < sizeof(wlen)) {
> +             printf("bad length");
> +             return;
> +     }
> +     memcpy(&wlen, p, sizeof(wlen));
> +     wlen = ntohs(wlen);
> +     p += sizeof(wlen);
> +     len -= sizeof(wlen);
> +
> +     if (len < wlen) {
> +             printf("bad withdraw length");
> +             return;
> +     }
> +     if (wlen > 0) {
> +             printf("\n     Withdrawn prefixes:");
> +             while (wlen > 0) {
> +                     if ((pos = nlri_get_prefix(p, wlen, &prefix,
> +                         &prefixlen)) == -1) {
> +                             printf("bad withdraw prefix");
> +                             return;
> +                     }
> +                     printf(" %s/%u", log_addr(&prefix), prefixlen);
> +                     p += pos;
> +                     len -= pos;
> +                     wlen -= pos;
> +             }
> +     }
> +
> +     if (len < sizeof(alen)) {
> +             printf("bad length");
> +             return;
> +     }
> +     memcpy(&alen, p, sizeof(alen));
> +     alen = ntohs(alen);
> +     p += sizeof(alen);
> +     len -= sizeof(alen);
> +
> +     if (len < alen) {
> +             printf("bad attribute length");
> +             return;
> +     }
> +     printf("\n");
> +     /* alen attributes here */
> +     while (alen > 3) {
> +             u_int8_t flags, type;
> +             u_int16_t attrlen;
> +
> +             flags = p[0];
> +             type = p[1];
> +
> +             /* get the attribute length */
> +             if (flags & ATTR_EXTLEN) {
> +                     if (len < sizeof(attrlen) + 2)
> +                             printf("bad attribute length");
> +                     memcpy(&attrlen, &p[2], sizeof(attrlen));
> +                     attrlen = ntohs(attrlen);
> +                     attrlen += sizeof(attrlen) + 2;
> +             } else {
> +                     attrlen = p[2];
> +                     attrlen += 1 + 2;
> +             }
> +
> +             show_attr(p, attrlen, 0);
> +             p += attrlen;
> +             alen -= attrlen;
> +             len -= attrlen;
> +     }
> +
> +     if (len > 0) {
> +             printf("    NLRI prefixes:");
> +             while (len > 0) {
> +                     if ((pos = nlri_get_prefix(p, len, &prefix,
> +                         &prefixlen)) == -1) {
> +                             printf("bad withdraw prefix");
> +                             return;
> +                     }
> +                     printf(" %s/%u", log_addr(&prefix), prefixlen);
> +                     p += pos;
> +                     len -= pos;
> +             }
> +     }
> +}
> +
>  void
>  show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
>  {
> +     static const u_int8_t marker[MSGSIZE_HEADER_MARKER] = {
> +         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
> +         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
>       struct bgpd_addr src, dst;
> +     u_char *p;
> +     u_int16_t len;
> +     u_int8_t type;
>  
>       mrt_to_bgpd_addr(&mm->src, &src);
>       mrt_to_bgpd_addr(&mm->dst, &dst);
>       printf("%s %s[%u] -> ", print_time(&mm->time),
>           log_addr(&src), mm->src_as);
> -     printf("%s[%u]: size %u\n", log_addr(&dst), mm->dst_as, mm->msg_len);
> +     printf("%s[%u]: size %u ", log_addr(&dst), mm->dst_as, mm->msg_len);
> +     p = mm->msg;
> +     len = mm->msg_len;
> +
> +     if (len < MSGSIZE_HEADER) {
> +             printf("illegal header length: %u byte\n", len);
> +             return;
> +     }
> +
> +     /* parse BGP message header */
> +     if (memcmp(p, marker, sizeof(marker))) {
> +             printf("incorrect marker in BGP message\n");
> +             return;
> +     }
> +     p += MSGSIZE_HEADER_MARKER;
> +
> +     memcpy(&len, p, 2);
> +     len = ntohs(len);
> +     p += 2;
> +     memcpy(&type, p, 1);
> +     p += 1;
> +
> +     if (len < MSGSIZE_HEADER || len > MAX_PKTSIZE) {
> +             printf("illegal header length: %u byte\n", len);
> +             return;
> +     }
> +
> +     switch (type) {
> +     case OPEN:
> +             printf("%s ", msgtypenames[type]);
> +             if (len < MSGSIZE_OPEN_MIN) {
> +                     printf("illegal length: %u byte\n", len);
> +                     return;
> +             }
> +             show_mrt_open(p, len - MSGSIZE_HEADER);
> +             break;
> +     case NOTIFICATION:
> +             printf("%s ", msgtypenames[type]);
> +             if (len < MSGSIZE_NOTIFICATION_MIN) {
> +                     printf("illegal length: %u byte\n", len);
> +                     return;
> +             }
> +             show_mrt_notification(p, len - MSGSIZE_HEADER);
> +             break;
> +     case UPDATE:
> +             printf("%s ", msgtypenames[type]);
> +             if (len < MSGSIZE_UPDATE_MIN) {
> +                     printf("illegal length: %u byte\n", len);
> +                     return;
> +             }
> +             show_mrt_update(p, len - MSGSIZE_HEADER);
> +             break;
> +     case KEEPALIVE:
> +             printf("%s ", msgtypenames[type]);
> +             if (len != MSGSIZE_KEEPALIVE) {
> +                     printf("illegal length: %u byte\n", len);
> +                     return;
> +             }
> +             /* nothing */
> +             break;
> +     case RREFRESH:
> +             printf("%s ", msgtypenames[type]);
> +             if (len != MSGSIZE_RREFRESH) {
> +                     printf("illegal length: %u byte\n", len);
> +                     return;
> +             }
> +             print_afi(p, len);
> +             break;
> +     default:
> +             printf("unknown type %u\n", type);
> +             return;
> +     }
> +     printf("\n");
>  }
>  
>  void
> 

Reply via email to