Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-logcat-text.c
bloba0e01b7cd8ff52c8c64e4f754bebc7c754cb31a1
1 /* packet-logcat-text.c
2 * Routines for Android Logcat text formats
4 * Copyright 2014, Michal Orynicz for Tieto Corporation
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "config.h"
15 #include <stdio.h> /* for sscanf() */
17 #include "epan/packet.h"
18 #include "epan/expert.h"
19 #include "epan/exported_pdu.h"
20 #include "epan/tap.h"
21 #include "wiretap/logcat_text.h"
23 extern const value_string priority_vals[];
25 static int proto_logcat_text;
27 static int hf_logcat_text_pid;
28 static int hf_logcat_text_tid;
29 static int hf_logcat_text_timestamp;
30 static int hf_logcat_text_priority;
31 static int hf_logcat_text_tag;
32 static int hf_logcat_text_log;
34 static int ett_logcat;
36 static expert_field ei_malformed_time;
37 static expert_field ei_malformed_token;
39 static dissector_handle_t logcat_text_brief_handle;
40 static dissector_handle_t logcat_text_tag_handle;
41 static dissector_handle_t logcat_text_process_handle;
42 static dissector_handle_t logcat_text_time_handle;
43 static dissector_handle_t logcat_text_thread_handle;
44 static dissector_handle_t logcat_text_threadtime_handle;
45 static dissector_handle_t logcat_text_long_handle;
47 static int exported_pdu_tap = -1;
49 static GRegex *special_regex;
50 static GRegex *brief_regex;
51 static GRegex *tag_regex;
52 static GRegex *time_regex;
53 static GRegex *process_regex;
54 static GRegex *thread_regex;
55 static GRegex *threadtime_regex;
56 static GRegex *long_regex;
58 static const char dissector_name[] = "Logcat Text";
60 typedef int (*tGETTER) (const char *frame, const char *token, tvbuff_t *tvb,
61 proto_tree *maintree, int start_offset, packet_info *pinfo);
63 typedef struct {
64 GRegex **regex;
65 const tGETTER *getters;
66 unsigned no_of_getters;
67 } dissect_info_t;
69 void proto_register_logcat_text(void);
70 void proto_reg_handoff_logcat_text(void);
72 static int get_priority(const char *frame, const char *token, tvbuff_t *tvb,
73 proto_tree *maintree, int start_offset, packet_info *pinfo _U_) {
74 int prio;
75 char *p = g_strstr_len(frame + start_offset, -1, token);
76 int offset = (int)(p - frame);
78 switch (*p) {
79 case 'I':
80 prio = 4;
81 break;
82 case 'V':
83 prio = 2;
84 break;
85 case 'D':
86 prio = 3;
87 break;
88 case 'W':
89 prio = 5;
90 break;
91 case 'E':
92 prio = 6;
93 break;
94 case 'F':
95 prio = 7;
96 break;
97 default:
98 prio = 0;
101 proto_tree_add_uint(maintree, hf_logcat_text_priority, tvb, offset, 1, prio);
102 return offset + 1;
105 static int get_tag(const char *frame, const char *token, tvbuff_t *tvb,
106 proto_tree *maintree, int start_offset, packet_info *pinfo) {
107 char *p = g_strstr_len(frame + start_offset, -1, token);
108 int offset = (int)(p - frame);
109 uint8_t *src_addr = wmem_strdup(pinfo->pool, token);
110 int tok_len = (int)strlen(token);
112 proto_tree_add_string(maintree, hf_logcat_text_tag, tvb, offset, tok_len,
113 token);
114 set_address(&pinfo->src, AT_STRINGZ, tok_len + 1, src_addr);
115 set_address(&pinfo->dst, AT_STRINGZ, sizeof(dissector_name), dissector_name);
116 return offset + tok_len;
119 static int get_ptid(const char *frame, const char *token, tvbuff_t *tvb,
120 proto_tree *maintree, int header_field, int start_offset) {
121 char *p = g_strstr_len(frame + start_offset, -1, token);
122 int offset = (int)(p - frame);
124 proto_tree_add_uint(maintree, header_field, tvb, offset, (int)strlen(token),
125 (uint32_t)g_ascii_strtoull(token, NULL, 10));
126 return offset + (int)strlen(token);
129 static int get_pid(const char *frame, const char *token, tvbuff_t *tvb,
130 proto_tree *maintree, int start_offset, packet_info *pinfo _U_) {
131 return get_ptid(frame, token, tvb, maintree, hf_logcat_text_pid, start_offset);
134 static int get_tid(const char *frame, const char *token, tvbuff_t *tvb,
135 proto_tree *maintree, int start_offset, packet_info *pinfo _U_) {
136 return get_ptid(frame, token, tvb, maintree, hf_logcat_text_tid, start_offset);
139 static int get_log(const char *frame, const char *token, tvbuff_t *tvb,
140 proto_tree *maintree, int start_offset, packet_info *pinfo) {
141 char *p = g_strstr_len(frame + start_offset, -1, token);
142 int offset = (int)(p - frame);
144 proto_tree_add_string(maintree, hf_logcat_text_log, tvb, offset,
145 (int)strlen(token), token);
146 col_add_str(pinfo->cinfo, COL_INFO, token);
147 return offset + (int)strlen(token);
150 static int get_time(const char *frame, const char *token, tvbuff_t *tvb,
151 proto_tree *maintree, int start_offset, packet_info *pinfo) {
152 int offset;
153 char *p;
154 int ms;
155 struct tm date;
156 time_t seconds;
157 nstime_t ts;
159 p = g_strstr_len(frame + start_offset, -1, token);
160 offset = (int)(p - frame);
162 if (6 == sscanf(token, "%d-%d %d:%d:%d.%d", &date.tm_mon, &date.tm_mday,
163 &date.tm_hour, &date.tm_min, &date.tm_sec, &ms)) {
164 date.tm_year = 70;
165 date.tm_mon -= 1;
166 date.tm_isdst = -1;
167 seconds = mktime(&date);
168 ts.secs = seconds;
169 ts.nsecs = (int) (ms * 1e6);
170 proto_tree_add_time(maintree, hf_logcat_text_timestamp, tvb, offset,
171 (int)strlen(token), &ts);
172 } else {
173 proto_tree_add_expert(maintree, pinfo, &ei_malformed_time, tvb, offset, -1);
175 return offset + (int)strlen(token);
178 static int dissect_logcat_text(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo,
179 const dissect_info_t *dinfo) {
180 char **tokens;
181 unsigned i;
182 char *frame = tvb_get_string_enc(pinfo->pool, tvb, 0, tvb_captured_length(tvb),
183 ENC_UTF_8);
184 proto_item *mainitem = proto_tree_add_item(tree, proto_logcat_text, tvb, 0, -1, ENC_NA);
185 proto_tree *maintree = proto_item_add_subtree(mainitem, ett_logcat);
186 int offset = 0;
188 col_set_str(pinfo->cinfo, COL_PROTOCOL, dissector_name);
190 if (!g_regex_match(special_regex, frame, G_REGEX_MATCH_NOTEMPTY, NULL)) {
192 tokens = g_regex_split(*dinfo->regex, frame, G_REGEX_MATCH_NOTEMPTY);
193 if (NULL == tokens) return 0;
194 if (g_strv_length(tokens) != dinfo->no_of_getters + 2) {
195 proto_tree_add_expert(maintree, pinfo, &ei_malformed_token, tvb, offset, -1);
196 g_strfreev(tokens);
197 return 0;
200 for (i = 0; i < dinfo->no_of_getters; ++i) {
201 offset = ((*dinfo->getters[i])(frame, tokens[i + 1], tvb, maintree, offset, pinfo));
203 } else {
204 tokens = g_regex_split(special_regex, frame, G_REGEX_MATCH_NOTEMPTY);
205 if (NULL == tokens) return 0;
206 offset = get_log(frame, tokens[1], tvb, maintree, 0, pinfo);
208 g_strfreev(tokens);
209 return offset;
212 static void add_exported_pdu(tvbuff_t *tvb, packet_info *pinfo, const char * subdissector_name){
213 if (have_tap_listener(exported_pdu_tap)) {
214 exp_pdu_data_t *exp_pdu_data;
216 exp_pdu_data = export_pdu_create_tags(pinfo, subdissector_name, EXP_PDU_TAG_DISSECTOR_NAME, NULL);
218 exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb);
219 exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb);
220 exp_pdu_data->pdu_tvb = tvb;
221 tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
225 static int dissect_logcat_text_brief(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
226 void *data _U_) {
227 static const tGETTER getters[] = { get_priority, get_tag, get_pid, get_log };
228 dissect_info_t dinfo = { &brief_regex, getters, array_length(getters) };
230 add_exported_pdu(tvb,pinfo,"logcat_text_brief");
231 return dissect_logcat_text(tvb, tree, pinfo, &dinfo);
234 static int dissect_logcat_text_tag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
235 void *data _U_) {
236 static const tGETTER getters[] = { get_priority, get_tag, get_log };
237 dissect_info_t dinfo = { &tag_regex, getters, array_length(getters) };
239 add_exported_pdu(tvb,pinfo,"logcat_text_tag");
240 return dissect_logcat_text(tvb, tree, pinfo, &dinfo);
243 static int dissect_logcat_text_process(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
244 void *data _U_) {
245 static const tGETTER getters[] = { get_priority, get_pid, get_log };
246 dissect_info_t dinfo = { &process_regex, getters, array_length(getters) };
248 add_exported_pdu(tvb,pinfo,"logcat_text_process");
249 set_address(&pinfo->dst, AT_STRINGZ, 1, "");
250 set_address(&pinfo->src, AT_STRINGZ, 1, "");
252 return dissect_logcat_text(tvb, tree, pinfo, &dinfo);
255 static int dissect_logcat_text_time(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
256 void *data _U_) {
257 static const tGETTER getters[] = { get_time, get_priority, get_tag, get_pid, get_log };
258 dissect_info_t dinfo = { &time_regex, getters, array_length(getters) };
260 add_exported_pdu(tvb,pinfo,"logcat_text_time");
261 return dissect_logcat_text(tvb, tree, pinfo, &dinfo);
264 static int dissect_logcat_text_thread(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
265 void *data _U_) {
266 static const tGETTER getters[] = { get_priority, get_pid, get_tid, get_log };
267 dissect_info_t dinfo = { &thread_regex, getters, array_length(getters) };
269 add_exported_pdu(tvb,pinfo,"logcat_text_brief");
270 set_address(&pinfo->dst, AT_STRINGZ, 1, "");
271 set_address(&pinfo->src, AT_STRINGZ, 1, "");
273 return dissect_logcat_text(tvb, tree, pinfo, &dinfo);
276 static int dissect_logcat_text_threadtime(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
277 void *data _U_) {
278 static const tGETTER getters[] = { get_time, get_pid, get_tid, get_priority, get_tag, get_log };
279 dissect_info_t dinfo = { &threadtime_regex, getters, array_length(getters) };
281 add_exported_pdu(tvb,pinfo,"logcat_text_threadtime");
282 return dissect_logcat_text(tvb, tree, pinfo, &dinfo);
285 static int dissect_logcat_text_long(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
286 void *data _U_) {
287 static const tGETTER getters[] = { get_time, get_pid, get_tid, get_priority, get_tag, get_log };
288 dissect_info_t dinfo = { &long_regex, getters, array_length(getters) };
290 add_exported_pdu(tvb,pinfo,"logcat_text_long");
291 return dissect_logcat_text(tvb, tree, pinfo, &dinfo);
294 static void logcat_text_init(void)
296 special_regex = g_regex_new(SPECIAL_STRING, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_OPTIMIZE | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY, NULL);
297 brief_regex = g_regex_new(BRIEF_STRING, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_OPTIMIZE | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY, NULL);
298 tag_regex = g_regex_new(TAG_STRING, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_OPTIMIZE | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY, NULL);
299 time_regex = g_regex_new(TIME_STRING, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_OPTIMIZE | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY, NULL);
300 thread_regex = g_regex_new(THREAD_STRING, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_OPTIMIZE | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY, NULL);
301 threadtime_regex = g_regex_new(THREADTIME_STRING, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_OPTIMIZE | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY, NULL);
302 process_regex = g_regex_new(PROCESS_STRING, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_OPTIMIZE | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY, NULL);
303 long_regex = g_regex_new(LONG_STRING, (GRegexCompileFlags)(G_REGEX_MULTILINE | G_REGEX_OPTIMIZE | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY, NULL);
306 static void logcat_text_cleanup(void)
308 g_regex_unref(special_regex);
309 g_regex_unref(brief_regex);
310 g_regex_unref(tag_regex);
311 g_regex_unref(time_regex);
312 g_regex_unref(thread_regex);
313 g_regex_unref(threadtime_regex);
314 g_regex_unref(process_regex);
315 g_regex_unref(long_regex);
318 void proto_register_logcat_text(void) {
319 expert_module_t *expert_module;
320 static hf_register_info hf[] = {
321 { &hf_logcat_text_timestamp,
322 { "Timestamp", "logcat_text.timestamp",
323 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00, NULL, HFILL
326 { &hf_logcat_text_tag,
327 { "Tag", "logcat_text.tag",
328 FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL
331 { &hf_logcat_text_log,
332 { "Log", "logcat_text.log",
333 FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL
336 { &hf_logcat_text_priority,
337 { "Priority", "logcat_text.priority",
338 FT_UINT8, BASE_DEC, VALS(priority_vals), 0x00, NULL, HFILL
341 { &hf_logcat_text_pid,
342 { "PID", "logcat_text.pid",
343 FT_UINT32, BASE_DEC, NULL, 0x00, "Process ID", HFILL
346 { &hf_logcat_text_tid,
347 { "TID", "logcat_text.tid",
348 FT_UINT32, BASE_DEC, NULL, 0x00, "Thread ID", HFILL
353 static ei_register_info ei[] = {
354 { &ei_malformed_time, { "logcat_text.malformed_time", PI_PROTOCOL, PI_ERROR, "Malformed time data", EXPFILL }},
355 { &ei_malformed_token, { "logcat_text.malformed_token", PI_PROTOCOL, PI_ERROR, "Failed to decode one or more tokens", EXPFILL }},
358 static int *ett[] = { &ett_logcat};
360 proto_logcat_text = proto_register_protocol("Android Logcat Text", dissector_name,
361 "logcat_text");
362 proto_register_field_array(proto_logcat_text, hf, array_length(hf));
363 proto_register_subtree_array(ett, array_length(ett));
365 logcat_text_brief_handle = register_dissector("logcat_text_brief",
366 dissect_logcat_text_brief, proto_logcat_text);
367 logcat_text_tag_handle = register_dissector("logcat_text_tag",
368 dissect_logcat_text_tag, proto_logcat_text);
369 logcat_text_time_handle = register_dissector("logcat_text_time",
370 dissect_logcat_text_time, proto_logcat_text);
371 logcat_text_process_handle = register_dissector("logcat_text_process",
372 dissect_logcat_text_process, proto_logcat_text);
373 logcat_text_thread_handle = register_dissector("logcat_text_thread",
374 dissect_logcat_text_thread, proto_logcat_text);
375 logcat_text_threadtime_handle = register_dissector("logcat_text_threadtime",
376 dissect_logcat_text_threadtime, proto_logcat_text);
377 logcat_text_long_handle = register_dissector("logcat_text_long",
378 dissect_logcat_text_long, proto_logcat_text);
380 register_init_routine(logcat_text_init);
381 register_cleanup_routine(logcat_text_cleanup);
383 expert_module = expert_register_protocol(proto_logcat_text);
384 expert_register_field_array(expert_module, ei, array_length(ei));
386 exported_pdu_tap = register_export_pdu_tap("Logcat Text");
389 void proto_reg_handoff_logcat_text(void) {
390 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_BRIEF,
391 logcat_text_brief_handle);
392 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_TAG,
393 logcat_text_tag_handle);
394 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_TIME,
395 logcat_text_time_handle);
396 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_THREAD,
397 logcat_text_thread_handle);
398 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_THREADTIME,
399 logcat_text_threadtime_handle);
400 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_PROCESS,
401 logcat_text_process_handle);
402 dissector_add_uint("wtap_encap", WTAP_ENCAP_LOGCAT_LONG,
403 logcat_text_long_handle);
407 * Editor modelines - https://www.wireshark.org/tools/modelines.html
409 * Local variables:
410 * c-basic-offset: 4
411 * tab-width: 8
412 * indent-tabs-mode: nil
413 * End:
415 * vi: set shiftwidth=4 tabstop=8 expandtab:
416 * :indentSize=4:tabSize=8:noTabs=true: