850 lines
27 KiB
C++
850 lines
27 KiB
C++
/* decode_as_model.cpp
|
|
* Data model for Decode As records.
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include <errno.h>
|
|
|
|
#include "decode_as_model.h"
|
|
#include <epan/to_str.h>
|
|
#include <epan/decode_as.h>
|
|
#include <epan/epan_dissect.h>
|
|
#include <epan/packet.h>
|
|
#include <epan/prefs.h>
|
|
#include <epan/prefs-int.h>
|
|
#include <epan/dissectors/packet-dcerpc.h>
|
|
|
|
#include <ui/qt/utils/qt_ui_utils.h>
|
|
#include <ui/qt/utils/variant_pointer.h>
|
|
#include <wsutil/file_util.h>
|
|
#include <wsutil/ws_assert.h>
|
|
|
|
#include <QVector>
|
|
|
|
static const char *DEFAULT_TABLE = "tcp.port"; // Arbitrary
|
|
static const char *DEFAULT_UI_TABLE = "TCP port"; // Arbitrary
|
|
|
|
DecodeAsItem::DecodeAsItem(const char* table_name, gconstpointer selector) :
|
|
tableName_(DEFAULT_TABLE),
|
|
tableUIName_(DEFAULT_UI_TABLE),
|
|
selectorUint_(0),
|
|
selectorString_(""),
|
|
selectorDCERPC_(NULL),
|
|
default_dissector_(DECODE_AS_NONE),
|
|
current_dissector_(DECODE_AS_NONE),
|
|
dissector_handle_(NULL)
|
|
{
|
|
if (table_name == nullptr)
|
|
return;
|
|
|
|
init(table_name, selector);
|
|
}
|
|
|
|
DecodeAsItem::DecodeAsItem(const decode_as_t *entry, gconstpointer selector) :
|
|
tableName_(DEFAULT_TABLE),
|
|
tableUIName_(DEFAULT_UI_TABLE),
|
|
selectorUint_(0),
|
|
selectorString_(""),
|
|
selectorDCERPC_(NULL),
|
|
default_dissector_(DECODE_AS_NONE),
|
|
current_dissector_(DECODE_AS_NONE),
|
|
dissector_handle_(NULL)
|
|
{
|
|
if (entry == nullptr)
|
|
return;
|
|
|
|
init(entry->table_name, selector);
|
|
}
|
|
|
|
DecodeAsItem::~DecodeAsItem()
|
|
{
|
|
}
|
|
|
|
void DecodeAsItem::init(const char* table_name, gconstpointer selector)
|
|
{
|
|
tableName_ = table_name;
|
|
tableUIName_ = get_dissector_table_ui_name(tableName_);
|
|
|
|
dissector_handle_t default_handle = NULL;
|
|
ftenum_t selector_type = get_dissector_table_selector_type(tableName_);
|
|
if (FT_IS_STRING(selector_type)) {
|
|
if (selector != NULL) {
|
|
default_handle = dissector_get_default_string_handle(tableName_, (const char*)selector);
|
|
selectorString_ = QString((const char*)selector);
|
|
}
|
|
} else if (FT_IS_UINT(selector_type)) {
|
|
if (selector != NULL) {
|
|
selectorUint_ = GPOINTER_TO_UINT(selector);
|
|
default_handle = dissector_get_default_uint_handle(tableName_, selectorUint_);
|
|
}
|
|
} else if (selector_type == FT_NONE) {
|
|
// There is no default for an FT_NONE dissector table
|
|
} else if (selector_type == FT_GUID) {
|
|
/* Special handling for DCE/RPC dissectors */
|
|
if (strcmp(tableName_, DCERPC_TABLE_NAME) == 0) {
|
|
selectorDCERPC_ = (decode_dcerpc_bind_values_t*)(selector);
|
|
}
|
|
}
|
|
|
|
if (default_handle != NULL) {
|
|
default_dissector_ = dissector_handle_get_description(default_handle);
|
|
// When adding a new record, we set the "current" values equal to
|
|
// the default, so the user can easily reset the value.
|
|
// The existing value read from the prefs file should already
|
|
// be added to the table from reading the prefs file.
|
|
// When reading existing values the current dissector should be
|
|
// set explicitly to the actual current value.
|
|
current_dissector_ = default_dissector_;
|
|
dissector_handle_ = default_handle;
|
|
}
|
|
}
|
|
|
|
void DecodeAsItem::setTable(const decode_as_t *entry)
|
|
{
|
|
if (entry == nullptr)
|
|
return;
|
|
|
|
tableName_ = entry->table_name;
|
|
tableUIName_ = get_dissector_table_ui_name(entry->table_name);
|
|
|
|
/* XXX: Should the selector values be reset (e.g., to 0 and "")
|
|
* What if someone tries to change the table to the DCERPC table?
|
|
* That doesn't really work without the DCERPC special handling.
|
|
*/
|
|
|
|
updateHandles();
|
|
}
|
|
|
|
void DecodeAsItem::setSelector(const QString &value)
|
|
{
|
|
ftenum_t selector_type = get_dissector_table_selector_type(tableName_);
|
|
|
|
if (FT_IS_STRING(selector_type)) {
|
|
selectorString_ = value;
|
|
} else if (FT_IS_UINT(selector_type)) {
|
|
selectorUint_ = value.toUInt(Q_NULLPTR, 0);
|
|
}
|
|
|
|
updateHandles();
|
|
}
|
|
|
|
void DecodeAsItem::setDissectorHandle(dissector_handle_t handle)
|
|
{
|
|
dissector_handle_ = handle;
|
|
if (handle == nullptr) {
|
|
current_dissector_ = DECODE_AS_NONE;
|
|
} else {
|
|
current_dissector_ = dissector_handle_get_description(handle);
|
|
}
|
|
}
|
|
|
|
void DecodeAsItem::updateHandles()
|
|
{
|
|
ftenum_t selector_type = get_dissector_table_selector_type(tableName_);
|
|
dissector_handle_t default_handle = nullptr;
|
|
|
|
if (FT_IS_STRING(selector_type)) {
|
|
default_handle = dissector_get_default_string_handle(tableName_, qUtf8Printable(selectorString_));
|
|
} else if (FT_IS_UINT(selector_type)) {
|
|
default_handle = dissector_get_default_uint_handle(tableName_, selectorUint_);
|
|
}
|
|
if (default_handle != nullptr) {
|
|
default_dissector_ = dissector_handle_get_description(default_handle);
|
|
} else {
|
|
default_dissector_ = DECODE_AS_NONE;
|
|
}
|
|
}
|
|
|
|
DecodeAsModel::DecodeAsModel(QObject *parent, capture_file *cf) :
|
|
QAbstractTableModel(parent),
|
|
cap_file_(cf)
|
|
{
|
|
}
|
|
|
|
DecodeAsModel::~DecodeAsModel()
|
|
{
|
|
foreach(DecodeAsItem* item, decode_as_items_)
|
|
delete item;
|
|
decode_as_items_.clear();
|
|
}
|
|
|
|
Qt::ItemFlags DecodeAsModel::flags(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid())
|
|
return Qt::ItemFlags();
|
|
|
|
DecodeAsItem* item = decode_as_items_[index.row()];
|
|
|
|
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
|
|
switch(index.column())
|
|
{
|
|
case DecodeAsModel::colTable:
|
|
case DecodeAsModel::colProtocol:
|
|
flags |= Qt::ItemIsEditable;
|
|
break;
|
|
case DecodeAsModel::colSelector:
|
|
{
|
|
ftenum_t selector_type = get_dissector_table_selector_type(item->tableName());
|
|
if ((selector_type != FT_NONE) &&
|
|
(item->selectorDCERPC() == NULL))
|
|
flags |= Qt::ItemIsEditable;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return flags;
|
|
}
|
|
|
|
QVariant DecodeAsModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid()) {
|
|
return QVariant();
|
|
}
|
|
|
|
DecodeAsItem* item;
|
|
|
|
switch (role)
|
|
{
|
|
case Qt::ToolTipRole:
|
|
switch (index.column())
|
|
{
|
|
case colTable:
|
|
return tr("Match using this field");
|
|
case colSelector:
|
|
return tr("Change behavior when the field matches this value");
|
|
case colType:
|
|
return tr("Field value type (and base, if Integer)");
|
|
case colDefault:
|
|
return tr("Default \"Decode As\" behavior");
|
|
case colProtocol:
|
|
return tr("Current\"Decode As\" behavior");
|
|
}
|
|
return QVariant();
|
|
case Qt::DisplayRole:
|
|
case Qt::EditRole:
|
|
item = decode_as_items_[index.row()];
|
|
if (item == NULL)
|
|
return QVariant();
|
|
|
|
switch (index.column())
|
|
{
|
|
case colTable:
|
|
return item->tableUIName();
|
|
case colSelector:
|
|
{
|
|
ftenum_t selector_type = get_dissector_table_selector_type(item->tableName());
|
|
if (FT_IS_UINT(selector_type)) {
|
|
return entryString(item->tableName(), GUINT_TO_POINTER(item->selectorUint()));
|
|
} else if (FT_IS_STRING(selector_type)) {
|
|
return entryString(item->tableName(), (gconstpointer)item->selectorString().toUtf8().constData());
|
|
} else if (selector_type == FT_GUID) {
|
|
if (item->selectorDCERPC() != NULL) {
|
|
return item->selectorDCERPC()->ctx_id;
|
|
}
|
|
}
|
|
|
|
return DECODE_AS_NONE;
|
|
}
|
|
case colType:
|
|
{
|
|
ftenum_t selector_type = get_dissector_table_selector_type(item->tableName());
|
|
|
|
if (FT_IS_STRING(selector_type)) {
|
|
return tr("String");
|
|
} else if (FT_IS_UINT(selector_type)) {
|
|
QString type_desc = tr("Integer, base ");
|
|
switch (get_dissector_table_param(item->tableName())) {
|
|
case BASE_OCT:
|
|
type_desc.append("8");
|
|
break;
|
|
case BASE_DEC:
|
|
type_desc.append("10");
|
|
break;
|
|
case BASE_HEX:
|
|
type_desc.append("16");
|
|
break;
|
|
default:
|
|
type_desc.append(tr("unknown"));
|
|
}
|
|
return type_desc;
|
|
} else if (selector_type == FT_NONE) {
|
|
return tr("<none>");
|
|
} else if (selector_type == FT_GUID) {
|
|
if (item->selectorDCERPC() != NULL) {
|
|
return QString("ctx_id");
|
|
} else {
|
|
return tr("GUID");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case colDefault:
|
|
return item->defaultDissector();
|
|
case colProtocol:
|
|
return item->currentDissector();
|
|
}
|
|
return QVariant();
|
|
|
|
case Qt::UserRole:
|
|
item = decode_as_items_[index.row()];
|
|
return QVariant::fromValue(static_cast<void *>(item));
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
QVariant DecodeAsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
|
|
return QVariant();
|
|
|
|
switch (section) {
|
|
case colTable:
|
|
return tr("Field");
|
|
case colSelector:
|
|
return tr("Value");
|
|
case colType:
|
|
return tr("Type");
|
|
case colDefault:
|
|
return tr("Default");
|
|
case colProtocol:
|
|
return tr("Current");
|
|
default:
|
|
ws_assert_not_reached();
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
int DecodeAsModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
// there are no children
|
|
if (parent.isValid()) {
|
|
return 0;
|
|
}
|
|
|
|
return static_cast<int>(decode_as_items_.count());
|
|
}
|
|
|
|
int DecodeAsModel::columnCount(const QModelIndex &parent) const
|
|
{
|
|
// there are no children
|
|
if (parent.isValid()) {
|
|
return 0;
|
|
}
|
|
|
|
return colDecodeAsMax;
|
|
}
|
|
|
|
bool DecodeAsModel::setData(const QModelIndex &cur_index, const QVariant &value, int role)
|
|
{
|
|
if (!cur_index.isValid())
|
|
return false;
|
|
|
|
if (role != Qt::EditRole)
|
|
return false;
|
|
|
|
if (data(cur_index, role) == value) {
|
|
// Data appears unchanged, do not do additional checks.
|
|
return true;
|
|
}
|
|
|
|
DecodeAsItem* item = decode_as_items_[cur_index.row()];
|
|
|
|
switch(cur_index.column())
|
|
{
|
|
case DecodeAsModel::colTable:
|
|
{
|
|
QString valueStr = value.toString();
|
|
//grab the table values from the Decode As list because they are persistent
|
|
for (GList *cur = decode_as_list; cur; cur = cur->next) {
|
|
decode_as_t *entry = (decode_as_t *) cur->data;
|
|
if (valueStr.compare(get_dissector_table_ui_name(entry->table_name)) == 0) {
|
|
item->setTable(entry);
|
|
//all other columns affected
|
|
emit dataChanged(index(cur_index.row(), colSelector),
|
|
index(cur_index.row(), colProtocol));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case DecodeAsModel::colProtocol:
|
|
{
|
|
dissector_handle_t handle = VariantPointer<dissector_handle>::asPtr(value);
|
|
item->setDissectorHandle(handle);
|
|
break;
|
|
}
|
|
case DecodeAsModel::colSelector:
|
|
item->setSelector(value.toString());
|
|
emit dataChanged(index(cur_index.row(), colDefault),
|
|
index(cur_index.row(), colProtocol));
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DecodeAsModel::insertRows(int row, int count, const QModelIndex &/*parent*/)
|
|
{
|
|
// support insertion of just one item for now.
|
|
if (count != 1 || row < 0 || row > rowCount())
|
|
return false;
|
|
|
|
beginInsertRows(QModelIndex(), row, row);
|
|
|
|
DecodeAsItem* item = nullptr;
|
|
const decode_as_t *firstEntry = nullptr;
|
|
|
|
if (cap_file_ && cap_file_->edt) {
|
|
// Populate the new Decode As item with the last protocol layer
|
|
// that can support Decode As and has a selector field for that
|
|
// present in the frame.
|
|
//
|
|
// XXX: This treats 0 (for UInts) and empty strings the same as
|
|
// the fields for the tables not being present at all.
|
|
|
|
wmem_list_frame_t * protos = wmem_list_tail(cap_file_->edt->pi.layers);
|
|
int8_t curr_layer_num_saved = cap_file_->edt->pi.curr_layer_num;
|
|
uint8_t curr_layer_num = wmem_list_count(cap_file_->edt->pi.layers);
|
|
|
|
while (protos != NULL && item == nullptr) {
|
|
int proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
|
|
const char * proto_name = proto_get_protocol_filter_name(proto_id);
|
|
for (GList *cur = decode_as_list; cur; cur = cur->next) {
|
|
decode_as_t *entry = (decode_as_t *) cur->data;
|
|
if (g_strcmp0(proto_name, entry->name) == 0) {
|
|
if (firstEntry == nullptr) {
|
|
firstEntry = entry;
|
|
}
|
|
ftenum_t selector_type = get_dissector_table_selector_type(entry->table_name);
|
|
// Pick the first value in the packet for the current
|
|
// layer for the table
|
|
// XXX: What if the Decode As table supports multiple
|
|
// values, but the first possible one is 0/NULL?
|
|
cap_file_->edt->pi.curr_layer_num = curr_layer_num;
|
|
void *selector = entry->values[0].build_values[0](&cap_file_->edt->pi);
|
|
// FT_NONE tables don't need a value
|
|
if (selector != NULL || selector_type == FT_NONE) {
|
|
item = new DecodeAsItem(entry, selector);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
protos = wmem_list_frame_prev(protos);
|
|
curr_layer_num--;
|
|
}
|
|
|
|
cap_file_->edt->pi.curr_layer_num = curr_layer_num_saved;
|
|
}
|
|
|
|
// If we didn't find an entry with a valid selector, create an entry
|
|
// from the last table with an empty selector, or an empty entry.
|
|
if (item == nullptr) {
|
|
item = new DecodeAsItem(firstEntry);
|
|
}
|
|
decode_as_items_ << item;
|
|
|
|
endInsertRows();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DecodeAsModel::removeRows(int row, int count, const QModelIndex &/*parent*/)
|
|
{
|
|
if (count != 1 || row < 0 || row >= rowCount())
|
|
return false;
|
|
|
|
beginRemoveRows(QModelIndex(), row, row);
|
|
DecodeAsItem* item = decode_as_items_.takeAt(row);
|
|
delete item;
|
|
endRemoveRows();
|
|
|
|
return true;
|
|
}
|
|
|
|
void DecodeAsModel::clearAll()
|
|
{
|
|
if (rowCount() < 1)
|
|
return;
|
|
|
|
beginResetModel();
|
|
foreach(DecodeAsItem* item, decode_as_items_)
|
|
delete item;
|
|
decode_as_items_.clear();
|
|
endResetModel();
|
|
}
|
|
|
|
bool DecodeAsModel::copyRow(int dst_row, int src_row)
|
|
{
|
|
if (src_row < 0 || src_row >= rowCount() || dst_row < 0 || dst_row >= rowCount()) {
|
|
return false;
|
|
}
|
|
|
|
DecodeAsItem* src = decode_as_items_[src_row];
|
|
DecodeAsItem* dst = decode_as_items_[dst_row];
|
|
|
|
*dst = *src;
|
|
|
|
QVector<int> roles;
|
|
roles << Qt::EditRole << Qt::BackgroundRole;
|
|
emit dataChanged(index(dst_row, 0), index(dst_row, columnCount()), roles);
|
|
|
|
return true;
|
|
}
|
|
|
|
prefs_set_pref_e DecodeAsModel::readDecodeAsEntry(char *key, const char *value, void *private_data, bool)
|
|
{
|
|
DecodeAsModel *model = (DecodeAsModel*)private_data;
|
|
if (model == NULL)
|
|
return PREFS_SET_OK;
|
|
|
|
if (strcmp(key, DECODE_AS_ENTRY) != 0) {
|
|
return PREFS_SET_NO_SUCH_PREF;
|
|
}
|
|
|
|
/* Parse into table, selector, initial, current */
|
|
char **values = g_strsplit_set(value, ",", 4);
|
|
DecodeAsItem *item = nullptr;
|
|
|
|
dissector_table_t dissector_table = find_dissector_table(values[0]);
|
|
|
|
QString tableName(values[0]);
|
|
// Get the table values from the Decode As list because they are persistent
|
|
for (GList *cur = decode_as_list; cur; cur = cur->next) {
|
|
decode_as_t *entry = (decode_as_t *) cur->data;
|
|
if (tableName.compare(entry->table_name) == 0) {
|
|
item = new DecodeAsItem(entry);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (item == nullptr) {
|
|
g_strfreev(values);
|
|
return PREFS_SET_SYNTAX_ERR;
|
|
}
|
|
|
|
QString selector(values[1]);
|
|
item->setSelector(selector);
|
|
|
|
/* The value for the default dissector in the decode_as_entries file
|
|
* has no effect other than perhaps making the config file more
|
|
* informative when edited manually.
|
|
* We will actually display and reset to the programmatic default value.
|
|
*/
|
|
item->setDissectorHandle(dissector_table_get_dissector_handle(dissector_table, values[3]));
|
|
|
|
model->decode_as_items_ << item;
|
|
g_strfreev(values);
|
|
|
|
return PREFS_SET_OK;
|
|
}
|
|
|
|
bool DecodeAsModel::copyFromProfile(QString filename, const char **err)
|
|
{
|
|
FILE *fp = ws_fopen(filename.toUtf8().constData(), "r");
|
|
|
|
if (fp == NULL) {
|
|
*err = g_strerror(errno);
|
|
return false;
|
|
}
|
|
|
|
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
|
read_prefs_file(filename.toUtf8().constData(), fp, readDecodeAsEntry, this);
|
|
endInsertRows();
|
|
|
|
fclose(fp);
|
|
|
|
return true;
|
|
}
|
|
|
|
QString DecodeAsModel::entryString(const char *table_name, gconstpointer value)
|
|
{
|
|
QString entry_str;
|
|
ftenum_t selector_type = get_dissector_table_selector_type(table_name);
|
|
|
|
switch (selector_type) {
|
|
|
|
case FT_UINT8:
|
|
case FT_UINT16:
|
|
case FT_UINT24:
|
|
case FT_UINT32:
|
|
{
|
|
uint num_val = GPOINTER_TO_UINT(value);
|
|
switch (get_dissector_table_param(table_name)) {
|
|
|
|
case BASE_DEC:
|
|
entry_str = QString::number(num_val);
|
|
break;
|
|
|
|
case BASE_HEX:
|
|
int width;
|
|
switch (selector_type) {
|
|
case FT_UINT8:
|
|
width = 2;
|
|
break;
|
|
case FT_UINT16:
|
|
width = 4;
|
|
break;
|
|
case FT_UINT24:
|
|
width = 6;
|
|
break;
|
|
case FT_UINT32:
|
|
width = 8;
|
|
break;
|
|
|
|
default:
|
|
ws_assert_not_reached();
|
|
break;
|
|
}
|
|
entry_str = QString("%1").arg(int_to_qstring(num_val, width, 16));
|
|
break;
|
|
|
|
case BASE_OCT:
|
|
entry_str = "0" + QString::number(num_val, 8);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FT_STRING:
|
|
case FT_STRINGZ:
|
|
case FT_UINT_STRING:
|
|
case FT_STRINGZPAD:
|
|
case FT_STRINGZTRUNC:
|
|
entry_str = (const char *)value;
|
|
break;
|
|
|
|
case FT_GUID:
|
|
//avoid the assert for now
|
|
break;
|
|
|
|
case FT_NONE:
|
|
//doesn't really matter, just avoiding the assert
|
|
return "0";
|
|
|
|
default:
|
|
ws_assert_not_reached();
|
|
break;
|
|
}
|
|
return entry_str;
|
|
}
|
|
|
|
void DecodeAsModel::fillTable()
|
|
{
|
|
decode_as_items_.clear();
|
|
beginResetModel();
|
|
|
|
dissector_all_tables_foreach_changed(buildChangedList, this);
|
|
decode_dcerpc_add_show_list(buildDceRpcChangedList, this);
|
|
|
|
endResetModel();
|
|
}
|
|
|
|
void DecodeAsModel::setDissectorHandle(const QModelIndex &index, dissector_handle_t dissector_handle)
|
|
{
|
|
DecodeAsItem* item = decode_as_items_[index.row()];
|
|
if (item != NULL)
|
|
item->setDissectorHandle(dissector_handle);
|
|
}
|
|
|
|
void DecodeAsModel::buildChangedList(const char *table_name, ftenum_t, void *key, void *value, void *user_data)
|
|
{
|
|
DecodeAsModel *model = (DecodeAsModel*)user_data;
|
|
if (model == NULL)
|
|
return;
|
|
|
|
dissector_handle_t current_dh;
|
|
DecodeAsItem* item = new DecodeAsItem(table_name, key);
|
|
|
|
current_dh = dtbl_entry_get_handle((dtbl_entry_t *)value);
|
|
item->setDissectorHandle(current_dh);
|
|
|
|
model->decode_as_items_ << item;
|
|
}
|
|
|
|
void DecodeAsModel::buildDceRpcChangedList(void *data, void *user_data)
|
|
{
|
|
dissector_table_t sub_dissectors;
|
|
guid_key guid_val;
|
|
decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)data;
|
|
|
|
DecodeAsModel *model = (DecodeAsModel*)user_data;
|
|
if (model == NULL)
|
|
return;
|
|
|
|
DecodeAsItem* item = new DecodeAsItem(DCERPC_TABLE_NAME, binding);
|
|
|
|
sub_dissectors = find_dissector_table(DCERPC_TABLE_NAME);
|
|
|
|
guid_val.ver = binding->ver;
|
|
guid_val.guid = binding->uuid;
|
|
item->setDissectorHandle(dissector_get_guid_handle(sub_dissectors, &guid_val));
|
|
|
|
model->decode_as_items_ << item;
|
|
}
|
|
|
|
typedef QPair<const char *, uint32_t> UintPair;
|
|
typedef QPair<const char *, const char *> CharPtrPair;
|
|
|
|
void DecodeAsModel::gatherChangedEntries(const char *table_name,
|
|
ftenum_t selector_type, void *key, void *, void *user_data)
|
|
{
|
|
DecodeAsModel *model = qobject_cast<DecodeAsModel*>((DecodeAsModel*)user_data);
|
|
if (model == NULL)
|
|
return;
|
|
|
|
switch (selector_type) {
|
|
case FT_UINT8:
|
|
case FT_UINT16:
|
|
case FT_UINT24:
|
|
case FT_UINT32:
|
|
model->changed_uint_entries_ << UintPair(table_name, GPOINTER_TO_UINT(key));
|
|
break;
|
|
case FT_NONE:
|
|
//need to reset dissector table, so this needs to be in a changed list,
|
|
//might as well be the uint one.
|
|
model->changed_uint_entries_ << UintPair(table_name, 0);
|
|
break;
|
|
|
|
case FT_STRING:
|
|
case FT_STRINGZ:
|
|
case FT_UINT_STRING:
|
|
case FT_STRINGZPAD:
|
|
case FT_STRINGZTRUNC:
|
|
model->changed_string_entries_ << CharPtrPair(table_name, (const char *) key);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void DecodeAsModel::applyChanges()
|
|
{
|
|
dissector_table_t sub_dissectors;
|
|
module_t *module;
|
|
pref_t* pref_value;
|
|
dissector_handle_t handle;
|
|
// Reset all dissector tables, then apply all rules from model.
|
|
|
|
// We can't call g_hash_table_removed from g_hash_table_foreach, which
|
|
// means we can't call dissector_reset_{string,uint} from
|
|
// dissector_all_tables_foreach_changed. Collect changed entries in
|
|
// lists and remove them separately.
|
|
//
|
|
// If dissector_all_tables_remove_changed existed we could call it
|
|
// instead.
|
|
dissector_all_tables_foreach_changed(gatherChangedEntries, this);
|
|
foreach (UintPair uint_entry, changed_uint_entries_) {
|
|
/* Set "Decode As preferences" to default values */
|
|
sub_dissectors = find_dissector_table(uint_entry.first);
|
|
handle = dissector_get_uint_handle(sub_dissectors, uint_entry.second);
|
|
if (handle != NULL) {
|
|
module = prefs_find_module(proto_get_protocol_filter_name(dissector_handle_get_protocol_index(handle)));
|
|
pref_value = prefs_find_preference(module, uint_entry.first);
|
|
if (pref_value != NULL) {
|
|
module->prefs_changed_flags |= prefs_get_effect_flags(pref_value);
|
|
reset_pref(pref_value);
|
|
}
|
|
}
|
|
|
|
dissector_reset_uint(uint_entry.first, uint_entry.second);
|
|
}
|
|
changed_uint_entries_.clear();
|
|
foreach (CharPtrPair char_ptr_entry, changed_string_entries_) {
|
|
dissector_reset_string(char_ptr_entry.first, char_ptr_entry.second);
|
|
}
|
|
changed_string_entries_.clear();
|
|
|
|
foreach(DecodeAsItem *item, decode_as_items_) {
|
|
decode_as_t *decode_as_entry;
|
|
|
|
if (item->currentDissector().isEmpty()) {
|
|
continue;
|
|
}
|
|
|
|
for (GList *cur = decode_as_list; cur; cur = cur->next) {
|
|
decode_as_entry = (decode_as_t *) cur->data;
|
|
|
|
if (!g_strcmp0(decode_as_entry->table_name, item->tableName())) {
|
|
|
|
ftenum_t selector_type = get_dissector_table_selector_type(item->tableName());
|
|
gconstpointer selector_value;
|
|
QByteArray byteArray;
|
|
|
|
switch (selector_type) {
|
|
case FT_UINT8:
|
|
case FT_UINT16:
|
|
case FT_UINT24:
|
|
case FT_UINT32:
|
|
selector_value = GUINT_TO_POINTER(item->selectorUint());
|
|
break;
|
|
case FT_STRING:
|
|
case FT_STRINGZ:
|
|
case FT_UINT_STRING:
|
|
case FT_STRINGZPAD:
|
|
case FT_STRINGZTRUNC:
|
|
byteArray = item->selectorString().toUtf8();
|
|
selector_value = (gconstpointer) byteArray.constData();
|
|
break;
|
|
case FT_NONE:
|
|
//selector value is ignored, but dissector table needs to happen
|
|
selector_value = NULL;
|
|
break;
|
|
case FT_GUID:
|
|
if (item->selectorDCERPC() != NULL) {
|
|
selector_value = (gconstpointer)item->selectorDCERPC();
|
|
} else {
|
|
//TODO: Support normal GUID dissector tables
|
|
selector_value = NULL;
|
|
}
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
if ((item->currentDissector() == item->defaultDissector())) {
|
|
decode_as_entry->reset_value(decode_as_entry->table_name, selector_value);
|
|
sub_dissectors = find_dissector_table(decode_as_entry->table_name);
|
|
|
|
/* For now, only numeric dissector tables can use preferences */
|
|
if (FT_IS_UINT(dissector_table_get_type(sub_dissectors))) {
|
|
if (item->dissectorHandle() != NULL) {
|
|
module = prefs_find_module(proto_get_protocol_filter_name(dissector_handle_get_protocol_index(item->dissectorHandle())));
|
|
pref_value = prefs_find_preference(module, decode_as_entry->table_name);
|
|
if (pref_value != NULL) {
|
|
module->prefs_changed_flags |= prefs_get_effect_flags(pref_value);
|
|
prefs_remove_decode_as_value(pref_value, item->selectorUint(), true);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
} else {
|
|
decode_as_entry->change_value(decode_as_entry->table_name, selector_value, item->dissectorHandle(), item->currentDissector().toUtf8().constData());
|
|
sub_dissectors = find_dissector_table(decode_as_entry->table_name);
|
|
|
|
/* For now, only numeric dissector tables can use preferences */
|
|
if (item->dissectorHandle() != NULL) {
|
|
if (FT_IS_UINT(dissector_table_get_type(sub_dissectors))) {
|
|
module = prefs_find_module(proto_get_protocol_filter_name(dissector_handle_get_protocol_index(item->dissectorHandle())));
|
|
pref_value = prefs_find_preference(module, decode_as_entry->table_name);
|
|
if (pref_value != NULL) {
|
|
module->prefs_changed_flags |= prefs_get_effect_flags(pref_value);
|
|
prefs_add_decode_as_value(pref_value, item->selectorUint(), false);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
prefs_apply_all();
|
|
}
|