Browse Source

Merge upstream version 1.5.0

Christoph Biedl 7 years ago
parent
commit
aa292050e8
14 changed files with 739 additions and 349 deletions
  1. 2 4
      .hg_archival.txt
  2. 1 0
      .hgtags
  3. 16 1
      ChangeLog
  4. 300 137
      bgpdump.c
  5. 2 0
      bgpdump_attr.h
  6. 13 0
      bgpdump_formats.h
  7. 345 132
      bgpdump_lib.c
  8. 10 1
      bgpdump_lib.h
  9. 39 49
      cfile_tools.c
  10. 0 14
      cfile_tools.h
  11. 4 4
      configure.in
  12. 4 4
      test.sh
  13. 2 2
      util.c
  14. 1 1
      util.h

+ 2 - 4
.hg_archival.txt

@@ -1,6 +1,4 @@
 repo: fc85b5d83c23266299237988401380dcb3d3c4f3
-node: cfcbe1f5bfc5da2f634ae576809acd0e91f8ff09
+node: a8ca3180d6d46836b4d4f3f66696b7ed1f7884ee
 branch: default
-latesttag: 1.4.99.15
-latesttagdistance: 14
-changessincelatesttag: 14
+tag: 1.5.0

+ 1 - 0
.hgtags

@@ -7,3 +7,4 @@ aeead79922f7eeac5d8e678b43101deef02cf847 1.4.99.9
 b8e3ed2b370ca220f46bfa59193665dfdee5d5ef 1.4.99.13
 c4c53146f09af40a0068992d67a345a05ac54514 1.4.99.14
 d8e8bcf60eb4c7ce065b2744d6a32003c728d8b2 1.4.99.15
+601292759e414fd15a59332928956012b3dc3ddb 1.5.00.00

+ 16 - 1
ChangeLog

@@ -1,12 +1,27 @@
 ==========================================================
 The current maintainer of this library is the
-RIPE NCC information services department.
+RIPE NCC Global Information Infrastructure department.
 
 You can reach us at https://bitbucket.org/ripencc/bgpdump
 
 PLEASE DO NOT E-MAIL INDIVIDUAL DEVELOPERS ABOUT
 ISSUES, AS YOUR E-MAIL MAY BE LOST
 ==========================================================
+
+2016-09-15 Colin Petrie <cpetrie@ripe.net> v1.5.0
+	* Many security fixes, crashes, segfaults, memory leaks fixed.
+	* Many fixes provided by Christoph Biedl from Debian port
+	* Fuzzed inputs, hints and ideas provided by Guillaume Valadon
+	* Thread-safety fixes from CAIDA/bgpstream version of bgpdump
+	* version bump as new fields have been added to structs, apps
+	  should be recompiled
+
+2015-11-05 Colin Petrie <cpetrie@ripe.net>
+	* Adding support for draft-petrie-grow-mrt-add-paths
+	  Note that this adds various output format changes, when reading messages
+	  with Add-path Path-IDs in them, there are extra columns and fields in
+	  the bgpdump output
+
 2015-10-08 Alexis Fasquel <alexis@pch.net>
 	* Adding support for Extended Timestamp MRT Header corresponding to MRT type BGP4MP_ET
 	  Note that this changes the semantics of the output of bgpdump - when a messages

+ 300 - 137
bgpdump.c

@@ -42,7 +42,7 @@ static void process(BGPDUMP_ENTRY *entry);
 static void process_bgpdump_mrtd_bgp(BGPDUMP_ENTRY *entry);
 static void show_ipv4_address(struct in_addr ip);
 static void show_attr(attributes_t *attr);
-static void show_prefixes(int count,struct prefix *prefix);
+static void show_prefixes(int count,struct prefix *prefix, int addpath);
 static void table_line_announce_1(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY *entry,char *time_str);
 static void table_line_announce(struct prefix *prefix,int count,BGPDUMP_ENTRY *entry,char *time_str);
 static void mrtd_table_line_withdraw(struct prefix *prefix, int count, BGPDUMP_ENTRY *entry, char *time_str);
@@ -54,7 +54,7 @@ static char *describe_origin(int origin);
 static int  bgp4mp_message_direction_receive(BGPDUMP_ENTRY *entry);
 
 #ifdef BGPDUMP_HAVE_IPV6
-    void show_prefixes6(int count,struct prefix *prefix);
+    void show_prefixes6(int count,struct prefix *prefix, int addpath);
     static void table_line_withdraw6(struct prefix *prefix,int count,BGPDUMP_ENTRY *entry,char *time_str);
     static void table_line_announce6(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY *entry,char *time_str);
 #endif
@@ -89,20 +89,60 @@ static int bgp4mp_message_direction_receive(BGPDUMP_ENTRY *entry) {
  - BGP4MP_ET (Extended Header)
  - BGP4MP_LOCAL (Local)
  - BGP4MP_ET_LOCAL (Local and Extended Header)
+ - BGP4MP_AP (Standard, Additional Paths)
+ - BGP4MP_ET_AP (Extended Header, Additional Paths)
+ - BGP4MP_LOCAL_AP (Local, Additional Paths)
+ - BGP4MP_ET_LOCAL_AP (Local, Extended Header, Additional Paths)
  */
 static const char* get_bgp4mp_format(BGPDUMP_ENTRY *entry) {
-    if (entry->type == BGPDUMP_TYPE_ZEBRA_BGP_ET &&
-            !bgp4mp_message_direction_receive(entry)) {
-        return "BGP4MP_ET_LOCAL";
+    if (entry->type == BGPDUMP_TYPE_ZEBRA_BGP_ET && !bgp4mp_message_direction_receive(entry)) {
+        if (is_addpath(entry)) {
+            return "BGP4MP_ET_LOCAL_AP";
+        } else {
+            return "BGP4MP_ET_LOCAL";
+        }
     } else if (entry->type == BGPDUMP_TYPE_ZEBRA_BGP_ET) {
-        return "BGP4MP_ET";
+        if (is_addpath(entry)) {
+            return "BGP4MP_ET_AP";
+        } else {
+            return "BGP4MP_ET";
+        }
     } else if (!bgp4mp_message_direction_receive(entry)) {
-        return "BGP4MP_LOCAL";
+        if (is_addpath(entry)) {
+            return "BGP4MP_LOCAL_AP";
+        } else {
+            return "BGP4MP_LOCAL";
+        }
+    } else if (is_addpath(entry)) {
+        return "BGP4MP_AP";
     } else {
         return "BGP4MP";
     }
 }
 
+static const char* get_bgp_state_name(u_int16_t state) {
+
+    const char *bgp_state_name[] = {
+        "Unknown",
+        "Idle",
+        "Connect",
+        "Active",
+        "Opensent",
+        "Openconfirm",
+        "Established",
+        /* not defined in RFC 6396 but quagga puts them into update files */
+        "Clearing",
+        "Deleted",
+        NULL
+    };
+
+    if (state && state >= (sizeof(bgp_state_name)) / (sizeof(*bgp_state_name))) {
+        return "Unknown";
+    } else {
+        return bgp_state_name[state];
+    }
+}
+
 static int mode=0;
 static int timetype=0;
 static int show_packet_index = 0;
@@ -137,7 +177,7 @@ extern int optind;
 
 int main(int argc, char *argv[]) {
     
-    char c;
+    int c;
     int fd;
     bool usage_error = false;
     bool use_syslog = true;
@@ -233,17 +273,6 @@ int main(int argc, char *argv[]) {
     return 0;
 }
 
-const char *bgp_state_name[] = {
-	"Unknown",
-	"Idle",
-	"Connect",
-	"Active",
-	"Opensent",
-	"Openconfirm",
-	"Established",
-	NULL
-};
-
 void process(BGPDUMP_ENTRY *entry) {
 
 	struct tm *date;
@@ -252,19 +281,21 @@ void process(BGPDUMP_ENTRY *entry) {
 	char time_str_fixed[128];
     char prefix[BGPDUMP_ADDRSTRLEN];
     char *bgp4mp_format;
+    char *bgp4mp_subtype_format;
+    int len;
 	
 	date=gmtime(&entry->time);
 	time2str(date,time_str_fixed);
     
     if (mode == 1) {
         // Timestamp mode
-        sprintf(time_str, "%ld", entry->time);
+        len = sprintf(time_str, "%lld", (long long)entry->time);
     } else {
-        time2str(date,time_str);
+        len = time2str(date,time_str);
     }
     // Appending microseconds to time_str if needed
     if (entry->type == BGPDUMP_TYPE_ZEBRA_BGP_ET) {
-        sprintf(time_str, "%s.%06ld", time_str, entry->ms);
+        sprintf(time_str + len, ".%06ld", entry->ms);
     }
     
 	if (mode==0)
@@ -352,9 +383,11 @@ void process(BGPDUMP_ENTRY *entry) {
 
 	case BGPDUMP_TYPE_TABLE_DUMP_V2:
 		if(mode == 0){
+
 			char peer_ip[BGPDUMP_ADDRSTRLEN];
 			//char time_str[30];
 			int i;
+            int addpath = is_addpath(entry);
 
 			BGPDUMP_TABLE_DUMP_V2_PREFIX *e;
 			e = &entry->body.mrtd_table_dump_v2_prefix;
@@ -372,13 +405,22 @@ void process(BGPDUMP_ENTRY *entry) {
 				// for multiple peers, we may need to print another TIME ourselves
 				if(i) printf("\nTIME: %s\n",time_str_fixed);
 				if(e->afi == AFI_IP){
-    				printf("TYPE: TABLE_DUMP_V2/IPV4_UNICAST\n");
+                    if (addpath)
+    				    printf("TYPE: TABLE_DUMP_V2/IPV4_UNICAST_ADDPATH\n");
+                    else  
+    				    printf("TYPE: TABLE_DUMP_V2/IPV4_UNICAST\n");
 #ifdef BGPDUMP_HAVE_IPV6
 				} else if(e->afi == AFI_IP6){
-    				printf("TYPE: TABLE_DUMP_V2/IPV6_UNICAST\n");
+                    if (addpath)
+    				    printf("TYPE: TABLE_DUMP_V2/IPV6_UNICAST_ADDPATH\n");
+                    else
+    				    printf("TYPE: TABLE_DUMP_V2/IPV6_UNICAST\n");
 #endif
 				}
-	    		printf("PREFIX: %s/%d\n",prefix, e->prefix_length);
+	    		printf("PREFIX: %s/%d",prefix, e->prefix_length);
+                if (addpath)
+                    printf(" PATH_ID: %u", e->entries[i].path_id);
+                printf("\n");
     			printf("SEQUENCE: %d\n",e->seq);
 
 				if(e->entries[i].peer->afi == AFI_IP){
@@ -414,6 +456,8 @@ void process(BGPDUMP_ENTRY *entry) {
         } else {
             bgp4mp_format = "BGP4MP_ET";
         }
+
+        int addpath = is_addpath(entry);
 	    
 	    switch(entry->subtype) 
 	    {
@@ -421,15 +465,31 @@ void process(BGPDUMP_ENTRY *entry) {
 		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4:
 		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL:
 		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL:
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_ADDPATH:
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_ADDPATH:
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL_ADDPATH:
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL_ADDPATH:
+
+            if (addpath) {
+                if (bgp4mp_message_direction_receive(entry))
+                    bgp4mp_subtype_format = "MESSAGE_ADDPATH";
+                else
+                    bgp4mp_subtype_format = "MESSAGE_LOCAL_ADDPATH";
+            } else {
+                if (bgp4mp_message_direction_receive(entry))
+                    bgp4mp_subtype_format = "MESSAGE";
+                else
+                    bgp4mp_subtype_format = "MESSAGE_LOCAL";
+            }
+
 
 		    switch(entry->body.zebra_message.type) 
 		    {
 			case BGP_MSG_UPDATE:
 			   if (mode ==0)
 		    	   {
-				bgp4mp_message_direction_receive(entry)
-					? printf("TYPE: %s/MESSAGE/Update\n", bgp4mp_format)
-					: printf("TYPE: %s/MESSAGE_LOCAL/Update\n", bgp4mp_format);
+
+                printf("TYPE: %s/%s/Update\n", bgp4mp_format, bgp4mp_subtype_format);
 
 				if (entry->body.zebra_message.source_as)
 			        {
@@ -511,52 +571,58 @@ void process(BGPDUMP_ENTRY *entry) {
 #endif				
 						printf("WITHDRAW\n");
 					if (entry->body.zebra_message.withdraw_count)
-			    			show_prefixes(entry->body.zebra_message.withdraw_count,entry->body.zebra_message.withdraw);
+                        
+                            // old style
+			    			show_prefixes(entry->body.zebra_message.withdraw_count,entry->body.zebra_message.withdraw, addpath);
 
+                            // MP
                                         if (entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST] && entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST]->prefix_count)
-                                                show_prefixes(entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST]->nlri);
+                                                show_prefixes(entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST]->nlri, addpath);
                                 
                                         if (entry->attr->mp_info->withdraw[AFI_IP][SAFI_MULTICAST] && entry->attr->mp_info->withdraw[AFI_IP][SAFI_MULTICAST]->prefix_count)
-                                                show_prefixes(entry->attr->mp_info->withdraw[AFI_IP][SAFI_MULTICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP][SAFI_MULTICAST]->nlri);
+                                                show_prefixes(entry->attr->mp_info->withdraw[AFI_IP][SAFI_MULTICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP][SAFI_MULTICAST]->nlri, addpath);
 
                                         if (entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST_MULTICAST] && entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST_MULTICAST]->prefix_count)
-                                                show_prefixes(entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST_MULTICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST_MULTICAST]->nlri);
+                                                show_prefixes(entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST_MULTICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST_MULTICAST]->nlri, addpath);
 
 #ifdef BGPDUMP_HAVE_IPV6
                                         if (entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST] && entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST]->prefix_count)
-                                                show_prefixes6(entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST]->nlri);
+                                                show_prefixes6(entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST]->nlri, addpath);
                                 
                                         if (entry->attr->mp_info->withdraw[AFI_IP6][SAFI_MULTICAST] && entry->attr->mp_info->withdraw[AFI_IP6][SAFI_MULTICAST]->prefix_count)
-                                                show_prefixes6(entry->attr->mp_info->withdraw[AFI_IP6][SAFI_MULTICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP6][SAFI_MULTICAST]->nlri);
+                                                show_prefixes6(entry->attr->mp_info->withdraw[AFI_IP6][SAFI_MULTICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP6][SAFI_MULTICAST]->nlri, addpath);
 
                                         if (entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST_MULTICAST] && entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST_MULTICAST]->prefix_count)
-                                                show_prefixes6(entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST_MULTICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST_MULTICAST]->nlri);
+                                                show_prefixes6(entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST_MULTICAST]->prefix_count,entry->attr->mp_info->withdraw[AFI_IP6][SAFI_UNICAST_MULTICAST]->nlri, addpath);
 #endif
 				}
 				if ( (entry->body.zebra_message.announce_count) || (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) 
 				{
 					printf("ANNOUNCE\n");
 			    		if (entry->body.zebra_message.announce_count)
-			    			show_prefixes(entry->body.zebra_message.announce_count,entry->body.zebra_message.announce);
+                            
+                            // old style
+			    			show_prefixes(entry->body.zebra_message.announce_count,entry->body.zebra_message.announce, addpath);
 
+                            // MP
                                         if (entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST] && entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->prefix_count)
-                                                show_prefixes(entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nlri);
+                                                show_prefixes(entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nlri, addpath);
                                 
                                         if (entry->attr->mp_info->announce[AFI_IP][SAFI_MULTICAST] && entry->attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->prefix_count)
-                                                show_prefixes(entry->attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nlri);
+                                                show_prefixes(entry->attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nlri, addpath);
 
                                         if (entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST] && entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->prefix_count)
-                                                show_prefixes(entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nlri);
+                                                show_prefixes(entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nlri, addpath);
 
 #ifdef BGPDUMP_HAVE_IPV6
                                         if (entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST] && entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->prefix_count)
-                                                show_prefixes6(entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nlri);
+                                                show_prefixes6(entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nlri, addpath);
                                 
                                         if (entry->attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST] && entry->attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->prefix_count)
-                                                show_prefixes6(entry->attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nlri);
+                                                show_prefixes6(entry->attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nlri, addpath);
 
                                         if (entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST] && entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->prefix_count)
-                                                show_prefixes6(entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nlri);
+                                                show_prefixes6(entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->prefix_count,entry->attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nlri, addpath);
 #endif					
 				}
 			   }
@@ -565,8 +631,10 @@ void process(BGPDUMP_ENTRY *entry) {
 				if ((entry->body.zebra_message.withdraw_count) || (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI)))
 				{
 
+                    // old style
 					table_line_withdraw(entry->body.zebra_message.withdraw,entry->body.zebra_message.withdraw_count,entry,time_str);
-
+                    
+                    // MP
                                         if (entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST] && entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST]->prefix_count)
                                                 table_line_withdraw(entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST]->nlri,entry->attr->mp_info->withdraw[AFI_IP][SAFI_UNICAST]->prefix_count,entry,time_str);	
 
@@ -590,7 +658,10 @@ void process(BGPDUMP_ENTRY *entry) {
 				}
 				if ( (entry->body.zebra_message.announce_count) || (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)))
 				{
+                    // old style
 					table_line_announce(entry->body.zebra_message.announce,entry->body.zebra_message.announce_count,entry,time_str);
+
+                    // MP
                                         if (entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST] && entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->prefix_count)
                                                 table_line_announce_1(entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST],entry->attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->prefix_count,entry,time_str);	
                                         if (entry->attr->mp_info->announce[AFI_IP][SAFI_MULTICAST] && entry->attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->prefix_count)
@@ -614,9 +685,7 @@ void process(BGPDUMP_ENTRY *entry) {
 			    if (mode != 0)
 				    break;
 
-				bgp4mp_message_direction_receive(entry)
-					? printf("TYPE: %s/MESSAGE/Open\n", bgp4mp_format)
-					: printf("TYPE: %s/MESSAGE_LOCAL/Open\n", bgp4mp_format);
+                printf("TYPE: %s/%s/Open\n", bgp4mp_format, bgp4mp_subtype_format);
 
 			    if (entry->body.zebra_message.source_as)
 			    {
@@ -671,9 +740,9 @@ void process(BGPDUMP_ENTRY *entry) {
 			case BGP_MSG_NOTIFY:
 			    if (mode != 0)
 				    break;
-				bgp4mp_message_direction_receive(entry)
-					? printf("TYPE: %s/MESSAGE/Notify\n", bgp4mp_format)
-					: printf("TYPE: %s/MESSAGE_LOCAL/Notify\n", bgp4mp_format);
+
+                printf("TYPE: %s/%s/Notify\n", bgp4mp_format, bgp4mp_subtype_format);
+
 			    if (entry->body.zebra_message.source_as)
 			    {
 				printf("FROM:");
@@ -846,9 +915,8 @@ void process(BGPDUMP_ENTRY *entry) {
 			    	if ( mode != 0)
 					break;
 
-				bgp4mp_message_direction_receive(entry)
-					? printf("TYPE: %s/MESSAGE/Keepalive\n", bgp4mp_format)
-					: printf("TYPE: %s/MESSAGE_LOCAL/Keepalive\n", bgp4mp_format);
+                printf("TYPE: %s/%s/Keepalive\n", bgp4mp_format, bgp4mp_subtype_format);
+
 				if (entry->body.zebra_message.source_as)
 				{
 					printf("FROM:");
@@ -926,7 +994,7 @@ void process(BGPDUMP_ENTRY *entry) {
 			//	printf(" N/A ");
 		    	printf("AS%u\n",entry->body.zebra_state_change.source_as);
 
-		    	printf("STATE: %s/%s\n",bgp_state_name[entry->body.zebra_state_change.old_state],bgp_state_name[entry->body.zebra_state_change.new_state]);
+		    	printf("STATE: %s/%s\n",get_bgp_state_name(entry->body.zebra_state_change.old_state),get_bgp_state_name(entry->body.zebra_state_change.new_state));
 		    }
 		    else if (mode==1 || mode==2 ) //-m -M
 		    {
@@ -977,7 +1045,7 @@ void process_bgpdump_mrtd_bgp(BGPDUMP_ENTRY *entry) {
     date=gmtime(&entry->time);
 
     if (mode == 1) {
-        sprintf(time_str, "%ld", entry->time);
+        sprintf(time_str, "%lld", (long long)entry->time);
     } else {
         
         time2str(date, time_str);
@@ -1005,11 +1073,11 @@ void process_bgpdump_mrtd_bgp(BGPDUMP_ENTRY *entry) {
                 show_attr(entry->attr);
             if (entry->body.mrtd_message.withdraw_count) {
                 printf("WITHDRAW\n");
-                show_prefixes(entry->body.mrtd_message.withdraw_count, entry->body.mrtd_message.withdraw);
+                show_prefixes(entry->body.mrtd_message.withdraw_count, entry->body.mrtd_message.withdraw, 0);
             }
             if (entry->body.mrtd_message.announce_count) {
                 printf("ANNOUNCE\n");
-                show_prefixes(entry->body.mrtd_message.announce_count, entry->body.mrtd_message.announce);
+                show_prefixes(entry->body.mrtd_message.announce_count, entry->body.mrtd_message.announce, 0);
             }
         }
         else {
@@ -1029,8 +1097,8 @@ void process_bgpdump_mrtd_bgp(BGPDUMP_ENTRY *entry) {
             printf("PEER:");
             show_ipv4_address(entry->body.mrtd_state_change.destination_ip);
             printf("AS%u\n", entry->body.mrtd_state_change.destination_as);
-            printf("STATE: %s/%s\n", bgp_state_name[entry->body.mrtd_state_change.old_state],
-                   bgp_state_name[entry->body.mrtd_state_change.new_state]);
+            printf("STATE: %s/%s\n", get_bgp_state_name(entry->body.mrtd_state_change.old_state),
+                   get_bgp_state_name(entry->body.mrtd_state_change.new_state));
         }
         else if (mode == 1 || mode == 2) {
             show_line_prefix("BGP", time_str, "STATE");
@@ -1170,68 +1238,89 @@ void show_attr(attributes_t *attr) {
 		    printf("MP_REACH_NLRI");
 #ifdef BGPDUMP_HAVE_IPV6
 		    if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST] || attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST] || attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST])
-
 		    {
 			   char buf[128];
 			    
 			   if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST])
 			   {
 				   printf("(IPv6 Unicast)\n");
-			   	   printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop,buf));
-			           if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop_len==32)
-					printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop_local,buf));
+                    if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop_len==4)
+                        printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop.v4_addr));
+                    if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop_len==16)
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop,buf));
+                    if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop_len==32) {
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop,buf));
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop_local,buf));
+                    }
 			   }
 			   else if (attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST])	 
 		  	   {
 			   	   printf("(IPv6 Multicast)\n");
-				   printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop,buf));
-			           if (attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop_len==32)
-					printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop_local,buf));
-
-		           }
-			   else
-		           {
-				   printf("(IPv6 Both unicast and multicast)\n");
-				   printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop,buf));
-			           if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop_len==32)
-					printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop_local,buf));
-
-
+                    if (attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop_len==4)
+                        printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop.v4_addr));
+                    if (attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop_len==16)
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop,buf));
+                    if (attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop_len==32) {
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop,buf));
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_MULTICAST]->nexthop_local,buf));
+                    }
+               }
+               else
+               {
+                   printf("(IPv6 Both unicast and multicast)\n");
+                    if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop_len==4)
+                        printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop.v4_addr));
+                    if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop_len==16)
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop,buf));
+                    if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop_len==32) {
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop,buf));
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST_MULTICAST]->nexthop_local,buf));
+                    }
 			   }
 		    }
 		    else
 #endif
 		    {
-			   
-			   if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST])
-			   {
-				   printf("(IPv4 Unicast)\n");
-				   printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop.v4_addr));
-			           if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop_len==32)
-					printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop_local.v4_addr));
-			  
-			   }
-			   else if (attr->mp_info->announce[AFI_IP][SAFI_MULTICAST])	 
-		  	   {
-			   	   printf("(IPv4 Multicast)\n");
-			           printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop.v4_addr));
-			           if (attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop_len==32)
-					printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop_local.v4_addr));
-			  
-		
-		           }
-			   else if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST])
-		           {
-				   printf("(IPv4 Both unicast and multicast)\n");
-				   printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop.v4_addr));
-			           if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop_len==32)
-					printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop_local.v4_addr));
-			  
+			   char buf[128];
 
-			   }
-  
-		    }
-	    }
+               if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST])
+               {
+                    printf("(IPv4 Unicast)\n");
+                    if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop_len==4)
+                        printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop.v4_addr));
+                    if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop_len==16)
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop,buf));
+                    if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop_len==32) {
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop,buf));
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop_local,buf));
+                    }
+                }
+               else if (attr->mp_info->announce[AFI_IP][SAFI_MULTICAST])	 
+                {
+                    printf("(IPv4 Multicast)\n");
+                    if (attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop_len==4)
+                        printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop.v4_addr));
+                    if (attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop_len==16)
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop,buf));
+                    if (attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop_len==32) {
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop,buf));
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_MULTICAST]->nexthop_local,buf));
+                    }
+                }
+                else if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST])
+                {
+                    printf("(IPv4 Both unicast and multicast)\n");
+                    if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop_len==4)
+                        printf("NEXT_HOP: %s\n",inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop.v4_addr));
+                    if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop_len==16)
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop,buf));
+                    if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop_len==32) {
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop,buf));
+                        printf("NEXT_HOP: %s\n",fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_UNICAST_MULTICAST]->nexthop_local,buf));
+                    }
+                }
+            }
+        }
 	    
 	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI) )!=0)
 	    {
@@ -1287,19 +1376,27 @@ void show_attr(attributes_t *attr) {
  
 }
 
-void show_prefixes(int count,struct prefix *prefix) {
+void show_prefixes(int count,struct prefix *prefix, int addpath) {
     int i;
     for(i=0;i<count;i++)
-	printf("  %s/%d\n",inet_ntoa(prefix[i].address.v4_addr),prefix[i].len);
+        if (addpath)
+	        printf("  %s/%d PATH_ID: %u\n",inet_ntoa(prefix[i].address.v4_addr),prefix[i].len, prefix[i].path_id);
+        else
+	        printf("  %s/%d\n",inet_ntoa(prefix[i].address.v4_addr),prefix[i].len);
+
 }
 #ifdef BGPDUMP_HAVE_IPV6
-void show_prefixes6(int count,struct prefix *prefix)
+void show_prefixes6(int count,struct prefix *prefix, int addpath)
 {
 	int i;
 	char buf[128];
 
 	for (i=0;i<count;i++)
-	 printf("  %s/%d\n",fmt_ipv6(prefix[i].address,buf),prefix[i].len);
+        if (addpath)
+	        printf("  %s/%d PATH_ID: %u\n",fmt_ipv6(prefix[i].address,buf),prefix[i].len, prefix[i].path_id);
+        else
+	        printf("  %s/%d\n",fmt_ipv6(prefix[i].address,buf),prefix[i].len);
+
 }
 #endif
 
@@ -1336,7 +1433,9 @@ static void table_line_withdraw(struct prefix *prefix,int count,BGPDUMP_ENTRY *e
                       				entry->body.zebra_message.destination_as);
                 		break;
 		}
-		printf("%s/%d\n",inet_ntoa(prefix[idx].address.v4_addr),prefix[idx].len);
+        is_addpath(entry)
+            ? printf("%s/%d|%u\n",inet_ntoa(prefix[idx].address.v4_addr),prefix[idx].len,prefix[idx].path_id)
+            : printf("%s/%d\n",inet_ntoa(prefix[idx].address.v4_addr),prefix[idx].len);
         }
 }
 
@@ -1355,11 +1454,11 @@ static void table_line_withdraw6(struct prefix *prefix,int count,BGPDUMP_ENTRY *
 		switch(entry->body.zebra_message.address_family) {
 			case AFI_IP6:
 				bgp4mp_message_direction_receive(entry)
-					? printf("%s|%u|%s/%d\n",
+					? printf("%s|%u|%s/%d",
 						fmt_ipv6(entry->body.zebra_message.source_ip,buf1),
 						entry->body.zebra_message.source_as,
 						fmt_ipv6(prefix[idx].address,buf),prefix[idx].len)
-					: printf("%s|%u|%s/%d\n",
+					: printf("%s|%u|%s/%d",
 						fmt_ipv6(entry->body.zebra_message.destination_ip,buf1),
 						entry->body.zebra_message.destination_as,
 						fmt_ipv6(prefix[idx].address,buf),prefix[idx].len);
@@ -1367,16 +1466,19 @@ static void table_line_withdraw6(struct prefix *prefix,int count,BGPDUMP_ENTRY *
             		case AFI_IP:
             		default:
 				bgp4mp_message_direction_receive(entry)
-					? printf("%s|%u|%s/%d\n",
+					? printf("%s|%u|%s/%d",
 						fmt_ipv4(entry->body.zebra_message.source_ip,buf1),
 						entry->body.zebra_message.source_as,
 						fmt_ipv6(prefix[idx].address,buf),prefix[idx].len)
-					: printf("%s|%u|%s/%d\n",
+					: printf("%s|%u|%s/%d",
 						fmt_ipv6(entry->body.zebra_message.destination_ip,buf1),
 						entry->body.zebra_message.destination_as,
 						fmt_ipv6(prefix[idx].address,buf),prefix[idx].len);
                 		break;
 		}
+        is_addpath(entry)
+            ? printf("|%u\n", prefix[idx].path_id)
+            : printf("\n");
         }	
 }
 #endif
@@ -1417,7 +1519,11 @@ static void table_line_announce(struct prefix *prefix,int count,BGPDUMP_ENTRY *e
 					: printf("%s|%u|",inet_ntoa(entry->body.zebra_message.destination_ip.v4_addr),entry->body.zebra_message.destination_as);
 				break;
 			}
-			printf("%s/%d|%s|%s|",inet_ntoa(prefix[idx].address.v4_addr),prefix[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
+
+            is_addpath(entry)
+                ? printf("%s/%d|%u|%s|%s|",inet_ntoa(prefix[idx].address.v4_addr),prefix[idx].len,prefix[idx].path_id,attr_aspath(entry->attr),describe_origin(entry->attr->origin))
+                : printf("%s/%d|%s|%s|",inet_ntoa(prefix[idx].address.v4_addr),prefix[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
+
 		    npref=entry->attr->local_pref;
 	            if( (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF) ) ==0)
 	            npref=0;
@@ -1454,7 +1560,10 @@ static void table_line_announce(struct prefix *prefix,int count,BGPDUMP_ENTRY *e
 					: printf("%s|%u|",inet_ntoa(entry->body.zebra_message.destination_ip.v4_addr),entry->body.zebra_message.destination_as);
 				break;
 			}
-			printf("%s/%d|%s|%s\n",inet_ntoa(prefix[idx].address.v4_addr),prefix[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
+
+            is_addpath(entry)
+                ? printf("%s/%d|%u|%s|%s\n",inet_ntoa(prefix[idx].address.v4_addr),prefix[idx].len,prefix[idx].path_id,attr_aspath(entry->attr),describe_origin(entry->attr->origin))
+                : printf("%s/%d|%s|%s\n",inet_ntoa(prefix[idx].address.v4_addr),prefix[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
 				
 		}
 	}
@@ -1497,7 +1606,10 @@ static void table_line_announce_1(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY
 						: printf("%s|%u|",inet_ntoa(entry->body.zebra_message.destination_ip.v4_addr),entry->body.zebra_message.destination_as);
 					break;
 				}
-				printf("%s/%d|%s|%s|",inet_ntoa(prefix->nlri[idx].address.v4_addr),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
+
+                is_addpath(entry)
+                    ? printf("%s/%d|%u|%s|%s|",inet_ntoa(prefix->nlri[idx].address.v4_addr),prefix->nlri[idx].len,prefix->nlri[idx].path_id,attr_aspath(entry->attr),describe_origin(entry->attr->origin))
+                    : printf("%s/%d|%s|%s|",inet_ntoa(prefix->nlri[idx].address.v4_addr),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
 
 		    npref=entry->attr->local_pref;
 	            if( (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF) ) ==0)
@@ -1506,7 +1618,11 @@ static void table_line_announce_1(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY
 	            if( (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC) ) ==0)
 	            nmed=0;
 			    
-			printf("%s|%d|%d|",inet_ntoa(entry->attr->nexthop),npref,nmed);
+                if (prefix->nexthop_len == 4)
+                    printf("%s|%d|%d|",inet_ntoa(prefix->nexthop.v4_addr),npref,nmed);
+                else if ((prefix->nexthop_len == 16) || (prefix->nexthop_len == 32))
+                    printf("%s|%d|%d|",fmt_ipv6(prefix->nexthop,buf),npref,nmed);
+                
 				//printf("%s|%d|%d|",inet_ntoa(prefix->nexthop.v4_addr),entry->attr->local_pref,entry->attr->med);
 				if( (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES) ) !=0)	
 		    			printf("%s|%s|",entry->attr->community->str+1,tmp2);
@@ -1516,6 +1632,11 @@ static void table_line_announce_1(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY
 			}
 			else 
 			{
+                // I'm not convinced this code block is actually ever executed
+                // it appears to handle old-style (non-MP) yet this function isn't
+                // called for that type.....
+                // cpetrie@ 2016-08-12
+
 				switch(entry->body.zebra_message.address_family)
 				{
 #ifdef BGPDUMP_HAVE_IPV6
@@ -1532,7 +1653,10 @@ static void table_line_announce_1(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY
 						: printf("%s|%u|",inet_ntoa(entry->body.zebra_message.destination_ip.v4_addr),entry->body.zebra_message.destination_as);
 					break;
 				}
-				printf("%s/%d|%s|%s|",inet_ntoa(prefix->nlri[idx].address.v4_addr),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
+
+                is_addpath(entry)
+                    ? printf("%s/%d|%u|%s|%s|",inet_ntoa(prefix->nlri[idx].address.v4_addr),prefix->nlri[idx].len,prefix->nlri[idx].path_id,attr_aspath(entry->attr),describe_origin(entry->attr->origin))
+                    : printf("%s/%d|%s|%s|",inet_ntoa(prefix->nlri[idx].address.v4_addr),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
 
 		    npref=entry->attr->local_pref;
 	            if( (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF) ) ==0)
@@ -1541,7 +1665,7 @@ static void table_line_announce_1(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY
 	            if( (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC) ) ==0)
 	            nmed=0;
 			    
-			printf("%s|%d|%d|",inet_ntoa(entry->attr->nexthop),npref,nmed);
+			    printf("%s|%d|%d|",inet_ntoa(entry->attr->nexthop),npref,nmed);
 				//printf("%s|%d|%d|",inet_ntoa(entry->attr->nexthop),entry->attr->local_pref,entry->attr->med);
 				if( (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES) ) !=0)	
 		    			printf("%s|%s|",entry->attr->community->str+1,tmp2);
@@ -1573,7 +1697,9 @@ static void table_line_announce_1(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY
 					: printf("%s|%u|",inet_ntoa(entry->body.zebra_message.destination_ip.v4_addr),entry->body.zebra_message.destination_as);
 				break;
 			}
-			printf("%s/%d|%s|%s\n",inet_ntoa(prefix->nlri[idx].address.v4_addr),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
+            is_addpath(entry)
+                ? printf("%s/%d|%u|%s|%s\n",inet_ntoa(prefix->nlri[idx].address.v4_addr),prefix->nlri[idx].len,prefix->nlri[idx].path_id,attr_aspath(entry->attr),describe_origin(entry->attr->origin))
+                : printf("%s/%d|%s|%s\n",inet_ntoa(prefix->nlri[idx].address.v4_addr),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
 				
 		}
 	}
@@ -1614,9 +1740,11 @@ static void table_line_announce6(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY
 	            nmed=0;
 			    
 				bgp4mp_message_direction_receive(entry)
-					? printf("%s|%u|%s/%d|%s|%s|%s|%u|%u|",fmt_ipv6(entry->body.zebra_message.source_ip,buf1),entry->body.zebra_message.source_as,fmt_ipv6(prefix->nlri[idx].address,buf2),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin),fmt_ipv6(prefix->nexthop,buf),npref,nmed)
-					: printf("%s|%u|%s/%d|%s|%s|%s|%u|%u|",fmt_ipv6(entry->body.zebra_message.destination_ip,buf1),entry->body.zebra_message.destination_as,fmt_ipv6(prefix->nlri[idx].address,buf2),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin),fmt_ipv6(prefix->nexthop,buf),npref,nmed);
+					? printf("%s|%u|%s/%d|",fmt_ipv6(entry->body.zebra_message.source_ip,buf1),entry->body.zebra_message.source_as,fmt_ipv6(prefix->nlri[idx].address,buf2),prefix->nlri[idx].len)
+					: printf("%s|%u|%s/%d|",fmt_ipv6(entry->body.zebra_message.destination_ip,buf1),entry->body.zebra_message.destination_as,fmt_ipv6(prefix->nlri[idx].address,buf2),prefix->nlri[idx].len);
+
 				break;
+
 			case AFI_IP:
 			default:
 
@@ -1629,10 +1757,20 @@ static void table_line_announce6(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY
 			    
 			//printf("%s|%d|%d|",inet_ntoa(entry->attr->nexthop),nprof,nmed);
 				bgp4mp_message_direction_receive(entry)
-					? printf("%s|%u|%s/%d|%s|%s|%s|%u|%u|",fmt_ipv4(entry->body.zebra_message.source_ip,buf1),entry->body.zebra_message.source_as,fmt_ipv6(prefix->nlri[idx].address,buf2),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin),fmt_ipv6(prefix->nexthop,buf),npref,nmed)
-					: printf("%s|%u|%s/%d|%s|%s|%s|%u|%u|",fmt_ipv4(entry->body.zebra_message.destination_ip,buf1),entry->body.zebra_message.destination_as,fmt_ipv6(prefix->nlri[idx].address,buf2),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin),fmt_ipv6(prefix->nexthop,buf),npref,nmed);
+					? printf("%s|%u|%s/%d|",fmt_ipv4(entry->body.zebra_message.source_ip,buf1),entry->body.zebra_message.source_as,fmt_ipv6(prefix->nlri[idx].address,buf2),prefix->nlri[idx].len)
+					: printf("%s|%u|%s/%d|",fmt_ipv4(entry->body.zebra_message.destination_ip,buf1),entry->body.zebra_message.destination_as,fmt_ipv6(prefix->nlri[idx].address,buf2),prefix->nlri[idx].len);
+
 				break;
 			}
+
+            if (is_addpath(entry))
+                printf("%u|", prefix->nlri[idx].path_id);
+
+            if (prefix->nexthop_len == 4)
+                printf("%s|%s|%s|%u|%u|", attr_aspath(entry->attr),describe_origin(entry->attr->origin),inet_ntoa(prefix->nexthop.v4_addr),npref,nmed);
+            else if ((prefix->nexthop_len == 16) || (prefix->nexthop_len == 32))
+                printf("%s|%s|%s|%u|%u|", attr_aspath(entry->attr),describe_origin(entry->attr->origin),fmt_ipv6(prefix->nexthop,buf),npref,nmed);
+
 			if( (entry->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES) ) !=0)	
 		    		printf("%s|%s|",entry->attr->community->str+1,tmp2);
 			else
@@ -1651,16 +1789,21 @@ static void table_line_announce6(struct mp_nlri *prefix,int count,BGPDUMP_ENTRY
 			{
 			case AFI_IP6:
 				bgp4mp_message_direction_receive(entry)
-					? printf("%s|%u|%s/%d|%s|%s\n",fmt_ipv6(entry->body.zebra_message.source_ip,buf1),entry->body.zebra_message.source_as,fmt_ipv6(prefix->nlri[idx].address,buf),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin))
-					: printf("%s|%u|%s/%d|%s|%s\n",fmt_ipv6(entry->body.zebra_message.destination_ip,buf1),entry->body.zebra_message.destination_as,fmt_ipv6(prefix->nlri[idx].address,buf),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
+					? printf("%s|%u|%s/%d|",fmt_ipv6(entry->body.zebra_message.source_ip,buf1),entry->body.zebra_message.source_as,fmt_ipv6(prefix->nlri[idx].address,buf),prefix->nlri[idx].len)
+					: printf("%s|%u|%s/%d|",fmt_ipv6(entry->body.zebra_message.destination_ip,buf1),entry->body.zebra_message.destination_as,fmt_ipv6(prefix->nlri[idx].address,buf),prefix->nlri[idx].len);
 				break;
 			case AFI_IP:
 			default:
 				bgp4mp_message_direction_receive(entry)
-					? printf("%s|%u|%s/%d|%s|%s\n",fmt_ipv4(entry->body.zebra_message.source_ip,buf1),entry->body.zebra_message.source_as,fmt_ipv6(prefix->nlri[idx].address,buf),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin))
-					: printf("%s|%u|%s/%d|%s|%s\n",fmt_ipv4(entry->body.zebra_message.destination_ip,buf1),entry->body.zebra_message.destination_as,fmt_ipv6(prefix->nlri[idx].address,buf),prefix->nlri[idx].len,attr_aspath(entry->attr),describe_origin(entry->attr->origin));
+					? printf("%s|%u|%s/%d|",fmt_ipv4(entry->body.zebra_message.source_ip,buf1),entry->body.zebra_message.source_as,fmt_ipv6(prefix->nlri[idx].address,buf),prefix->nlri[idx].len)
+					: printf("%s|%u|%s/%d|",fmt_ipv4(entry->body.zebra_message.destination_ip,buf1),entry->body.zebra_message.destination_as,fmt_ipv6(prefix->nlri[idx].address,buf),prefix->nlri[idx].len);
 				break;
 			}
+
+            if (is_addpath(entry))
+                printf("%u|", prefix->nlri[idx].path_id);
+
+            printf("%s|%s\n",attr_aspath(entry->attr),describe_origin(entry->attr->origin));
 		}		
 
 	}
@@ -1691,7 +1834,7 @@ static void table_line_mrtd_route(BGPDUMP_MRTD_TABLE_DUMP *route,BGPDUMP_ENTRY *
         t = &route->uptime;
     }
     if (mode == 1) {
-        sprintf(time_str, "%ld", *t);
+        sprintf(time_str, "%lld", (long long)*t);
     } else {
         date=gmtime(t);
         time2str(date, time_str);
@@ -1769,6 +1912,7 @@ static void table_line_dump_v2_prefix(BGPDUMP_TABLE_DUMP_V2_PREFIX *e,BGPDUMP_EN
     char peer[BGPDUMP_ADDRSTRLEN], prefix[BGPDUMP_ADDRSTRLEN], nexthop[BGPDUMP_ADDRSTRLEN];
     
     int i;
+    int addpath = is_addpath(entry);
     
     for(i = 0; i < e->entry_count; i++) {
         attributes_t *attr = e->entries[i].attr;
@@ -1803,18 +1947,23 @@ static void table_line_dump_v2_prefix(BGPDUMP_TABLE_DUMP_V2_PREFIX *e,BGPDUMP_EN
             t = &tmp;
         }
         if (mode == 1) {
-            sprintf(time_str, "%ld", *t);
+            sprintf(time_str, "%lld", (long long)*t);
         } else {
             date=gmtime(t);
             time2str(date, time_str);
         }
-        show_line_prefix("TABLE_DUMP2", time_str, "B");
 
-        
+        (addpath)
+            ? show_line_prefix("TABLE_DUMP2_AP", time_str, "B")
+            : show_line_prefix("TABLE_DUMP2", time_str, "B");
+
         if (mode == 1)
         {
             printf("%s|%u|",peer,e->entries[i].peer->peer_as);
-            printf("%s/%d|%s|%s|",prefix,e->prefix_length,aspath_str,origin);
+
+            (addpath)
+                ? printf("%s/%d|%u|%s|%s|",prefix,e->prefix_length,e->entries[i].path_id,aspath_str,origin)
+                : printf("%s/%d|%s|%s|",prefix,e->prefix_length,aspath_str,origin);
             
             npref=attr->local_pref;
             if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF) ) ==0)
@@ -1823,13 +1972,25 @@ static void table_line_dump_v2_prefix(BGPDUMP_TABLE_DUMP_V2_PREFIX *e,BGPDUMP_EN
             if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC) ) ==0)
                 nmed=0;
             
-#ifdef BGPDUMP_HAVE_IPV6
             if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)) && attr->mp_info->announce[AFI_IP6][SAFI_UNICAST])
             {
-                fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop,nexthop);
+                if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop_len == 4)
+                    strncpy(nexthop, inet_ntoa(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop.v4_addr), BGPDUMP_ADDRSTRLEN);
+                else if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop_len == 16)
+                    fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop,nexthop);
+                else if (attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop_len == 32)
+                    fmt_ipv6(attr->mp_info->announce[AFI_IP6][SAFI_UNICAST]->nexthop,nexthop);
+            }
+            else if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)) && attr->mp_info->announce[AFI_IP][SAFI_UNICAST])
+            {
+                if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop_len == 4)
+                    strncpy(nexthop, inet_ntoa(attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop.v4_addr), BGPDUMP_ADDRSTRLEN);
+                else if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop_len == 16)
+                    fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop,nexthop);
+                else if (attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop_len == 32)
+                    fmt_ipv6(attr->mp_info->announce[AFI_IP][SAFI_UNICAST]->nexthop,nexthop);
             }
             else
-#endif
             {
                 strncpy(nexthop, inet_ntoa(attr->nexthop), BGPDUMP_ADDRSTRLEN);
             }
@@ -1848,7 +2009,9 @@ static void table_line_dump_v2_prefix(BGPDUMP_TABLE_DUMP_V2_PREFIX *e,BGPDUMP_EN
         else
         {
             printf("%s|%u|",peer,e->entries[i].peer->peer_as);
-            printf("%s/%d|%s|%s\n",prefix,e->prefix_length,aspath_str,origin);
+            (addpath)
+                ? printf("%s/%d|%u|%s|%s\n",prefix,e->prefix_length,e->entries[i].path_id,aspath_str,origin)
+                : printf("%s/%d|%s|%s\n",prefix,e->prefix_length,aspath_str,origin);
             
         }
     }

+ 2 - 0
bgpdump_attr.h

@@ -107,6 +107,7 @@ struct unknown_attr
 };
 
 typedef u_int32_t as_t;
+typedef u_int32_t pathid_t;
 
 typedef struct attr attributes_t;
 struct attr
@@ -210,6 +211,7 @@ typedef union union_BGPDUMP_IP_ADDRESS {
 struct prefix {
     BGPDUMP_IP_ADDRESS	address;
     u_char		len;
+    pathid_t    path_id;
 };
 
 #define MAX_PREFIXES 2050

+ 13 - 0
bgpdump_formats.h

@@ -79,6 +79,17 @@ Original Author: Dan Ardelean (dan@ripe.net)
 #define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL	6  /* BGP4MP_MESSAGE_LOCAL */
 #define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL	7  /* BGP4MP_MESSAGE_AS4_LOCAL */
 
+/* draft-petrie-grow-mrt-add-paths-00 */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_ADDPATH            8   /* BGP4MP_MESSAGE_ADDPATH */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_ADDPATH        9   /* BGP4MP_MESSAGE_AS4_ADDPATH */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL_ADDPATH      10  /* BGP4MP_MESSAGE_LOCAL_ADDPATH */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL_ADDPATH  11  /* BGP4MP_MESSAGE_AS4_LOCAL */
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH    8    /* RIB_IPV4_UNICAST_ADDPATH */
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH  9    /* RIB_IPV4_MULTICAST_ADDPATH */
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH    10   /* RIB_IPV6_UNICAST_ADDPATH */
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH  11   /* RIB_IPV6_MULTICAST_ADDPATH */
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_GENERIC_ADDPATH         12   /* RIB_GENERIC_ADDPATH */
+
 /* BGP state - defined in RFC1771 */
 #define BGP_STATE_IDLE		1
 #define BGP_STATE_CONNECT	2
@@ -125,6 +136,7 @@ typedef struct struct_BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE {
 typedef struct struct_BGPDUMP_TABLE_DUMP_V2_ROUTE_ENTRY {
 	uint16_t            peer_index;
 	uint32_t            originated_time;
+    pathid_t            path_id;
 	BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE_ENTRY *peer;
         attributes_t        *attr;
 } BGPDUMP_TABLE_DUMP_V2_ROUTE_ENTRY;
@@ -262,6 +274,7 @@ typedef struct struct_BGPDUMP_ENTRY {
     u_int32_t length;
     attributes_t *attr;
     BGPDUMP_BODY body;
+    struct struct_BGPDUMP * dump;
 } BGPDUMP_ENTRY;
 
 #endif

+ 345 - 132
bgpdump_lib.c

@@ -42,6 +42,8 @@ this license is included with libbgpdump.
 #include <assert.h>
 
 void	  bgpdump_free_attr(attributes_t *attr);
+static    BGPDUMP_ENTRY* bgpdump_entry_create(BGPDUMP *dump);
+static    int process_mrtd_bgp(struct mstream *s, BGPDUMP_ENTRY *entry);
 static    int process_mrtd_table_dump(struct mstream *s,BGPDUMP_ENTRY *entry);
 static    int process_mrtd_table_dump_v2(struct mstream *s,BGPDUMP_ENTRY *entry);
 static    int process_mrtd_table_dump_v2_peer_index_table(struct mstream *s,BGPDUMP_ENTRY *entry);
@@ -58,16 +60,16 @@ static    int process_zebra_bgp_message_notify(struct mstream *s,BGPDUMP_ENTRY *
 static    int process_zebra_bgp_entry(struct mstream *s,BGPDUMP_ENTRY *entry);
 static    int process_zebra_bgp_snapshot(struct mstream *s,BGPDUMP_ENTRY *entry);
 
-static    attributes_t *process_attributes(struct mstream *s, u_int8_t asn_len, struct zebra_incomplete *incomplete);
+static    attributes_t *process_attributes(struct mstream *s, u_int8_t asn_len, struct zebra_incomplete *incomplete, int is_addp);
 static    void process_attr_aspath_string(struct aspath *as);
 static    char aspath_delimiter_char (u_char type, u_char which);
 static    void process_attr_community_string(struct community *com);
 
-static    void process_mp_announce(struct mstream *s, struct mp_info *info, struct zebra_incomplete *incomplete);
-static    void process_mp_withdraw(struct mstream *s, struct mp_info *info, struct zebra_incomplete *incomplete);
-static    int read_prefix_list(struct mstream *s, u_int16_t af, struct prefix *prefixes, struct zebra_incomplete *incomplete);
+static    void process_mp_announce(struct mstream *s, struct mp_info *info, struct zebra_incomplete *incomplete, int is_addp);
+static    void process_mp_withdraw(struct mstream *s, struct mp_info *info, struct zebra_incomplete *incomplete, int is_addp);
+static    int read_prefix_list(struct mstream *s, u_int16_t af, struct prefix *prefixes, struct zebra_incomplete *incomplete, int is_addp);
 
-static    as_t read_asn(struct mstream *s, as_t *asn, u_int8_t len);
+static    as_t read_asn(struct mstream *s, u_int8_t len);
 static    struct aspath *create_aspath(u_int16_t len, u_int8_t asn_len);
 static    void aspath_error(struct aspath *as);
 static    int check_new_aspath(struct aspath *aspath);
@@ -75,8 +77,6 @@ static    void process_asn32_trans(attributes_t *attr, u_int8_t asn_len);
 static    struct aspath *asn32_merge_paths(struct aspath *path, struct aspath *newpath);
 static    void asn32_expand_16_to_32(char *dst, char *src, int len);
 
-BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE *table_dump_v2_peer_index_table = NULL;
-
 #if defined(linux)
 static    size_t strlcat(char *dst, const char *src, size_t size);
 #endif
@@ -93,10 +93,17 @@ BGPDUMP *bgpdump_open_dump(const char *filename) {
         perror("can't open dumpfile");
         return NULL;
     }
-    
     BGPDUMP *this_dump = malloc(sizeof(BGPDUMP));
+    if (this_dump == NULL) {
+        perror("malloc");
+        return NULL;
+    }
     strcpy(this_dump->filename, "[STDIN]");
     if(filename && strcmp(filename, "-")) {
+        if (strlen(filename) >= BGPDUMP_MAX_FILE_LEN - 1) {
+            fprintf (stderr, "File name %s is too long.\n", filename);
+            exit(1);
+        }
 	strcpy(this_dump->filename, filename);
     }
 
@@ -104,38 +111,53 @@ BGPDUMP *bgpdump_open_dump(const char *filename) {
     this_dump->eof=0;
     this_dump->parsed = 0;
     this_dump->parsed_ok = 0;
+    // peer index table shared among entries
+    this_dump->table_dump_v2_peer_index_table = NULL;
 
     return this_dump;
 }
 
 void bgpdump_close_dump(BGPDUMP *dump) {
-    if(dump!=NULL) {
 
-    	if(table_dump_v2_peer_index_table){
-		if(table_dump_v2_peer_index_table->entries) {
-			free(table_dump_v2_peer_index_table->entries);
-			table_dump_v2_peer_index_table->entries = NULL;
-		}
-		free(table_dump_v2_peer_index_table);
-		table_dump_v2_peer_index_table = NULL;
-	}
+    if(dump == NULL) {
+        return;
+    }
+
+    if(dump->table_dump_v2_peer_index_table){
+        free(dump->table_dump_v2_peer_index_table->entries);
+    }
+    free(dump->table_dump_v2_peer_index_table);
 	cfr_close(dump->f);
-        free(dump);
+    free(dump);
+}
+
+BGPDUMP_ENTRY* bgpdump_entry_create(BGPDUMP *dump){
+    BGPDUMP_ENTRY *this_entry = malloc(sizeof(BGPDUMP_ENTRY));
+    if(this_entry == NULL) {
+        err("%s: out of memory", __func__);
+        return NULL;
     }
+    memset(this_entry, 0, sizeof(BGPDUMP_ENTRY));
+    this_entry->dump = dump;
+    return this_entry;
 }
 
 BGPDUMP_ENTRY*	bgpdump_read_next(BGPDUMP *dump) {
     assert(dump);
 
-    BGPDUMP_ENTRY *this_entry=NULL;
     struct mstream s;
     u_char *buffer;
     int ok=0;
-    u_int32_t bytes_read;
+    u_int32_t bytes_read, t;
 
-    this_entry = malloc(sizeof(BGPDUMP_ENTRY));
+    BGPDUMP_ENTRY *this_entry = bgpdump_entry_create(dump);
+    if(this_entry == NULL) {
+        err("%s: out of memmory", __func__);
+        dump->eof = 1;
+        return(NULL);
+    }
 
-    bytes_read = cfr_read_n(dump->f, &(this_entry->time), 4);
+    bytes_read = cfr_read_n(dump->f, &t, 4);
     bytes_read += cfr_read_n(dump->f, &(this_entry->type), 2);
     bytes_read += cfr_read_n(dump->f, &(this_entry->subtype), 2);
     bytes_read += cfr_read_n(dump->f, &(this_entry->length), 4);
@@ -144,7 +166,7 @@ BGPDUMP_ENTRY*	bgpdump_read_next(BGPDUMP *dump) {
         /* Intel byte ordering stuff ... */
         this_entry->type = ntohs(this_entry->type);
         this_entry->subtype = ntohs(this_entry->subtype);
-        this_entry->time = ntohl(this_entry->time);
+        this_entry->time = (time_t) ntohl (t);
         this_entry->length = ntohl(this_entry->length);
         
         /* If Extended Header format, then reading the miscroseconds attribute */
@@ -178,7 +200,19 @@ BGPDUMP_ENTRY*	bgpdump_read_next(BGPDUMP *dump) {
     dump->parsed++;
     this_entry->attr=NULL;
 
-    buffer = malloc(this_entry->length);
+    if(this_entry->length == 0) {
+        err("%s: invalid entry length: 0", __func__);
+	free(this_entry);
+	dump->eof=1;
+	return(NULL);
+    }
+
+    if ((buffer = malloc(this_entry->length)) == NULL) {
+	err("%s: out of memory", __func__);
+	free(this_entry);
+	dump->eof=1;
+	return(NULL);
+    }
     bytes_read = cfr_read_n(dump->f, buffer, this_entry->length);
     if(bytes_read != this_entry->length) {
 	err("bgpdump_read_next: incomplete dump record (%d bytes read, expecting %d)",
@@ -246,8 +280,16 @@ void bgpdump_free_mem(BGPDUMP_ENTRY *entry) {
 
 	switch(entry->type) {
 	    case BGPDUMP_TYPE_ZEBRA_BGP:
+	    case BGPDUMP_TYPE_ZEBRA_BGP_ET:
 		switch(entry->subtype) {
 		    case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE:
+		    case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4:
+		    case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL:
+		    case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL:
+		    case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_ADDPATH:
+		    case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_ADDPATH:
+		    case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL_ADDPATH:
+		    case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL_ADDPATH:
 			switch(entry->body.zebra_message.type) {
 			    case BGP_MSG_NOTIFY:
 				if(entry->body.zebra_message.notify_data)
@@ -262,17 +304,24 @@ void bgpdump_free_mem(BGPDUMP_ENTRY *entry) {
 		}
 		break;
 	    case BGPDUMP_TYPE_TABLE_DUMP_V2:
-		if(entry->subtype == BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_UNICAST ||
-		   entry->subtype == BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_UNICAST ){
-
-			BGPDUMP_TABLE_DUMP_V2_PREFIX *e;
-			e = &entry->body.mrtd_table_dump_v2_prefix;
-			int i;
-
-			for(i = 0; i < e->entry_count; i++){
-				bgpdump_free_attr(e->entries[i].attr);
-			}
-			free(e->entries);
+        switch(entry->subtype) {
+            case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_UNICAST:
+            case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_UNICAST:
+            case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
+            case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
+            {
+                BGPDUMP_TABLE_DUMP_V2_PREFIX *e;
+                e = &entry->body.mrtd_table_dump_v2_prefix;
+                int i;
+
+                // Conditional as the entries have already been free'd in this case
+                if(!(e->entry_count && entry->dump->table_dump_v2_peer_index_table == NULL)) {
+                    for(i = 0; i < e->entry_count; i++){
+                        bgpdump_free_attr(e->entries[i].attr);
+                    }
+                    free(e->entries);
+                }
+            }
 		}
 		break;
 	}
@@ -327,30 +376,60 @@ void bgpdump_free_attr(attributes_t *attr){
 	}
 }
 
+/* Helper function to check if this is an Additional Paths enabled subtype (exported) */
+int is_addpath(BGPDUMP_ENTRY *entry) {
+    switch(entry->type) {
+        case BGPDUMP_TYPE_ZEBRA_BGP:
+        case BGPDUMP_TYPE_ZEBRA_BGP_ET:
+            switch(entry->subtype) {
+                case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_ADDPATH:
+                case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_ADDPATH:
+                case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL_ADDPATH:
+                case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL_ADDPATH:
+                    return 1;
+                default:
+                    return 0;
+            }
+        case BGPDUMP_TYPE_TABLE_DUMP_V2:
+            switch(entry->subtype) {
+                case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
+                case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH:
+                case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
+                case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH:
+                case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_GENERIC_ADDPATH:
+                    return 1;
+                default:
+                    return 0;
+            }
+        default:
+            return 0;
+    }
+}
 
 int process_mrtd_bgp(struct mstream *s, BGPDUMP_ENTRY *entry) {
     switch(entry->subtype) {
     case BGPDUMP_SUBTYPE_MRTD_BGP_UPDATE:
     case BGPDUMP_SUBTYPE_MRTD_BGP_KEEPALIVE:
-	read_asn(s, &entry->body.mrtd_message.source_as, ASN16_LEN);
+	entry->body.mrtd_message.source_as = read_asn(s, ASN16_LEN);
 	entry->body.mrtd_message.source_ip = mstream_get_ipv4(s);
 
-	read_asn(s, &entry->body.mrtd_message.destination_as, ASN16_LEN);
+	entry->body.mrtd_message.destination_as = read_asn(s, ASN16_LEN);
 	entry->body.mrtd_message.destination_ip = mstream_get_ipv4(s);
 
 	mstream_t withdraw_stream = mstream_copy(s, mstream_getw(s, NULL));
 	entry->body.mrtd_message.withdraw_count = read_prefix_list(&withdraw_stream, AFI_IP,
 								   entry->body.mrtd_message.withdraw,
-								   &entry->body.mrtd_message.incomplete);
+								   &entry->body.mrtd_message.incomplete, 0);
 
-	entry->attr = process_attributes(s, ASN16_LEN, &entry->body.mrtd_message.incomplete);
+	if((entry->attr = process_attributes(s, ASN16_LEN, &entry->body.mrtd_message.incomplete, 0)) == NULL)
+	    return 0;
 
 	entry->body.mrtd_message.announce_count = read_prefix_list(s, AFI_IP, 
 								   entry->body.mrtd_message.announce,
-								   &entry->body.mrtd_message.incomplete);
+								   &entry->body.mrtd_message.incomplete, 0);
 	break;
     case BGPDUMP_SUBTYPE_MRTD_BGP_STATE_CHANGE:
-	read_asn(s, &entry->body.mrtd_state_change.destination_as, ASN16_LEN);
+	entry->body.mrtd_state_change.destination_as = read_asn(s, ASN16_LEN);
 	entry->body.mrtd_state_change.destination_ip = mstream_get_ipv4(s);
 	entry->body.mrtd_state_change.old_state = mstream_getw(s, NULL);
 	entry->body.mrtd_state_change.new_state = mstream_getw(s, NULL);
@@ -412,9 +491,10 @@ int process_mrtd_table_dump(struct mstream *s,BGPDUMP_ENTRY *entry) {
             assert(0); // unreachable
     }
 
-    read_asn(s,&entry->body.mrtd_table_dump.peer_as, asn_len);
+    entry->body.mrtd_table_dump.peer_as = read_asn(s, asn_len);
 
-    entry->attr = process_attributes(s, asn_len, NULL);
+    if((entry->attr = process_attributes(s, asn_len, NULL, 0)) == NULL)
+        return 0;
 
     return 1;
 }
@@ -427,12 +507,15 @@ int process_mrtd_table_dump_v2(struct mstream *s,BGPDUMP_ENTRY *entry) {
 		return process_mrtd_table_dump_v2_peer_index_table(s, entry);
 	break;
 	case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_UNICAST:
+	case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
 		return process_mrtd_table_dump_v2_ipv4_unicast(s, entry);
 	break;
 	case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_UNICAST:
+	case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
 		return process_mrtd_table_dump_v2_ipv6_unicast(s, entry);
 	break;
 	case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_GENERIC:
+	case BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_GENERIC_ADDPATH:
 		//return process_mrtd_table_dump_v2_generic(s, entry);
 	break;
 	}
@@ -446,19 +529,21 @@ int process_mrtd_table_dump_v2_peer_index_table(struct mstream *s,BGPDUMP_ENTRY
 	uint8_t peertype;
 	uint16_t view_name_len;
 
-	if(table_dump_v2_peer_index_table){
-		if(table_dump_v2_peer_index_table->entries)
-			free(table_dump_v2_peer_index_table->entries);
-		free(table_dump_v2_peer_index_table);
+	if(entry->dump->table_dump_v2_peer_index_table) {
+		free(entry->dump->table_dump_v2_peer_index_table->entries);
 	}
+	free(entry->dump->table_dump_v2_peer_index_table);
 
-	table_dump_v2_peer_index_table = malloc(sizeof(BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE));
-	t = table_dump_v2_peer_index_table;
+	if((entry->dump->table_dump_v2_peer_index_table = malloc(sizeof(BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE))) == NULL) {
+	    err("process_mrtd_table_dump_v2_peer_index_table: failed to allocate memory for index table");
+	    return 0;
+	}
+	t = entry->dump->table_dump_v2_peer_index_table;
 	t->entries = NULL;
 
-    t->local_bgp_id = mstream_get_ipv4(s);
+	t->local_bgp_id = mstream_get_ipv4(s);
 
-    mstream_getw(s,&view_name_len);
+	mstream_getw(s,&view_name_len);
 	strcpy(t->view_name, "");
 
 	// view_name_len is without trailing \0
@@ -469,7 +554,7 @@ int process_mrtd_table_dump_v2_peer_index_table(struct mstream *s,BGPDUMP_ENTRY
 		t->view_name[view_name_len] = 0;
 	}
 
-    mstream_getw(s,&t->peer_count);
+	mstream_getw(s,&t->peer_count);
 
 	t->entries = malloc(sizeof(BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE_ENTRY) * t->peer_count);
 	if(t->entries == NULL){
@@ -496,9 +581,9 @@ int process_mrtd_table_dump_v2_peer_index_table(struct mstream *s,BGPDUMP_ENTRY
 
 
 		if(peertype & BGPDUMP_PEERTYPE_TABLE_DUMP_V2_AS4)
-			read_asn(s, &t->entries[i].peer_as, 4);
+			t->entries[i].peer_as = read_asn(s, ASN32_LEN);
 		else
-			read_asn(s, &t->entries[i].peer_as, 2);
+			t->entries[i].peer_as = read_asn(s, ASN16_LEN);
 
 	}
 	return 0;
@@ -508,6 +593,7 @@ int process_mrtd_table_dump_v2_peer_index_table(struct mstream *s,BGPDUMP_ENTRY
 int process_mrtd_table_dump_v2_ipv4_unicast(struct mstream *s, BGPDUMP_ENTRY *entry){
 	BGPDUMP_TABLE_DUMP_V2_PREFIX *prefixdata;
 	prefixdata = &entry->body.mrtd_table_dump_v2_prefix;
+    int addpath = is_addpath(entry);
 	uint16_t i;
 
 	prefixdata->afi = AFI_IP;
@@ -525,15 +611,26 @@ int process_mrtd_table_dump_v2_ipv4_unicast(struct mstream *s, BGPDUMP_ENTRY *en
 		return 0;
 	}
 
+	if(prefixdata->entry_count && entry->dump->table_dump_v2_peer_index_table == NULL) {
+	    free(prefixdata->entries);
+	    err("%s: missing peer index table", __func__);
+	    return 0;
+        }
+
 	for(i=0; i < prefixdata->entry_count; i++){
 		BGPDUMP_TABLE_DUMP_V2_ROUTE_ENTRY *e;
 		e = &prefixdata->entries[i];
 
 		mstream_getw(s, &e->peer_index);
-		e->peer = &table_dump_v2_peer_index_table->entries[e->peer_index];
+		assert(e->peer_index <= entry->dump->table_dump_v2_peer_index_table->peer_count);
+		e->peer = &entry->dump->table_dump_v2_peer_index_table->entries[e->peer_index];
 		mstream_getl(s, &e->originated_time);
+
+		if (addpath)
+		    mstream_getl(s, &e->path_id);
             
-		e->attr = process_attributes(s, 4, NULL);
+		if((e->attr = process_attributes(s, 4, NULL, is_addpath(entry))) == NULL)
+		    return 0;
 	}
 
 	return 1;
@@ -544,6 +641,7 @@ int process_mrtd_table_dump_v2_ipv6_unicast(struct mstream *s, BGPDUMP_ENTRY *en
 #ifdef BGPDUMP_HAVE_IPV6
 	BGPDUMP_TABLE_DUMP_V2_PREFIX *prefixdata;
 	prefixdata = &entry->body.mrtd_table_dump_v2_prefix;
+    int addpath = is_addpath(entry);
 	uint16_t i;
 
 	prefixdata->afi = AFI_IP6;
@@ -563,15 +661,26 @@ int process_mrtd_table_dump_v2_ipv6_unicast(struct mstream *s, BGPDUMP_ENTRY *en
 		return 0;
 	}
 
+	if(prefixdata->entry_count && entry->dump->table_dump_v2_peer_index_table == NULL) {
+	    free(prefixdata->entries);
+	    err("%s: missing peer index table", __func__);
+	    return 0;
+        }
+
 	for(i=0; i < prefixdata->entry_count; i++){
 		BGPDUMP_TABLE_DUMP_V2_ROUTE_ENTRY *e;
 		e = &prefixdata->entries[i];
 
 		mstream_getw(s, &e->peer_index);
-		e->peer = &table_dump_v2_peer_index_table->entries[e->peer_index];
+		assert(e->peer_index <= entry->dump->table_dump_v2_peer_index_table->peer_count);
+		e->peer = &entry->dump->table_dump_v2_peer_index_table->entries[e->peer_index];
 		mstream_getl(s, &e->originated_time);
 
-		e->attr = process_attributes(s, 4, NULL);
+		if (addpath)
+		    mstream_getl(s, &e->path_id);
+
+		if((e->attr = process_attributes(s, 4, NULL, is_addpath(entry))) == NULL)
+		    return 0;
 	}
 
 #endif
@@ -586,9 +695,13 @@ int process_zebra_bgp(struct mstream *s,BGPDUMP_ENTRY *entry) {
 	    return process_zebra_bgp_state_change(s, entry, ASN32_LEN);
 	case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE:
 	case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL:
+    case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_ADDPATH:
+	case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL_ADDPATH:
 	    return process_zebra_bgp_message(s, entry, ASN16_LEN);
 	case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4:
 	case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL:
+	case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_ADDPATH:
+	case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL_ADDPATH:
 	    return process_zebra_bgp_message(s, entry, ASN32_LEN);
 	case BGPDUMP_SUBTYPE_ZEBRA_BGP_ENTRY:
 	    return process_zebra_bgp_entry(s,entry);
@@ -601,8 +714,8 @@ int process_zebra_bgp(struct mstream *s,BGPDUMP_ENTRY *entry) {
 }
 
 int process_zebra_bgp_state_change(struct mstream *s,BGPDUMP_ENTRY *entry, u_int8_t asn_len) {
-    read_asn(s, &entry->body.zebra_state_change.source_as, asn_len);
-    read_asn(s, &entry->body.zebra_state_change.destination_as, asn_len);
+    entry->body.zebra_state_change.source_as = read_asn(s, asn_len);
+    entry->body.zebra_state_change.destination_as = read_asn(s, asn_len);
 
     /* Work around Zebra dump corruption.
      * N.B. I don't see this in quagga 0.96.4 any more. Is it fixed? */
@@ -666,14 +779,18 @@ int process_zebra_bgp_message(struct mstream *s,BGPDUMP_ENTRY *entry, u_int8_t a
 	switch(entry->subtype) {
 		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL:
 		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL:
-			read_asn(s, &entry->body.zebra_message.destination_as, asn_len);
-			read_asn(s, &entry->body.zebra_message.source_as, asn_len);
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL_ADDPATH:
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL_ADDPATH:
+			entry->body.zebra_message.destination_as = read_asn(s, asn_len);
+			entry->body.zebra_message.source_as = read_asn(s, asn_len);
 			break;
 		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE:
 		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4:
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_ADDPATH:
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_ADDPATH:
 		default:
-			read_asn(s, &entry->body.zebra_message.source_as, asn_len);
-			read_asn(s, &entry->body.zebra_message.destination_as, asn_len);
+			entry->body.zebra_message.source_as = read_asn(s, asn_len);
+			entry->body.zebra_message.destination_as = read_asn(s, asn_len);
 			break;
 	}
 
@@ -690,11 +807,15 @@ int process_zebra_bgp_message(struct mstream *s,BGPDUMP_ENTRY *entry, u_int8_t a
 		switch(entry->subtype) {
 			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL:
 			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL:
+			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL_ADDPATH:
+			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL_ADDPATH:
 		    		entry->body.zebra_message.destination_ip.v4_addr = mstream_get_ipv4(s);
 		    		entry->body.zebra_message.source_ip.v4_addr = mstream_get_ipv4(s);
 				break;
 			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE:
 			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4:
+			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_ADDPATH:
+			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_ADDPATH:
 			default:
 				entry->body.zebra_message.source_ip.v4_addr = mstream_get_ipv4(s);
 				entry->body.zebra_message.destination_ip.v4_addr = mstream_get_ipv4(s);
@@ -707,11 +828,15 @@ int process_zebra_bgp_message(struct mstream *s,BGPDUMP_ENTRY *entry, u_int8_t a
 		switch(entry->subtype) {
 			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL:
 			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL:
+			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL_ADDPATH:
+			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL_ADDPATH:
 				mstream_get(s,&entry->body.zebra_message.destination_ip.v6_addr.s6_addr, 16);
 				mstream_get(s,&entry->body.zebra_message.source_ip.v6_addr.s6_addr, 16);
 				break;
 			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE:
 			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4:
+			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_ADDPATH:
+			case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_ADDPATH:
 			default:
 				mstream_get(s,&entry->body.zebra_message.source_ip.v6_addr.s6_addr, 16);
 				mstream_get(s,&entry->body.zebra_message.destination_ip.v6_addr.s6_addr, 16);
@@ -789,7 +914,10 @@ int process_zebra_bgp_message_notify(struct mstream *s, BGPDUMP_ENTRY *entry) {
     entry->body.zebra_message.notify_len = entry->body.zebra_message.size - 21;
 
     if(entry->body.zebra_message.notify_len > 0) {
-	entry->body.zebra_message.notify_data = malloc(entry->body.zebra_message.notify_len);
+	if((entry->body.zebra_message.notify_data = malloc(entry->body.zebra_message.notify_len)) == NULL) {
+            err("%s: out of memory", __func__);
+            return 0;
+        }
 	mstream_get(s, entry->body.zebra_message.notify_data, entry->body.zebra_message.notify_len);
     }
 
@@ -798,13 +926,17 @@ int process_zebra_bgp_message_notify(struct mstream *s, BGPDUMP_ENTRY *entry) {
 
 int process_zebra_bgp_message_open(struct mstream *s, BGPDUMP_ENTRY *entry, u_int8_t asn_len) {
     mstream_getc(s, &entry->body.zebra_message.version);
-    read_asn(s, &entry->body.zebra_message.my_as, asn_len);
+    entry->body.zebra_message.my_as = read_asn(s, asn_len);
     mstream_getw(s, &entry->body.zebra_message.hold_time);
     entry->body.zebra_message.bgp_id = mstream_get_ipv4(s);
     mstream_getc(s, &entry->body.zebra_message.opt_len);
 
     if(entry->body.zebra_message.opt_len) {
-	entry->body.zebra_message.opt_data = malloc(entry->body.zebra_message.opt_len);
+	if((entry->body.zebra_message.opt_data = malloc(entry->body.zebra_message.opt_len)) == NULL) {
+	    err("%s: out of memory", __func__);
+	    return 0;
+	}
+
 	mstream_get(s, entry->body.zebra_message.opt_data, entry->body.zebra_message.opt_len);
     }
 
@@ -817,13 +949,16 @@ int process_zebra_bgp_message_update(struct mstream *s, BGPDUMP_ENTRY *entry, u_
     mstream_t withdraw_stream = mstream_copy(s, mstream_getw(s, NULL));
     entry->body.zebra_message.withdraw_count = read_prefix_list(&withdraw_stream, AFI_IP,
                          entry->body.zebra_message.withdraw,
-			 &entry->body.zebra_message.incomplete);
+			 &entry->body.zebra_message.incomplete,
+             is_addpath(entry));
 
-    entry->attr = process_attributes(s, asn_len, &entry->body.zebra_message.incomplete);
+    if((entry->attr = process_attributes(s, asn_len, &entry->body.zebra_message.incomplete, is_addpath(entry))) == NULL)
+        return 0;
 
     entry->body.zebra_message.announce_count = read_prefix_list(s, AFI_IP, 
                          entry->body.zebra_message.announce,
-			 &entry->body.zebra_message.incomplete);
+			 &entry->body.zebra_message.incomplete,
+             is_addpath(entry));
 
     return 1;
 }
@@ -842,7 +977,15 @@ static attributes_t *attr_init(struct mstream *s, int len) {
 
     attributes_t *attr = malloc(sizeof(struct attr));
     
-    attr->data=malloc(len);
+    if(attr == NULL) {
+        err("%s: out of memory", __func__);
+        return NULL;
+    }
+    if((attr->data=malloc(len)) == NULL) {
+        free(attr);
+        err("%s: out of memory", __func__);
+        return NULL;
+    }
     memcpy(attr->data, &s->start[s->position], len);
     
     attr->len = len;
@@ -861,8 +1004,13 @@ static attributes_t *attr_init(struct mstream *s, int len) {
     attr->aspath			= NULL;
     attr->community		= NULL;
     attr->transit		= NULL;
-    attr->mp_info		= calloc(1, sizeof(struct mp_info));;
-
+    attr->mp_info		= calloc(1, sizeof(struct mp_info));
+    if(attr->mp_info == NULL) {
+        free(attr->data);
+        free(attr);
+        err("%s: out of memory", __func__);
+        return NULL;
+    }
     attr->unknown_num = 0;
     attr->unknown = NULL;
 
@@ -877,8 +1025,11 @@ static attributes_t *attr_init(struct mstream *s, int len) {
 static void process_unknown_attr(struct mstream *s, attributes_t *attr, int flag, int type, int len) {
     /* Unknown attribute. Save as is */
     attr->unknown_num++;
-    attr->unknown = realloc(attr->unknown, attr->unknown_num * sizeof(struct unknown_attr));
-    
+    if((attr->unknown = realloc(attr->unknown, attr->unknown_num * sizeof(struct unknown_attr))) == NULL) {
+        err("%s: out of memory", __func__);
+        exit(1); /* XXX */
+    }
+
     /* Pointer to the unknown attribute we want to fill in */
     struct unknown_attr unknown = {
         .flag = flag,
@@ -886,13 +1037,16 @@ static void process_unknown_attr(struct mstream *s, attributes_t *attr, int flag
         .len = len,
         .raw = malloc(len)
     };
-    
+    if(unknown.raw == NULL) {
+        err("%s: out of memory", __func__);
+        exit(1); /* XXX */
+    }
     attr->unknown[attr->unknown_num - 1] = unknown;
     
     mstream_get(s, unknown.raw, len);
 }
 
-static void process_one_attr(struct mstream *outer_stream, attributes_t *attr, u_int8_t asn_len, struct zebra_incomplete *incomplete) {
+static void process_one_attr(struct mstream *outer_stream, attributes_t *attr, u_int8_t asn_len, struct zebra_incomplete *incomplete, int is_addp) {
     int flag = mstream_getc(outer_stream, NULL);
     int type = mstream_getc(outer_stream, NULL);
     int len;
@@ -916,10 +1070,10 @@ static void process_one_attr(struct mstream *outer_stream, attributes_t *attr, u
         
     switch(type) {
         case BGP_ATTR_MP_REACH_NLRI:
-            process_mp_announce(s, attr->mp_info, incomplete);
+            process_mp_announce(s, attr->mp_info, incomplete, is_addp);
             break;
         case BGP_ATTR_MP_UNREACH_NLRI:
-            process_mp_withdraw(s, attr->mp_info, incomplete);
+            process_mp_withdraw(s, attr->mp_info, incomplete, is_addp);
             break;
         case BGP_ATTR_ORIGIN:
             assert(attr->origin == -1);
@@ -947,14 +1101,22 @@ static void process_one_attr(struct mstream *outer_stream, attributes_t *attr, u
             break;
         case BGP_ATTR_AGGREGATOR:
             assert(-1 == attr->new_aggregator_as);
-            read_asn(s, &attr->aggregator_as, asn_len);
+            attr->aggregator_as = read_asn(s, asn_len);
             attr->aggregator_addr = mstream_get_ipv4(s);
             break;
         case BGP_ATTR_COMMUNITIES:
             assert(! attr->community);
-            attr->community		= malloc(sizeof(struct community));
+            if((attr->community		= malloc(sizeof(struct community))) == NULL) {
+                err("%s: out of memory", __func__);
+                exit(1); /* XXX */
+            }
+            
             attr->community->size	= len / 4;
-            attr->community->val	= malloc(len);
+            if((attr->community->val	= malloc(len)) == NULL) {
+                err("%s: out of memory", __func__);
+                exit(1); /* XXX */
+            }
+
             mstream_get(s,attr->community->val,len);
             attr->community->str	= NULL;
             process_attr_community_string(attr->community);
@@ -969,7 +1131,7 @@ static void process_one_attr(struct mstream *outer_stream, attributes_t *attr, u
             break;
         case BGP_ATTR_NEW_AGGREGATOR:
             assert(-1 == attr->new_aggregator_as);
-            read_asn(s, &attr->new_aggregator_as, ASN32_LEN);
+            attr->new_aggregator_as = read_asn(s, ASN32_LEN);
             attr->new_aggregator_addr = mstream_get_ipv4(s);
             break;
         case BGP_ATTR_ORIGINATOR_ID:
@@ -978,9 +1140,15 @@ static void process_one_attr(struct mstream *outer_stream, attributes_t *attr, u
             break;
         case BGP_ATTR_CLUSTER_LIST:
             assert(! attr->cluster);
-            attr->cluster		= malloc(sizeof(struct cluster_list));
+            if((attr->cluster= malloc(sizeof(struct cluster_list))) == NULL) {
+                err("%s: out of memory", __func__);
+                exit(1); /* XXX */
+            }
             attr->cluster->length	= len/4;
-            attr->cluster->list = malloc((attr->cluster->length) * sizeof(struct in_addr));
+            if((attr->cluster->list = calloc((attr->cluster->length), sizeof(struct in_addr))) == NULL) {
+                err("%s: out of memory", __func__);
+                exit(1); /* XXX */
+            }
             
             int i; // cluster index
             for (i = 0; i < attr->cluster->length; i++)
@@ -991,17 +1159,20 @@ static void process_one_attr(struct mstream *outer_stream, attributes_t *attr, u
     }    
 }
 
-attributes_t *process_attributes(struct mstream *s, u_int8_t asn_len, struct zebra_incomplete *incomplete) {
+attributes_t *process_attributes(struct mstream *s, u_int8_t asn_len, struct zebra_incomplete *incomplete, int is_addp) {
     int	total = mstream_getw(s, NULL);
     
     attributes_t *attr = attr_init(s, total);
+    if(attr == NULL)
+        return NULL;
+
     mstream_t copy = mstream_copy(s, total);
 
     if(mstream_can_read(&copy) != total)
         warn("entry is truncated: expected=%u remaining=%u", total, mstream_can_read(&copy));
     
     while(mstream_can_read(&copy))
-        process_one_attr(&copy, attr, asn_len, incomplete);
+        process_one_attr(&copy, attr, asn_len, incomplete, is_addp);
     
     // Once all attributes have been read, take care of ASN32 transition
     process_asn32_trans(attr, asn_len);
@@ -1016,11 +1187,16 @@ struct aspath *create_aspath(u_int16_t len, u_int8_t asn_len) {
     aspath->length	= len;
     aspath->count	= 0;
     aspath->str		= NULL;
-    if(len > 0)
-       aspath->data	= malloc(len);
-    else
+    if(len > 0) {
+       if((aspath->data	= malloc(len)) == NULL) {
+         err("%s: out of memory", __func__);
+         free(aspath);
+         return NULL;
+       }
+    } else
        aspath->data	= NULL;
-  }
+  } else
+      err("%s: out of memory", __func__);
   return aspath;
 }
 
@@ -1033,13 +1209,17 @@ void aspath_error(struct aspath *as) {
   }
 
   as->str = malloc(strlen(ASPATH_STR_ERROR) + 1);
-  strcpy(as->str, ASPATH_STR_ERROR);
+  if (as->str != NULL)
+    strcpy(as->str, ASPATH_STR_ERROR);
 }
 
 void process_attr_aspath_string(struct aspath *as) {
     const int MAX_ASPATH_LEN = 8000;  
-    as->str = malloc(MAX_ASPATH_LEN);
-    
+    if((as->str = malloc(MAX_ASPATH_LEN)) == NULL) {
+        err("%s: out of memory", __func__);
+        exit(1); /* XXX */
+    }
+
     /* Set default values */
     int space = 0;
     u_char type = AS_SEQUENCE;
@@ -1206,46 +1386,55 @@ void process_attr_community_string(struct community *com) {
 	}
     }
 
-    com->str = malloc(strlen(buf)+1);
-    strcpy(com->str, buf);
+    if((com->str = malloc(strlen(buf)+1)) != NULL) {
+        strcpy(com->str, buf);
+    } else {
+        err("%s: out of memory", __func__);
+        exit(1); /* XXX */
+    }
 }
 
-static struct mp_nlri *get_nexthop(struct mstream *s, u_int16_t afi) {
+static struct mp_nlri *get_nexthop(struct mstream *s) {
     struct mp_nlri *nlri = calloc(1, sizeof(struct mp_nlri));
     
+    if(nlri == NULL) {
+        err("%s: out of memory", __func__);
+        return NULL;
+    }
     nlri->nexthop_len = mstream_getc(s, NULL);
     
     // sometimes nexthop_len is 0 - not sure what this means (see IS-626)
     // if(mp_nlri->nexthop_len == 0)
     //    return len;
 
-    if(afi == AFI_IP) {
-        assert(nlri->nexthop_len == 4);
-        nlri->nexthop.v4_addr = mstream_get_ipv4(s);
-        return nlri;
-    }
+    // the AFI is irrelevant to the nexthop, since RFC5549
+    // so this code now just checks for an expected length:
+    // 4 = IPv4
+    // 16 = IPv6
+    // 32 = IPv6 + link-local
 
-#ifdef BGPDUMP_HAVE_IPV6
-    assert(afi == AFI_IP6);
-    mstream_get(s, &nlri->nexthop.v6_addr, 16);
-    if(nlri->nexthop_len == 32) {
-        /* Is there also a link-local address? */
+    if(nlri->nexthop_len == 4) {
+        nlri->nexthop.v4_addr = mstream_get_ipv4(s);
+    } else if(nlri->nexthop_len == 16) {
+        mstream_get(s, &nlri->nexthop.v6_addr, 16);
+    } else if(nlri->nexthop_len == 32) {
+        mstream_get(s, &nlri->nexthop.v6_addr, 16);
         mstream_get(s, &nlri->nexthop_local.v6_addr.s6_addr, 16);
-    } else if(nlri->nexthop_len != 16) {
+    }
+    else {
         warn("process_mp_announce: unknown MP nexthop length %d", nlri->nexthop_len);
     }
-#endif
     return nlri;
 }
 
-void process_mp_announce(struct mstream *s, struct mp_info *info, struct zebra_incomplete *incomplete) {
+void process_mp_announce(struct mstream *s, struct mp_info *info, struct zebra_incomplete *incomplete, int is_addp) {
     u_int16_t afi;
     u_int8_t safi;
 
     // look for MRT abbreviated MP_NLRI packets
     if(s->start[s->position] != 0) {
         assert(info->announce[AFI_IP6][SAFI_UNICAST] == NULL);
-        info->announce[AFI_IP6][SAFI_UNICAST] = get_nexthop(s, AFI_IP6);
+        info->announce[AFI_IP6][SAFI_UNICAST] = get_nexthop(s);
         return;
     }
     
@@ -1262,7 +1451,7 @@ void process_mp_announce(struct mstream *s, struct mp_info *info, struct zebra_i
             return;
     }
 
-    info->announce[afi][safi] = get_nexthop(s, afi);
+    info->announce[afi][safi] = get_nexthop(s);
 
     // SNPA is defunct and num_snpa should always be 0
     u_int8_t num_snpa;
@@ -1272,10 +1461,10 @@ void process_mp_announce(struct mstream *s, struct mp_info *info, struct zebra_i
         mstream_get(s, NULL, mstream_getc(s, NULL));
     }
 
-    info->announce[afi][safi]->prefix_count = read_prefix_list(s, afi, info->announce[afi][safi]->nlri, incomplete);
+    info->announce[afi][safi]->prefix_count = read_prefix_list(s, afi, info->announce[afi][safi]->nlri, incomplete, is_addp);
 }
 
-void process_mp_withdraw(struct mstream *s, struct mp_info *info, struct zebra_incomplete *incomplete) {
+void process_mp_withdraw(struct mstream *s, struct mp_info *info, struct zebra_incomplete *incomplete, int is_addp) {
 	u_int16_t afi;
 	u_int8_t safi;
 	struct mp_nlri *mp_nlri;
@@ -1296,17 +1485,27 @@ void process_mp_withdraw(struct mstream *s, struct mp_info *info, struct zebra_i
 	}
 
 	/* Allocate structure */
-	mp_nlri = malloc(sizeof(struct mp_nlri));
+	if((mp_nlri = malloc(sizeof(struct mp_nlri))) == NULL) {
+	    err("%s: out of memory", __func__);
+	    exit(1); /* XXX */
+	}
 	memset(mp_nlri, 0, sizeof(struct mp_nlri));
 	info->withdraw[afi][safi] = mp_nlri;
 
-	mp_nlri->prefix_count = read_prefix_list(s, afi, mp_nlri->nlri, incomplete);
+	mp_nlri->prefix_count = read_prefix_list(s, afi, mp_nlri->nlri, incomplete, is_addp);
 }
 
-static int read_prefix_list(struct mstream *s, u_int16_t afi, struct prefix *prefixes, struct zebra_incomplete *incomplete) {
+static int read_prefix_list(struct mstream *s, u_int16_t afi, struct prefix *prefixes, struct zebra_incomplete *incomplete, int is_addp) {
     int count = 0;
     
     while(mstream_can_read(s)) {
+
+        /* If this is an Additional Paths enabled NLRI, then there is a
+         * 4 octet identifier preceeding each prefix entry */
+        pathid_t path_id = 0;
+        if (is_addp)
+            path_id = mstream_getl(s, NULL);
+
         u_int8_t p_len = mstream_getc(s,NULL); // length in bits
         u_int8_t p_bytes = (p_len + 7) / 8;
         
@@ -1319,7 +1518,8 @@ static int read_prefix_list(struct mstream *s, u_int16_t afi, struct prefix *pre
             incomplete->afi = afi;
             incomplete->orig_len = p_len;
             incomplete->prefix = (struct prefix) {
-                .len = mstream_can_read(s) * 8
+                .len = mstream_can_read(s) * 8,
+                .path_id = path_id
             };
             mstream_get(s, &incomplete->prefix.address, p_bytes);
             break;
@@ -1330,7 +1530,7 @@ static int read_prefix_list(struct mstream *s, u_int16_t afi, struct prefix *pre
         if(count++ > MAX_PREFIXES)
             continue;
 
-        *prefix = (struct prefix) { .len = p_len };
+        *prefix = (struct prefix) { .len = p_len, .path_id = path_id };
         mstream_get(s, &prefix->address, p_bytes);
     }
     
@@ -1342,18 +1542,13 @@ static int read_prefix_list(struct mstream *s, u_int16_t afi, struct prefix *pre
     return count;
 }
 
-static as_t read_asn(struct mstream *s, as_t *asn, u_int8_t len) {
-  u_int16_t asn16;
-
-  assert(len == sizeof(u_int32_t) || len == sizeof(u_int16_t));
+static as_t read_asn(struct mstream *s, u_int8_t len) {
+  assert(len == ASN32_LEN || len == ASN16_LEN);
   switch(len) {
-    case sizeof(u_int32_t):
-      return mstream_getl(s, asn);
-    case sizeof(u_int16_t):
-      mstream_getw(s, &asn16);
-      if(asn)
-	*asn = asn16;
-	return asn16;
+    case ASN32_LEN:
+      return mstream_getl(s, NULL);
+    case ASN16_LEN:
+      return mstream_getw(s, NULL);
     default:
       /* Not reached. Avoid compiler warning */
       return 0;
@@ -1421,7 +1616,10 @@ void process_asn32_trans(attributes_t *attr, u_int8_t asn_len) {
 }
 
 struct aspath *asn32_merge_paths(struct aspath *path, struct aspath *newpath) {
+  void *tmp;
   struct aspath *mergedpath = create_aspath(0, ASN32_LEN);
+  if(mergedpath == NULL)
+      return NULL;
   struct assegment *segment, *mergedsegment;
   int newlen;
 
@@ -1430,7 +1628,14 @@ struct aspath *asn32_merge_paths(struct aspath *path, struct aspath *newpath) {
   while(mergedpath->count < path->count - newpath->count) {
     /* Make room */
     newlen = mergedpath->length + sizeof(struct assegment) + segment->length * ASN32_LEN;
-    mergedpath->data = realloc(mergedpath->data, newlen);
+    tmp = realloc(mergedpath->data, newlen);
+    if(tmp == NULL) {
+        free(mergedpath->data);
+        free(mergedpath);
+        err("%s: out of memory", __func__);
+        return NULL;
+    }
+    mergedpath->data = tmp;
 
     /* Create a new AS-path segment */
     mergedsegment = (struct assegment *) (mergedpath->data + mergedpath->length);
@@ -1455,7 +1660,14 @@ struct aspath *asn32_merge_paths(struct aspath *path, struct aspath *newpath) {
   }
 
   /* Append NEW_AS_PATH to merged path */
-  mergedpath->data = realloc(mergedpath->data, mergedpath->length + newpath->length);
+  tmp = realloc(mergedpath->data, mergedpath->length + newpath->length);
+  if(tmp == NULL) {
+      free(mergedpath->data);
+      free(mergedpath);
+      err("%s: out of memory", __func__);
+      return NULL;
+  }
+  mergedpath->data = tmp;
   memcpy(mergedpath->data + mergedpath->length, newpath->data, newpath->length);
   mergedpath->length += newpath->length;
 
@@ -1482,3 +1694,4 @@ size_t strlcat(char *dst, const char *src, size_t size) {
   return (strlen(dst));
 }
 #endif
+

+ 10 - 1
bgpdump_lib.h

@@ -35,6 +35,10 @@ Original Author: Dan Ardelean (dan@ripe.net)
 #include "bgpdump_attr.h"
 #include "bgpdump_formats.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define BGPDUMP_MAX_FILE_LEN	1024
 #define BGPDUMP_MAX_AS_PATH_LEN	2000
 
@@ -50,6 +54,7 @@ typedef struct struct_BGPDUMP {
     char	filename[BGPDUMP_MAX_FILE_LEN];
     int		parsed;
     int		parsed_ok;
+    BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE *table_dump_v2_peer_index_table;
 } BGPDUMP;
 
 /* prototypes */
@@ -58,7 +63,11 @@ BGPDUMP *bgpdump_open_dump(const char *filename);
 void	bgpdump_close_dump(BGPDUMP *dump);
 BGPDUMP_ENTRY*	bgpdump_read_next(BGPDUMP *dump);
 void	bgpdump_free_mem(BGPDUMP_ENTRY *entry);
+char    *bgpdump_version(void);
+int     is_addpath(BGPDUMP_ENTRY *entry);
 
-char *bgpdump_version(void);
+#ifdef __cplusplus
+}
+#endif
 
 #endif

+ 39 - 49
cfile_tools.c

@@ -30,23 +30,15 @@
 const char * cfr_formats[CFR_NUM_FORMATS] = {
   "not open",     //  0
   "uncompressed", //  1
-#ifndef DONT_HAVE_BZ2
   "bzip2",         //  2
-#endif
-#ifndef DONT_HAVE_GZ
   "gzip",         //  3
-#endif
 };
 
 const char * cfr_extensions[CFR_NUM_FORMATS] = {
   "",             //  0
   "",             //  1
-#ifndef DONT_HAVE_BZ2
   ".bz2",          //  2
-#endif
-#ifndef DONT_HAVE_GZ
   ".gz"          //  3
-#endif
 };
 
 
@@ -74,15 +66,16 @@ CFRFILE *cfr_open(const char *path) {
 
   // Do action dependent on file format
   retval = (CFRFILE *) calloc(1,sizeof(CFRFILE));
+  if(retval == NULL)
+	return (NULL);    
   retval->eof = 0;
   retval->error1 = 0;
   retval->error2 = 0;
 
 
-#ifndef DONT_HAVE_GZ
   if((path == NULL) || (strcmp(path, "-") == 0)) {
 	/* dump from stdin */
-	gzFile *f;
+	gzFile f;
 	while (format < CFR_NUM_FORMATS) {
 		if (strcmp(cfr_extensions[format], ".gz") == 0)
         		break;
@@ -97,7 +90,6 @@ CFRFILE *cfr_open(const char *path) {
 	retval->format = format;
 	return (retval);
   }
-#endif
   while (format < CFR_NUM_FORMATS) {
     ext_len = strlen(cfr_extensions[format]);
     if (strncmp(cfr_extensions[format],
@@ -123,7 +115,6 @@ CFRFILE *cfr_open(const char *path) {
       return(retval);
     }
     break;
-#ifndef DONT_HAVE_BZ2
   case 2:  // bzip2
     { 
       int bzerror;
@@ -153,11 +144,9 @@ CFRFILE *cfr_open(const char *path) {
       return(retval);
     }
     break;
-#endif
-#ifndef DONT_HAVE_GZ
   case 3:  // gzip
     { 
-	gzFile *f;
+	gzFile f;
       	// get file 
 	f = gzopen(path, "r");
 	if(f == NULL) {
@@ -168,7 +157,6 @@ CFRFILE *cfr_open(const char *path) {
 	return (retval);
    }
    break;
-#endif
   default:  // this is an internal error, no diag yet.
     fprintf(stderr,"illegal format '%d' in cfr_open!\n", format);
     exit(1);
@@ -195,18 +183,14 @@ int cfr_close(CFRFILE *stream) {
       stream->error1 = retval;
       break;
   case 2: // bzip2
-      #ifndef DONT_HAVE_BZ2
       BZ2_bzReadClose( &stream->error2, (BZFILE *)stream->data2);
       stream->error1 = retval = fclose((FILE *)(stream->data1));
       break;
-      #endif
   case 3:  // gzip
-      #ifndef DONT_HAVE_GZ
       if(stream->data2!=NULL)
           retval = gzclose(stream->data2);
       stream->error2 = retval;
       break;
-      #endif
     default:  // internal error
           assert("illegal stream->format" && 0);
   }
@@ -247,7 +231,6 @@ size_t cfr_read(void *ptr, size_t size, size_t nmemb, CFRFILE *stream) {
       return (retval);
     }
     break;
-#ifndef DONT_HAVE_BZ2    
    case 2:  // bzip2
     { 
       BZFILE * bzin; 
@@ -298,12 +281,10 @@ size_t cfr_read(void *ptr, size_t size, size_t nmemb, CFRFILE *stream) {
       return(0);
     }
     break;
-#endif    
-#ifndef DONT_HAVE_GZ
   case 3:  // gzip
     { 
-      gzFile * in;
-      in = (gzFile *)(stream->data2);
+      gzFile in;
+      in = (gzFile)(stream->data2);
       retval = gzread(in, ptr, size*nmemb);
       if (retval != nmemb*size) {
         // fprintf(stderr,"short read!!!\n");
@@ -314,7 +295,6 @@ size_t cfr_read(void *ptr, size_t size, size_t nmemb, CFRFILE *stream) {
       return (retval/size);
     }
     break;
-#endif
   default:  // this is an internal error, no diag yet.
     fprintf(stderr,"illegal format '%d' in cfr_read!\n",stream->format);
     exit(1);
@@ -332,7 +312,8 @@ ssize_t cfr_getline(char **lineptr, size_t *n, CFRFILE *stream) {
   // For bzip2 the speedup for additional buffering was only 5%
   // so I dropped it.
   // Returns -1 in case of an error.
-  
+  char *tmp;
+
   if (stream == NULL) return(-1);  
 
   switch (stream->format) {
@@ -346,7 +327,6 @@ ssize_t cfr_getline(char **lineptr, size_t *n, CFRFILE *stream) {
     }
     break;
 
-#ifndef DONT_HAVE_BZ2
   case 2:  // bzip2  
     {                
       size_t count;
@@ -358,11 +338,20 @@ ssize_t cfr_getline(char **lineptr, size_t *n, CFRFILE *stream) {
       // allocate initial buffer if none was passed or size was zero
       if (*lineptr == NULL) {
         *lineptr = (char *) calloc(120, 1);
+        if(*lineptr == NULL) {
+            stream->error1 = errno;
+            return(-1);
+        }
         *n = 120;
       }
       if (*n == 0) {
         *n = 120;
-        *lineptr = (char *) realloc(*lineptr, *n); // to avoid memory-leaks
+        tmp = (char *) realloc(*lineptr, *n); // to avoid memory-leaks
+        if(tmp == NULL) {
+            stream->error1 = errno;
+            return(-1);
+        }
+        *lineptr = tmp;
       }
 
       count = 0;
@@ -375,11 +364,12 @@ ssize_t cfr_getline(char **lineptr, size_t *n, CFRFILE *stream) {
         count ++;
         if (count >= *n) {
           *n = 2 * *n;
-          *lineptr = (char *) realloc(*lineptr, *n);
-          if (*lineptr == NULL) {
+          tmp = (char *) realloc(*lineptr, *n);
+          if (tmp == NULL) {
             stream->error1 = errno;
             return(-1);
           }
+          *lineptr = tmp;
         }
         (*lineptr)[count-1] = c;
       } while (c != '\n');
@@ -387,11 +377,9 @@ ssize_t cfr_getline(char **lineptr, size_t *n, CFRFILE *stream) {
       return(count);
     }
     break;
-#endif
-#ifndef DONT_HAVE_GZ
   case 3:  // gzip
     { 
-      char * return_ptr = gzgets((gzFile *)(stream->data2), *lineptr, *n );
+      char * return_ptr = gzgets((gzFile)(stream->data2), *lineptr, *n );
       if (return_ptr == Z_NULL) {
         stream->error2 = errno;
         return(-1);
@@ -400,7 +388,6 @@ ssize_t cfr_getline(char **lineptr, size_t *n, CFRFILE *stream) {
   
     }
     break;
-#endif
   default:  // this is an internal error, no diag yet.
     fprintf(stderr,"illegal format '%d' in cfr_getline!\n",stream->format);
     exit(1);
@@ -449,38 +436,47 @@ char * cfr_strerror(CFRFILE *stream) {
   // Result may change on subsequent call to this function.
 
   static char res[120];
+  int ret;
   char * msg, * msg2;
 
   if (stream == NULL) {
-    asprintf(&msg,"Error: stream is NULL, i.e. not opened");
-    return(msg);
+    snprintf(res, sizeof(res), "%s", "Error: stream is NULL, i.e. not opened");
+    return(res);
   }
 
-  asprintf(&msg,
+  ret = asprintf(&msg,
            "stream-i/o: %s, %s  [%s]",
            stream->eof?"EOF":"",
            strerror(stream->error1),
            cfr_compressor_str(stream));
+  if (ret == -1)
+    goto oom;
   if (stream->format == 2) {
-    asprintf(&msg2, 
+    ret = asprintf(&msg2, 
              "%s: %s",
              msg, 
              _cfr_compressor_strerror(stream->format, stream->error2));
     free(msg);
+    if (ret == -1)
+      goto oom;
     msg = msg2;
   } 
   if (stream->format == 3) {
-    asprintf(&msg2, 
+    ret = asprintf(&msg2, 
              "%s: %s",
              msg, 
-             gzerror((gzFile*)(stream->data2), &(stream->error2)));
+             gzerror((gzFile)(stream->data2), &(stream->error2)));
     free(msg);
+    if (ret == -1)
+      goto oom;
     msg = msg2;
   }
-  snprintf(res, 120, "%s", msg);
-  res[119] = 0;
+  snprintf(res, sizeof(res), "%s", msg);
   free(msg); 
   return(res);
+oom:
+  snprintf(res, sizeof(res), "%s", "Error: asprintf: out of memory");
+  return(res);
 }
 
 const char * cfr_compressor_str(CFRFILE *stream) {
@@ -509,22 +505,17 @@ const char * _cfr_compressor_strerror(int format, int err) {
     return("file not compressed");
     break;
     
-#ifndef DONT_HAVE_BZ2
   case 2:
     return(_bz2_strerror(err));
     break;
-#endif          
-#ifndef DONT_HAVE_GZ
   case 3:
     return NULL;
     break;
-#endif          
   default:
     return("unknowen compressor code");
   }  
 }
     
-#ifndef DONT_HAVE_BZ2
 const char * _bz2_strerror(int err) {
   // Since bzlib does not have strerror, we do it here manually.
   // This works for version 1.0 of 21 March 2000 of bzlib.h
@@ -547,5 +538,4 @@ const char * _bz2_strerror(int err) {
   default: return("unknowen bzip2 error code");
   }
 }
-#endif
     

+ 0 - 14
cfile_tools.h

@@ -34,13 +34,9 @@
 #include <stdio.h>
 #include <unistd.h>
 
-#ifndef DONT_HAVE_BZ2
 #include <bzlib.h>
-#endif
 
-#ifndef DONT_HAVE_GZ
 #include <zlib.h>
-#endif
 
 // Types
 
@@ -61,15 +57,7 @@ typedef struct _CFRFILE CFRFILE;
 
 // Formats
 
-#ifndef DONT_HAVE_BZ2
-  #ifndef DONT_HAVE_GZ
 	#define CFR_NUM_FORMATS 4
-  #else
-	#define CFR_NUM_FORMATS 3
-  #endif
-#else
-	#define CFR_NUM_FORMATS 2
-#endif
 
 // Functions
 
@@ -83,9 +71,7 @@ int          cfr_error(CFRFILE *stream);
 char       * cfr_strerror(CFRFILE *stream);
 const char * cfr_compressor_str(CFRFILE *stream);
 
-#ifndef DONT_HAVE_BZ2
 const char * _bz2_strerror(int err);
-#endif
 
 
 #endif

+ 4 - 4
configure.in

@@ -1,11 +1,11 @@
 dnl Process this file with autoconf to produce a configure script.
 AC_REVISION($Revision$)
 
-AC_INIT([libbgpdump], 1.4.99.15, [ris@ripe.net])
+AC_INIT([libbgpdump], 1.5.0, [ris@ripe.net])
 AC_CONFIG_SRCDIR([bgpdump_lib.c])
 AC_CONFIG_HEADERS([bgpdump-config.h])
 
-CFLAGS="-g -O3 $CFLAGS -Wall"
+CFLAGS="-g $CFLAGS -Wall"
 CFLAGS="$CFLAGS -Wsystem-headers -Wno-format-y2k -Wno-sign-compare -Wcast-align"
 CFLAGS="$CFLAGS -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wswitch -Wshadow"
 
@@ -23,8 +23,8 @@ AC_CHECK_TYPE(u_int8_t, , AC_DEFINE(u_int8_t, uint8_t, [Define if system headers
 AC_CHECK_TYPE(u_int16_t, , AC_DEFINE(u_int16_t, uint16_t, [Define if system headers do not define u_int16_t]))
 AC_CHECK_TYPE(u_int32_t, , AC_DEFINE(u_int32_t, uint32_t, [Define if system headers do not define u_int32_t]))
 
-AC_CHECK_LIB(z, gzopen, [], AC_DEFINE(DONT_HAVE_GZ, 1, Define if libz not present))
-AC_CHECK_LIB(bz2, BZ2_bzReadOpen, [], AC_DEFINE(DONT_HAVE_BZ2, 1, Define if libbzip2 not present))
+AC_CHECK_LIB(z, gzopen, [], AC_MSG_ERROR([libz not found],1))
+AC_CHECK_LIB(bz2, BZ2_bzReadOpen, [], AC_MSG_ERROR([libbzip2 not found],1))
 
 # Check for inet_ntoa in -lnsl if not found (Solaris)
 AC_CHECK_FUNCS(inet_ntoa, [], AC_CHECK_LIB(nsl, inet_ntoa, [], AC_MSG_ERROR([inet_ntoa not found],1)))

+ 4 - 4
test.sh

@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/bin/sh
 
 FAILURES=0
 
@@ -6,11 +6,11 @@ mkdir -p test_out
 
 echo "Running Regression Tests..."
 for mrt in `ls test_data`; do
-    echo -n "      testing $mrt..."
+    /bin/echo -n "      testing $mrt..."
     OUT=$mrt.bgp.gz
     ./bgpdump -vm test_data/$mrt > test_out/$OUT
-    gzcat test_expect/$OUT | diff -q test_out/$OUT -
-    if [ $? == 0 ]; then
+    gzip -cd test_expect/$OUT | diff -q test_out/$OUT -
+    if [ $? = 0 ]; then
         echo "success"
     else
         FAILURES=$(( $FAILURES + 1 ))

+ 2 - 2
util.c

@@ -66,9 +66,9 @@ void err(const char *fmt, ...) { log(ERR, error); }
 void warn(const char *fmt, ...) { log(WARNING, warn); }
 void debug(const char *fmt, ...) { log(INFO, info); }
 
-void time2str(struct tm* date,char *time_str)
+int time2str(struct tm* date,char *time_str)
 {
-    sprintf(time_str, "%02d/%02d/%02d %02d:%02d:%02d", date->tm_mon+1, date->tm_mday, date->tm_year%100,
+    return sprintf(time_str, "%02d/%02d/%02d %02d:%02d:%02d", date->tm_mon+1, date->tm_mday, date->tm_year%100,
             date->tm_hour, date->tm_min, date->tm_sec);
 }
 

+ 1 - 1
util.h

@@ -38,7 +38,7 @@ char *fmt_ipv4(BGPDUMP_IP_ADDRESS addr, char *buffer);
 char *fmt_ipv6(BGPDUMP_IP_ADDRESS addr, char *buffer);
 void test_fmt_ip(void);
 
-void time2str(struct tm* date,char *time_str);
+int time2str(struct tm* date,char *time_str);
 int int2str(uint32_t value, char* str);
 void test_utils(void);