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
This commit is contained in:
John Thacker 2023-01-20 01:10:27 -05:00
parent ee5435784d
commit c65d5a0a80
6 changed files with 205 additions and 67 deletions

15
file.c
View File

@ -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);
}

View File

@ -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):

View File

@ -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.
*/

View File

@ -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) {

View File

@ -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 = {

View File

@ -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.
*/