2 * Wireshark - Network traffic analyzer
4 * Copyright 1998 Gerald Combs <gerald@wireshark.org>
6 * SPDX-License-Identifier: GPL-2.0-or-later
10 // #define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
12 #include <wireshark.h>
14 #include <epan/value_string.h>
17 #include "dfilter-translator.h"
18 #include "sttype-field.h"
19 #include "sttype-op.h"
22 static GHashTable
*registered_translators_
;
24 static void cleanup_hash_table_key(gpointer data
)
29 bool register_dfilter_translator(const char *translator_name
, DFTranslator translator
)
31 if (!registered_translators_
) {
32 registered_translators_
= g_hash_table_new_full(g_str_hash
,
34 cleanup_hash_table_key
,
37 return g_hash_table_insert(registered_translators_
, g_strdup(translator_name
), translator
);
40 void deregister_dfilter_translator(const char *translator_name
)
42 if (!registered_translators_
) {
45 g_hash_table_remove(registered_translators_
, translator_name
);
48 char **get_dfilter_translator_list(void)
50 if (!registered_translators_
) {
54 GList
*key_l
= g_list_sort(g_hash_table_get_keys(registered_translators_
), (GCompareFunc
)g_ascii_strcasecmp
);
55 size_t key_count
= g_list_length(key_l
);
61 char **translator_list
= g_malloc(sizeof(char *) * (key_count
+ 1));
63 for (GList
*cur
= g_list_first(key_l
); cur
; cur
= g_list_next(cur
), idx
++) {
64 translator_list
[idx
] = (char *) cur
->data
;
66 translator_list
[key_count
] = NULL
;
69 return translator_list
;
72 // XXX We should return an error message for failed translations.
73 const char *translate_dfilter(const char *translator_name
, const char *dfilter
)
75 if (!registered_translators_
|| !translator_name
) {
79 DFTranslator translator
= (DFTranslator
) g_hash_table_lookup(registered_translators_
, translator_name
);
84 stnode_t
*root_node
= dfilter_get_syntax_tree(dfilter
);
89 GString
*translated_filter
= g_string_new("");
90 bool res
= translator(root_node
, translated_filter
);
91 stnode_free(root_node
);
93 return g_string_free(translated_filter
, !res
);
97 // pcap filter (BPF) translation
98 // XXX - Fields are spread across all sorts of dissectors; not sure if there is a better place for this.
101 stnode_op_to_pcap_filter(stnode_op_t op
) {
103 case STNODE_OP_NOT
: return "not";
104 case STNODE_OP_AND
: return "&&";
105 case STNODE_OP_OR
: return "||";
106 case STNODE_OP_ANY_EQ
: return "";
107 // case STNODE_OP_ALL_NE: return "!=";
108 case STNODE_OP_GT
: return "greater";
109 // case STNODE_OP_GE: return ">=";
110 case STNODE_OP_LT
: return "less";
111 // case STNODE_OP_LE: return "<=";
112 // case STNODE_OP_CONTAINS: return "icontains";
113 case STNODE_OP_UNARY_MINUS
: return "-";
115 case STNODE_OP_NOT_IN
:
122 // scanner.l in libpcap
123 static const string_string abbrev_to_pcap_filter
[] = {
125 { "eth.addr", "ether host" },
126 { "eth.dst", "ether dst" },
127 { "eth.src", "ether src" },
129 // { "slip", "slip" },
131 { "fddi.addr", "fddi host" },
132 { "fddi.dst", "fddi dst" },
133 { "fddi.src", "fddi src" },
135 { "tr.addr", "tr host" },
136 { "tr.dst", "tr dst" },
137 { "tr.src", "tr src" },
139 { "wlan.addr", "wlan host" },
140 { "wlan.ra", "wlan ra" },
141 { "wlan.ta", "wlan ta" },
142 // { "wlan.da", "wlan" },
143 // { "wlan", "wlan addr1" },
144 // { "wlan", "wlan addr2" },
145 // { "wlan", "wlan addr3" },
146 // { "wlan", "wlan addr4" },
150 { "ip.addr", "ip host" },
151 { "ip.dst", "ip dst" },
152 { "ip.src", "ip src" },
153 { "ip.proto", "ip proto" },
155 { "sctp.port", "sctp port" },
156 { "sctp.dstport", "sctp dst port" },
157 { "sctp.srcport", "sctp src port" },
159 { "tcp.port", "tcp port" },
160 { "tcp.dstport", "tcp dst port" },
161 { "tcp.srcport", "tcp src port" },
163 { "udp.port", "udp port" },
164 { "udp.dstport", "udp dst port" },
165 { "udp.srcport", "tcp src port" },
174 { "ipv6.addr", "ip6 host" },
175 { "ipv6.dst", "ip6 dst" },
176 { "ipv6.src", "ip6 src" },
177 { "icmpv6", "icmp6" },
197 { "dec_stp", "stp" },
199 { "netbios", "netbeui" },
202 { "pppoed", "pppoed" },
203 { "pppoes", "pppoes" },
204 { "geneve", "geneve" },
211 // { "", "oamf4ec" },
212 // { "", "oamf4sc" },
217 // { "", "connectmsg" },
218 // { "", "metaconnect" },
222 // NOLINTNEXTLINE(misc-no-recursion)
223 bool pcap_visit_dfilter_node(stnode_t
*node
, stnode_op_t parent_bool_op
, GString
*pcap_filter
)
225 stnode_t
*left
, *right
;
227 if (stnode_type_id(node
) == STTYPE_TEST
) {
228 stnode_op_t op
= STNODE_OP_UNINITIALIZED
;
229 sttype_oper_get(node
, &op
, &left
, &right
);
231 const char *op_str
= stnode_op_to_pcap_filter(op
);
237 if ((op
== STNODE_OP_ANY_EQ
|| op
== STNODE_OP_ALL_NE
) && stnode_type_id(right
) != STTYPE_FVALUE
) {
238 // Don't translate things like "ip.src == ip.dst"
241 bool add_parens
= (op
== STNODE_OP_AND
|| op
== STNODE_OP_OR
) && op
!= parent_bool_op
&& parent_bool_op
!= STNODE_OP_UNINITIALIZED
;
243 g_string_append_c(pcap_filter
, '(');
245 if (!pcap_visit_dfilter_node(left
, op
, pcap_filter
)) {
248 if (strlen(op_str
) > 0) {
249 g_string_append_c(pcap_filter
, ' ');
251 g_string_append_printf(pcap_filter
, "%s ", op_str
);
252 if (!pcap_visit_dfilter_node(right
, op
, pcap_filter
)) {
256 g_string_append_c(pcap_filter
, ')');
260 op
= op
== STNODE_OP_NOT
? op
: parent_bool_op
;
261 if (pcap_filter
->len
> 0) {
262 g_string_append_c(pcap_filter
, ' ');
264 g_string_append_printf(pcap_filter
, "%s ", op_str
);
265 if (!pcap_visit_dfilter_node(left
, op
, pcap_filter
)) {
270 ws_assert_not_reached();
273 else if (stnode_type_id(node
) == STTYPE_SET
) {
276 else if (stnode_type_id(node
) == STTYPE_FUNCTION
) {
279 else if (stnode_type_id(node
) == STTYPE_FIELD
) {
280 header_field_info
*hfinfo
= sttype_field_hfinfo(node
);
281 const char *pcap_fragment
= try_str_to_str(hfinfo
->abbrev
, abbrev_to_pcap_filter
);
282 if (!pcap_fragment
) {
285 g_string_append_printf(pcap_filter
, "%s", pcap_fragment
);
287 else if (stnode_type_id(node
) == STTYPE_FVALUE
) {
288 g_string_append_printf(pcap_filter
, "%s", stnode_tostr(node
, true));
291 g_string_append_printf(pcap_filter
, "%s", stnode_type_name(node
));
297 bool dfilter_to_pcap_filter(stnode_t
*root_node
, GString
*pcap_filter
) {
298 return pcap_visit_dfilter_node(root_node
, STNODE_OP_UNINITIALIZED
, pcap_filter
);
301 void dfilter_translator_init(void)
303 register_dfilter_translator("pcap filter", dfilter_to_pcap_filter
);
306 void dfilter_translator_cleanup(void)
308 char **df_translators
= get_dfilter_translator_list();
310 if (df_translators
== NULL
) {
314 for (size_t idx
= 0; df_translators
[idx
]; idx
++) {
315 deregister_dfilter_translator(df_translators
[idx
]);
318 g_free(df_translators
);
322 * Editor modelines - https://www.wireshark.org/tools/modelines.html
327 * indent-tabs-mode: nil
330 * vi: set shiftwidth=4 tabstop=8 expandtab:
331 * :indentSize=4:tabSize=8:noTabs=true: