From c65d5a0a80faed9c9a1d6527be2faa6d92e14ea5 Mon Sep 17 00:00:00 2001 From: John Thacker Date: Fri, 20 Jan 2023 01:10:27 -0500 Subject: [PATCH] wiretap: Reprocess Name Resolution Blocks during redissect Keep name resolution information as mandatory elements for NRBs, and when the ipv4 or ipv6 callback is set, have name resolution entries from already read NRBs sent to the callback. rescan_packets can use this when redissecting to reobtain the name resolution entries from the NRB, similar to what is done with Decryption Secrets Blocks. (This can also later be used if we read NRBs and DSBs in pcapng_open before the first packet, and before the callbacks are set.) This doesn't yet make the changes to wtap_dumper to write them out, but is a step towards that too. (It's not clear in cases where we dissect packets whether we want to copy the entire NRB, or only write out actually used addresses as done now. For copying without reading a file, like with editcap, we presumably do want to copy them.) Fix #13425. Ping #15502 --- file.c | 15 +++--- wiretap/pcapng.c | 115 +++++++++++++++++++++------------------- wiretap/wtap-int.h | 6 +++ wiretap/wtap.c | 75 ++++++++++++++++++++++++-- wiretap/wtap_opttypes.c | 53 ++++++++++++++++-- wiretap/wtap_opttypes.h | 8 +++ 6 files changed, 205 insertions(+), 67 deletions(-) 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. */