是否可以在 tcpdump 捕获输出中查看 unicode 文本?

是否可以在 tcpdump 捕获输出中查看 unicode 文本?

不幸的是,似乎tcpdump无法检测和显示捕获中的 Unicode 编码文本(特别是 utf-8)。它将 unicode 文本视为常规二进制数据,并以点的形式显示。我需要此功能来调试应用程序。

更具体地说,我在tmuxGnome 终端的远程 ssh 会话中运行 tcpdump 4.3.0。操作系统是 debian 7。

是否可以使用tcpdump它或与其他 Linux 命令组合来查看实时网络捕获中的 unicode 文本?

答案1

下面的 TXR Lisp 程序,调用方法pcap.tl如下:

$ tcpdump -s 1024 -w - | ~/txr/txr pcap.tl

它解析 pcap 格式输出-w并生成如下输出:

192.168.1.102 --> 192.168.1.146
  ether hdr: #S(eth-header dst-mac #(8 0 39 249 113 4) src-mac #(0 30 79 164 102 184) eth-type ETH_IPV4)
  ipv4 hdr:  #S(ipv4-header ihl 5 ver 4 ecn 0 dscp 0 len 101 ident 7434 fragoffs-hi 0 flags 2
               fragoffs-lo 0 ttl 64 proto 6 hdr-sum 39232 src-ip 3232235878
               dst-ip 3232235922)
  ipv4 payload as text: P��.;;�.�+i�.6�...
KK-?9rrt2b
春が来た (Haru-ga Kita/Spring has Com

代码使用 FFI 类型声明来定义与 pcap 文件和数据包格式、以太网标头和 ipv4 标头相对应的结构类型。对于大端和小端机器,ipv4 标头以两种不同的方式定义,因为它依赖于位字段。

我们将整个 IPv4 有效负载作为 UTF-8 数据获取,对其进行解码,用点替换控制字符并打印。

2022 年 5 月 24 日编辑:新代码利用 TXR 276 中的字节序位字段支持。位字段现在可以基于字节序类型,例如be-uint16,因此我们不再需要根据字节序以两种方式声明 IPv4 标头结构主人:

(typedef ll-t (enumed uint32 ll-t
                DLT_NULL DLT_EN10MB))

(typedef eth-t (enumed be-uint16 eth-t
                 (ETH_IPV4 #x0800)
                 (ETH_ARP  #x0806)
                 (ETH_IPV6 #x08DD)))

(typedef pcap-header (struct pcap-header
                       (magic uint32)
                       (majver uint16)
                       (minver uint16)
                       (tzoffs uint32)
                       (tzprec uint32)
                       (snaplen uint32)
                       (lltype ll-t)))

(typedef pkt-header (struct pkt-header
                      (tsec uint32)
                      (tfrac uint32)
                      (trunclen uint32)
                      (origlen uint32)))


(typedef eth-header (struct eth-header
                      (dst-mac (array 6 uint8))
                      (src-mac (array 6 uint8))
                      (eth-type eth-t)))

(typedef ipv4-header (struct ipv4-header
                       (ver (bit 4 be-uint16))
                       (ihl (bit 4 be-uint16))
                       (dscp (bit 6 be-uint16))
                       (ecn (bit 2 be-uint16))
                       (len be-uint16)
                       (ident be-uint16)
                       (flags (bit 3 be-uint16))
                       (fragoffs-hi (bit 5 be-uint16))
                       (fragoffs-lo uint8)
                       (ttl uint8)
                       (proto uint8)
                       (hdr-sum be-uint16)
                       (src-ip be-uint32)
                       (dst-ip be-uint32))))

;; Look for IPv4 packets and print headers
(defun decode-packet (phdr buf)
  (let ((eh (ffi-get buf (ffi eth-header))))
    (unless (eq eh.eth-type 'ETH_IPV4)
      (return-from decode-packet))
    (let* ((ih (ffi-get buf (ffi ipv4-header) (sizeof eth-header)))
           (hdrsz (+ (sizeof eth-header) (sizeof ipv4-header)))
           (len (- (length buf) hdrsz))
           (body (carray-buf buf (ffi char) hdrsz))
           (rawtext (carray-get body))
           (text (mapcar (iffi [andf chr-iscntrl [notf chr-isspace]] (ret #\.))
                         rawtext)))
      (put-line `@(str-inaddr ih.src-ip) --> @(str-inaddr ih.dst-ip)`)
      (put-line `  ether hdr: @eh`)
      (put-line `  ipv4 hdr:  @ih`)
      (put-line `  ipv4 payload as text: @text`))))

;; main program
(let ((*stdin* (open-fileno (fileno *stdin*) "rbu")) ;; binary, unbuffered
      (hdr (new pcap-header))
      (hdr-buf (make-buf (sizeof pcap-header)))
      (phdr (new pkt-header))
      (phdr-buf (make-buf (sizeof pkt-header)))
      (pay-buf (make-buf 65536)))

  ;; read pcap file header
  (when (< (fill-buf hdr-buf) (sizeof pcap-header))
    (return))

  ;; decode to structure
  (ffi-in hdr-buf hdr (ffi pcap-header) t)

  (unless (eq hdr.lltype 'DLT_EN10MB)
    (put-line "can only deal with Ethernet frames")
    (exit nil))

  ;; read and decode packets
  (while t
    (when (< (fill-buf phdr-buf) (sizeof pkt-header))
      (return))
    (ffi-in phdr-buf phdr (ffi pkt-header) t)
    (buf-set-length pay-buf phdr.trunclen)
    (when (< (fill-buf pay-buf) phdr.trunclen)
      (return))
    (decode-packet phdr pay-buf)))

body绑定到carray覆盖在 上的对象buf,位移为hdrsz,以传送以太网和 IPV4 标头。元素类型为char.它占据了标头之后缓冲区的整个剩余部分。

然后(carray-get body)将整个外部值转换为 Lisp 字符串。由于元素类型为char,UTF-8 转换开始: 数组的特殊行为char。如果类型是bchar,它只会将字节视为字符 1:1。如果类型为wchar,则数组将为wchar_t字符,并相应地转换为字符串。要获取数字字节向量而不是字符串,我们可以将元素类型设置为ucharuint8

该程序很容易扩展以处理 TCP、UDP、IPv6,无论需要什么。它可以在特定标头字段上查找特定匹配。

相关内容