diff --git a/file.c b/file.c index a0c941eacc..a164626c8d 100644 --- a/file.c +++ b/file.c @@ -1774,13 +1774,16 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb if (redissect) { /* - * Decryption secrets are read while sequentially processing records and - * then passed to the dissector. During redissection, the previous secrets - * are lost (see epan_free above), but they are not read again from the - * file as only packet records are re-read. Therefore reset the wtap secrets - * callback such that wtap resupplies the secrets callback with previously - * read secrets. + * Decryption secrets and name resolution blocks are read while + * sequentially processing records and then passed to the dissector. + * During redissection, the previous information is lost (see epan_free + * above), but they are not read again from the file as only packet + * records are re-read. Therefore reset the wtap secrets and name + * resolution callbacks such that wtap resupplies the callbacks with + * previously read information. */ + wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name); + wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name); wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback); } diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index 4a51d4a499..51e2736f1d 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -250,8 +250,6 @@ typedef struct interface_info_s { typedef struct { guint current_section_number; /**< Section number of the current section being read sequentially */ GArray *sections; /**< Sections found in the capture file. */ - wtap_new_ipv4_callback_t add_new_ipv4; - wtap_new_ipv6_callback_t add_new_ipv6; } pcapng_t; /* @@ -2305,7 +2303,6 @@ pcapng_process_name_resolution_block_option(wtapng_block_t *wblock, static gboolean pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, - pcapng_t *pn, section_info_t *section_info, wtapng_block_t *wblock, int *err, gchar **err_info) @@ -2318,6 +2315,7 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, guint record_len, opt_cont_buf_len; char *namep; int namelen; + wtapng_nrb_mandatory_t *nrb_mand; /* * Is this block long enough to be an NRB? @@ -2341,6 +2339,11 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, wblock->block = wtap_block_create(WTAP_BLOCK_NAME_RESOLUTION); } + /* + * Set the mandatory values for the block. + */ + nrb_mand = (wtapng_nrb_mandatory_t *)wtap_block_get_mandatory_data(wblock->block); + /* * Start out with a buffer big enough for an IPv6 address and one * 64-byte name; we'll make the buffer bigger if necessary. @@ -2416,29 +2419,30 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, } block_read += nrb.record_len; - if (pn->add_new_ipv4) { + /* + * Scan through all the names in + * the record and add them. + */ + memcpy(&v4_addr, + ws_buffer_start_ptr(&nrb_rec), 4); + /* IPv4 address is in big-endian order in the file always, which is how we store + it internally as well, so don't byte-swap it */ + for (namep = (char *)ws_buffer_start_ptr(&nrb_rec) + 4, record_len = nrb.record_len - 4; + record_len != 0; + namep += namelen, record_len -= namelen) { /* - * Scan through all the names in - * the record and add them. + * Scan forward for a null + * byte. */ - memcpy(&v4_addr, - ws_buffer_start_ptr(&nrb_rec), 4); - /* IPv4 address is in big-endian order in the file always, which is how we store - it internally as well, so don't byte-swap it */ - for (namep = (char *)ws_buffer_start_ptr(&nrb_rec) + 4, record_len = nrb.record_len - 4; - record_len != 0; - namep += namelen, record_len -= namelen) { - /* - * Scan forward for a null - * byte. - */ - namelen = name_resolution_block_find_name_end(namep, record_len, err, err_info); - if (namelen == -1) { - ws_buffer_free(&nrb_rec); - return FALSE; /* fail */ - } - pn->add_new_ipv4(v4_addr, namep, FALSE); + namelen = name_resolution_block_find_name_end(namep, record_len, err, err_info); + if (namelen == -1) { + ws_buffer_free(&nrb_rec); + return FALSE; /* fail */ } + hashipv4_t *tp = g_new0(hashipv4_t, 1); + tp->addr = v4_addr; + (void) g_strlcpy(tp->name, namep, MAXNAMELEN); + nrb_mand->ipv4_addr_list = g_list_prepend(nrb_mand->ipv4_addr_list, tp); } if (!wtap_read_bytes(fh, NULL, PADDING4(nrb.record_len), err, err_info)) { @@ -2484,22 +2488,22 @@ pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, } block_read += nrb.record_len; - if (pn->add_new_ipv6) { - for (namep = (char *)ws_buffer_start_ptr(&nrb_rec) + 16, record_len = nrb.record_len - 16; - record_len != 0; - namep += namelen, record_len -= namelen) { - /* - * Scan forward for a null - * byte. - */ - namelen = name_resolution_block_find_name_end(namep, record_len, err, err_info); - if (namelen == -1) { - ws_buffer_free(&nrb_rec); - return FALSE; /* fail */ - } - pn->add_new_ipv6(ws_buffer_start_ptr(&nrb_rec), - namep, FALSE); + for (namep = (char *)ws_buffer_start_ptr(&nrb_rec) + 16, record_len = nrb.record_len - 16; + record_len != 0; + namep += namelen, record_len -= namelen) { + /* + * Scan forward for a null + * byte. + */ + namelen = name_resolution_block_find_name_end(namep, record_len, err, err_info); + if (namelen == -1) { + ws_buffer_free(&nrb_rec); + return FALSE; /* fail */ } + hashipv6_t *tp = g_new0(hashipv6_t, 1); + memcpy(tp->addr, ws_buffer_start_ptr(&nrb_rec), sizeof tp->addr); + (void) g_strlcpy(tp->name, namep, MAXNAMELEN); + nrb_mand->ipv6_addr_list = g_list_prepend(nrb_mand->ipv6_addr_list, tp); } if (!wtap_read_bytes(fh, NULL, PADDING4(nrb.record_len), err, err_info)) { @@ -3282,7 +3286,7 @@ pcapng_read_block(wtap *wth, FILE_T fh, pcapng_t *pn, return FALSE; break; case(BLOCK_TYPE_NRB): - if (!pcapng_read_name_resolution_block(fh, &bh, pn, section_info, wblock, err, err_info)) + if (!pcapng_read_name_resolution_block(fh, &bh, section_info, wblock, err, err_info)) return FALSE; break; case(BLOCK_TYPE_ISB): @@ -3362,6 +3366,22 @@ pcapng_process_idb(wtap *wth, section_info_t *section_info, g_array_append_val(section_info->interfaces, iface_info); } +/* Process an NRB that we have just read. */ +static void +pcapng_process_nrb(wtap *wth, wtapng_block_t *wblock) +{ + wtapng_process_nrb(wth, wblock->block); + + if (wth->nrb_hdrs == NULL) { + wth->nrb_hdrs = g_array_new(FALSE, FALSE, sizeof(wtap_block_t)); + } + /* Store NRB such that it can be saved by the dumper. + * XXX: NRBs are not saved yet by the dumper, only the resolved + * and used lookups passed into via wtap_dump_set_addrinfo_list() + */ + g_array_append_val(wth->nrb_hdrs, wblock->block); +} + /* Process a DSB that we have just read. */ static void pcapng_process_dsb(wtap *wth, wtapng_block_t *wblock) @@ -3514,14 +3534,6 @@ pcapng_open(wtap *wth, int *err, gchar **err_info) pcapng->sections = g_array_sized_new(FALSE, FALSE, sizeof(section_info_t), 1); g_array_append_val(pcapng->sections, first_section); - /* - * Set the callbacks for new addresses to null; if our caller wants - * to be called, they will set them to point to the appropriate - * caller. - */ - pcapng->add_new_ipv4 = NULL; - pcapng->add_new_ipv6 = NULL; - wth->subtype_read = pcapng_read; wth->subtype_seek_read = pcapng_seek_read; wth->subtype_close = pcapng_close; @@ -3603,9 +3615,6 @@ pcapng_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, wblock.frame_buffer = buf; wblock.rec = rec; - pcapng->add_new_ipv4 = wth->add_new_ipv4; - pcapng->add_new_ipv6 = wth->add_new_ipv6; - /* read next block */ while (1) { *data_offset = file_tell(wth->fh); @@ -3678,10 +3687,8 @@ pcapng_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, case(BLOCK_TYPE_NRB): /* More name resolution entries */ ws_debug("block type BLOCK_TYPE_NRB"); - if (wth->nrb_hdrs == NULL) { - wth->nrb_hdrs = g_array_new(FALSE, FALSE, sizeof(wtap_block_t)); - } - g_array_append_val(wth->nrb_hdrs, wblock.block); + pcapng_process_nrb(wth, &wblock); + /* Do not free wblock.block, it is consumed by pcapng_process_nrb */ break; case(BLOCK_TYPE_ISB): diff --git a/wiretap/wtap-int.h b/wiretap/wtap-int.h index 193808c45a..2b1ad434a9 100644 --- a/wiretap/wtap-int.h +++ b/wiretap/wtap-int.h @@ -340,6 +340,12 @@ wtap_full_file_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf, void wtap_add_idb(wtap *wth, wtap_block_t idb); +/** + * Invokes the callback with the given name resolution block. + */ +void +wtapng_process_nrb(wtap *wth, wtap_block_t nrb); + /** * Invokes the callback with the given decryption secrets block. */ diff --git a/wiretap/wtap.c b/wiretap/wtap.c index 5d1326e0f0..8e63e81f5f 100644 --- a/wiretap/wtap.c +++ b/wiretap/wtap.c @@ -1490,14 +1490,81 @@ wtap_cleareof(wtap *wth) { file_clearerr(wth->fh); } +static inline void +wtapng_process_nrb_ipv4(wtap *wth, wtap_block_t nrb) +{ + const wtapng_nrb_mandatory_t *nrb_mand = (wtapng_nrb_mandatory_t*)wtap_block_get_mandatory_data(nrb); + + if (wth->add_new_ipv4) { + for (GList *elem = nrb_mand->ipv4_addr_list; elem != NULL; elem = elem->next) { + hashipv4_t *tp = elem->data; + wth->add_new_ipv4(tp->addr, tp->name, FALSE); + } + } +} + +static inline void +wtapng_process_nrb_ipv6(wtap *wth, wtap_block_t nrb) +{ + const wtapng_nrb_mandatory_t *nrb_mand = (wtapng_nrb_mandatory_t*)wtap_block_get_mandatory_data(nrb); + + if (wth->add_new_ipv6) { + for (GList *elem = nrb_mand->ipv6_addr_list; elem != NULL; elem = elem->next) { + hashipv6_t *tp = elem->data; + wth->add_new_ipv6(tp->addr, tp->name, FALSE); + } + } +} + void wtap_set_cb_new_ipv4(wtap *wth, wtap_new_ipv4_callback_t add_new_ipv4) { - if (wth) - wth->add_new_ipv4 = add_new_ipv4; + if (!wth) + return; + + wth->add_new_ipv4 = add_new_ipv4; + + /* Are there any existing NRBs? (XXX: Unlike with DSBs, the + * GArray of nrb_hdrs is not initialized until the first one + * is encountered. */ + if (!wth->nrb_hdrs) + return; + /* + * Send all NRBs that were read so far to the new callback. file.c + * relies on this to support redissection (during redissection, the + * previous name resolutions are lost and has to be resupplied). + */ + for (guint i = 0; i < wth->nrb_hdrs->len; i++) { + wtap_block_t nrb = g_array_index(wth->nrb_hdrs, wtap_block_t, i); + wtapng_process_nrb_ipv4(wth, nrb); + } } void wtap_set_cb_new_ipv6(wtap *wth, wtap_new_ipv6_callback_t add_new_ipv6) { - if (wth) - wth->add_new_ipv6 = add_new_ipv6; + if (!wth) + return; + + wth->add_new_ipv6 = add_new_ipv6; + + /* Are there any existing NRBs? (XXX: Unlike with DSBs, the + * GArray of nrb_hdrs is not initialized until the first one + * is encountered. */ + if (!wth->nrb_hdrs) + return; + /* + * Send all NRBs that were read so far to the new callback. file.c + * relies on this to support redissection (during redissection, the + * previous name resolutions are lost and has to be resupplied). + */ + for (guint i = 0; i < wth->nrb_hdrs->len; i++) { + wtap_block_t nrb = g_array_index(wth->nrb_hdrs, wtap_block_t, i); + wtapng_process_nrb_ipv6(wth, nrb); + } +} + +void +wtapng_process_nrb(wtap *wth, wtap_block_t nrb) +{ + wtapng_process_nrb_ipv4(wth, nrb); + wtapng_process_nrb_ipv6(wth, nrb); } void wtap_set_cb_new_secrets(wtap *wth, wtap_new_secrets_callback_t add_new_secrets) { diff --git a/wiretap/wtap_opttypes.c b/wiretap/wtap_opttypes.c index 753e72f63b..cc20214577 100644 --- a/wiretap/wtap_opttypes.c +++ b/wiretap/wtap_opttypes.c @@ -1595,9 +1595,46 @@ static void shb_copy_mand(wtap_block_t dest_block, wtap_block_t src_block) static void nrb_create(wtap_block_t block) { - block->mandatory_data = NULL; + block->mandatory_data = g_new0(wtapng_nrb_mandatory_t, 1); } +static void nrb_free_mand(wtap_block_t block) +{ + wtapng_nrb_mandatory_t *mand = (wtapng_nrb_mandatory_t *)block->mandatory_data; + g_list_free_full(mand->ipv4_addr_list, g_free); + g_list_free_full(mand->ipv6_addr_list, g_free); +} + +#if 0 +static gpointer copy_hashipv4(gconstpointer src, gpointer user_data _U_ +{ + hashipv4_t *src_ipv4 = (hashipv4_t*)src; + hashipv4_t *dst = g_new0(hashipv4_t, 1); + dst->addr = src_ipv4->addr; + (void) g_strlcpy(dst->name, src_ipv4->name, MAXNAMELEN); + return dst; +} + +static gpointer copy_hashipv4(gconstpointer src, gpointer user_data _U_ +{ + hashipv6_t *src_ipv6 = (hashipv6_t*)src; + hashipv6_t *dst = g_new0(hashipv6_t, 1); + dst->addr = src_ipv4->addr; + (void) g_strlcpy(dst->name, src_ipv4->name, MAXNAMELEN); + return dst; +} + +static void nrb_copy_mand(wtap_block_t dest_block, wtap_block_t src_block) +{ + wtapng_nrb_mandatory_t *src = (wtapng_nrb_mandatory_t *)src_block->mandatory_data; + wtapng_nrb_mandatory_t *dst = (wtapng_nrb_mandatory_t *)dest_block->mandatory_data; + g_list_free_full(dst->ipv4_addr_list, g_free); + g_list_free_full(dst->ipv6_addr_list, g_free); + dst->ipv4_addr_list = g_list_copy_deep(src->ipv4_addr_list, copy_hashipv4, NULL); + dst->ipv6_addr_list = g_list_copy_deep(src->ipv6_addr_list, copy_hashipv6, NULL); +} +#endif + static void isb_create(wtap_block_t block) { block->mandatory_data = g_new0(wtapng_if_stats_mandatory_t, 1); @@ -1799,8 +1836,18 @@ void wtap_opttypes_initialize(void) "NRB", /* name */ "Name Resolution Block", /* description */ nrb_create, /* create */ - NULL, /* free_mand */ - NULL, /* copy_mand */ + nrb_free_mand, /* free_mand */ + /* We eventually want to copy these, when dumper actually + * writes them out. If we're actually processing packets, + * as opposed to just reading and writing a file without + * printing (e.g., editcap), do we still want to copy all + * the pre-existing NRBs, or do we want to limit it to + * the actually used addresses, as currently? + */ +#if 0 + nrb_copy_mand, /* copy_mand */ +#endif + NULL, NULL /* options */ }; static const wtap_opttype_t ns_dnsname = { diff --git a/wiretap/wtap_opttypes.h b/wiretap/wtap_opttypes.h index b21c2e1efa..f9553f23b9 100644 --- a/wiretap/wtap_opttypes.h +++ b/wiretap/wtap_opttypes.h @@ -227,6 +227,14 @@ typedef struct wtapng_if_descr_mandatory_s { * pcapng ISB:s or equivalent(?)*/ } wtapng_if_descr_mandatory_t; +/** + * Holds the required data from a WTAP_BLOCK_NAME_RESOLUTION. + */ +typedef struct wtapnf_nrb_mandatory_s { + GList *ipv4_addr_list; + GList *ipv6_addr_list; +} wtapng_nrb_mandatory_t; + /** * Holds the required data from a WTAP_BLOCK_IF_STATISTICS. */