Skip to content

fix #1190 support to display packet content as UTF-8 - #1382

Open
lotabout wants to merge 3 commits into
the-tcpdump-group:masterfrom
lotabout:feat/support-utf8
Open

fix #1190 support to display packet content as UTF-8#1382
lotabout wants to merge 3 commits into
the-tcpdump-group:masterfrom
lotabout:feat/support-utf8

Conversation

@lotabout

@lotabout lotabout commented Nov 2, 2025

Copy link
Copy Markdown

This PR adds a new --utf8 option to enable UTF-8 character support.

When UTF-8 support is enabled, tcpdump will detect and display UTF-8 characters in the payload as-is when using the -A option.
Note that in -X mode, if a multi-byte character spans across two lines, it will appear on the first line, and a spaces will be padded on the next line.

Tests

  • Verified with several random PCAP files dumped using -A and -x, ensuring their MD5 checksums remain identical without --utf8.
  • Manually tested using a UTF-8 sample PCAP on macOS.

utf8.pcap.zip

@lotabout lotabout changed the title fix #1190 support to display packet content as UTF-8 [Draft] fix #1190 support to display packet content as UTF-8 Nov 2, 2025
@lotabout
lotabout force-pushed the feat/support-utf8 branch 4 times, most recently from 2ecc6b2 to 354fa81 Compare November 2, 2025 16:17
@lotabout lotabout changed the title [Draft] fix #1190 support to display packet content as UTF-8 fix #1190 support to display packet content as UTF-8 Nov 2, 2025
@gvanem

gvanem commented Nov 4, 2025

Copy link
Copy Markdown
Contributor

I tried this on Windows using MSVC and clang-cl. But there is no wcwidth() here:

print-ascii.c(118,11): error: call to undeclared function 'wcwidth'; ISO C99 and later do not support implicit function declarations
      [-Wimplicit-function-declaration]
  118 |                 int w = wcwidth(wc);
      |                         ^

@infrastation

Copy link
Copy Markdown
Member

How did it build in Appveyor then?

@gvanem

gvanem commented Nov 4, 2025

Copy link
Copy Markdown
Contributor

How did it build in Appveyor then?

Since HAVE_WCHAR_T was not detected and used I presume. No diff for CMakeLists.txt AFAICS.

@lotabout

lotabout commented Nov 4, 2025

Copy link
Copy Markdown
Author

@gvanem Could you please help me give it another try on Windows? I’ve added Markus Kuhn’s implementation as a replacement on Windows.

@gvanem

gvanem commented Nov 4, 2025

Copy link
Copy Markdown
Contributor

@lotabout Tried it, but I see a lot of junk with with windump.exe --utf8 -Ar utf8.pcap. Like;
image

I assume your utf8.pcap file is based on this or this which displays better in my TCC shell:

image

@lotabout
lotabout force-pushed the feat/support-utf8 branch 2 times, most recently from 6629672 to a13a471 Compare November 5, 2025 16:37
@lotabout

lotabout commented Nov 5, 2025

Copy link
Copy Markdown
Author

@gvanem Please help to try again with latest code, it turns out that locale should be set correctly for mbrtowc to work properly.

(left: tcpdump, right: cat. Compiled on Windows 11 with VS 2022, Shell: PowerShell with $OutputEncoding = [System.Text.Encoding]::UTF8 set)
image

image

@lotabout lotabout closed this Nov 5, 2025
@infrastation

Copy link
Copy Markdown
Member

tcpdump CI is failing because of my recent changes in libpcap. Please wait until this is fixed.

@lotabout lotabout reopened this Nov 5, 2025
@lotabout

lotabout commented Nov 5, 2025

Copy link
Copy Markdown
Author

tcpdump CI is failing because of my recent changes in libpcap. Please wait until this is fixed.

@infrastation Got it, Thanks~

@gvanem

gvanem commented Nov 5, 2025

Copy link
Copy Markdown
Contributor

Work very well now!

@lotabout
lotabout force-pushed the feat/support-utf8 branch 2 times, most recently from 870f465 to b5f77ca Compare November 10, 2025 02:14
@lotabout

Copy link
Copy Markdown
Author

@fxlb Hi! Sorry for the ping (I saw you're very active here). This is my first PR to this project — is there anything else I should do to help get it merged, apart from passing the CI checks?

@gvanem

gvanem commented Dec 24, 2025

Copy link
Copy Markdown
Contributor

Why is nobody besides me and @lotabout interested in merging this?

Comment thread print-ascii.c Outdated


/*
* The blow is_utf8_printable is taken from ngrep

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably that should be "The below is_utf8_printable is taken from ngrep".

Comment thread print-ascii.c Outdated
}

/* Check if the wide character is printable */
#if defined(_WIN32) || defined(_WIN64)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any compilers for Windows that define _WIN64, but don't define _WIN32, on "modern" Windows? ("modern" here means "not 16-bit Windows".)

Comment thread print-ascii.c Outdated
utf8_len = ndo->ndo_utf8 ? is_utf8_printable(cp, length, NULL) : 0;

if (utf8_len > 0) {
/* Valid printable UTF-8 character */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if utf8_len is greater than length - i.e., you have a partial UTF-8 character?

@guyharris

Copy link
Copy Markdown
Member

The title of the pull request and commit message should probably be just "Add support to display packet content as UTF-8", with "Fix #1190" in the body of the commit message.

@fxlb

fxlb commented Dec 25, 2025

Copy link
Copy Markdown
Member
  1. The UTF8 support in ngrep is very new: First PR (40) on Oct 31, PR 41 merged on Nov 1, so very few tests.
    (Tested with one file, says the author.)
    Comment in PR 41:
    "given all the crazy things UTF-8 can do (e.g. with combining characters)" ...
    [https://github.com/jpr5/ngrep/]

  2. Currently, I think Unicode handling can wait. We have made and continue to make great efforts to make the code more robust. Now is not the time to weaken it. We could look at this change after the 5.0 release.

@infrastation

infrastation commented Dec 26, 2025

Copy link
Copy Markdown
Member

I agree that for this new feature it is more important to implement it safely than quickly. In particular, it should be impossible to weaponise it as is sometimes done using ANSI escape codes, see CVE-2025-46394 for one example. So this requires a bit more attention before it is declared safe and ready.

lotabout and others added 3 commits September 9, 2026 20:25
nd_utf8_glyph() reads one displayable "glyph" from the packet buffer:
a code point encoded as one of the well-formed byte sequences of
Table 3-7 of the Unicode Standard (no overlong forms, surrogates or
values above U+10FFFF), that is a letter, a spacing mark, a digit, a
punctuation character or a symbol, optionally followed by up to two
combining marks.  Everything else (malformed or truncated sequences,
controls, format characters such as bidirectional controls and zero
width characters, separators other than U+0020, private use, unassigned
and Default_Ignorable code points) is rejected and left to the caller
to print as ".".  A glyph is always one or two terminal columns wide,
so the output can carry neither terminal control sequences nor
invisible text.

The classification comes from tables generated by gen-unicode-tables.py
from a pinned Unicode version (currently 16.0.0) rather than from the C
library, so the result does not depend on the locale, on the platform
or on wchar_t, and the same expected output can be used on every
platform in the test suite.  Every byte is read with GET_U_1().

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
--charset=utf-8 makes ascii_print() and hex_and_ascii_print() print
the glyphs accepted by nd_utf8_glyph() as is; the default,
--charset=ascii, keeps the current byte-for-byte output.

In the -X text column each packet byte still corresponds to exactly
one column: a glyph is printed at the position of its first byte,
followed by one filler space per additional byte.  Fillers of a glyph
that spans two lines continue on the next line.  A two-column glyph
that starts at the last position of a line is printed at the start of
the next line instead; a two-column code point is at least three bytes
long in UTF-8, so it always fits there.  Since a filler always
separates two multi-byte glyphs, terminals cannot merge adjacent code
points (ZWJ sequences, emoji modifiers, flags) in the -X column, and the
rendered width equals the computed width.

The hex column is unchanged; the text column of a line is built in a
buffer whose size follows from the per-position bound of one glyph of
ND_UTF8_GLYPH_MAX_BYTES bytes plus one glyph carried over from the
previous line.  No setlocale() is needed; the terminal has to be set to
UTF-8.

Fix the-tcpdump-group#1190

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
utf8.pcap holds UDP payloads covering: 2-, 3- and 4-byte characters;
combining marks (NFD, Thai, Devanagari, a third stacked mark and a mark
without a base); ZWJ, emoji modifier, flag, keycap and tag sequences;
content that must never be emitted (C1 CSI, ESC, RLO, LRI, U+2028,
NBSP, ideographic space, ZWSP, BOM, soft hyphen, private use,
noncharacter, unassigned); malformed UTF-8 (overlong, surrogate,
above U+10FFFF, F5 lead byte, lone continuation byte, sequences
truncated at the end of the packet); every -X line boundary case; and a
capture truncated in the middle of a character.

The -ascii variants check that the default output is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

5 participants