You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python网络嗅探器无法捕获流量及跨平台适配问题咨询

Hey there, let's break down your two issues and fix the code step by step:

1. Why you can't capture WLAN traffic (only localhost ping works)

There are two critical reasons here:

  • Wrong interface binding: Setting host = "localhost" tells the sniffer to only listen on the loopback interface (lo), not your actual WLAN network card. To capture WLAN traffic, you need to bind to your WLAN adapter's IP address (like 192.168.1.100) or use an empty string '' to listen on all available interfaces.
  • Protocol restriction on Linux: Your code uses IPPROTO_ICMP for Linux, which limits the socket to only capturing ICMP packets (like ping). Windows uses IPPROTO_IP which lets it capture all IP-layer traffic—this is a key cross-platform difference you missed.

2. Why promiscuous mode is only handled on Windows

Windows and Linux have totally different mechanisms to enable traffic capture for all passing packets:

  • On Windows, ioctl(SIO_RCVALL, RCVALL_ON) enables a special "receive all" mode that captures all IP packets passing through the network card, acting like promiscuous mode for IP-layer traffic.
  • On Linux, you need two steps to capture all traffic:
    1. Enable promiscuous mode on the target network interface using setsockopt with the IFF_PROMISC flag.
    2. Linux's raw IPPROTO_IP sockets only capture packets destined for the local machine by default. Enabling promiscuous mode lets it see all packets passing through the adapter (as long as you have root privileges).

The original code didn't implement any Linux-specific promiscuous mode logic, so it couldn't capture non-local traffic there.

Fixed Cross-Platform Code

Here's the adjusted code that works on both Linux and Windows to capture all IP-layer WLAN traffic:

import socket
import os
import struct
from ctypes import *
import fcntl  # Required for Linux interface settings

# Replace with your WLAN adapter's IP, or use '' to listen on all interfaces
host = ''

class IP(Structure):
    _fields_ = [
        ("ihl", c_ubyte, 4),
        ("version", c_ubyte, 4),
        ("tos", c_ubyte),
        ("len", c_ushort),
        ("id", c_ushort),
        ("offset", c_ushort),
        ("ttl", c_ubyte),
        ("protocol_num", c_ubyte),
        ("sum", c_ushort),
        ("src", c_uint),
        ("dst", c_uint),
    ]

    def __new__(self, socket_buffer=None):
        return self.from_buffer_copy(socket_buffer)

    def __init__(self, socket_buffer=None):
        self.protocol_map = {1 : "ICMP", 6 : "TCP", 17 : "UDP"}
        self.src_address = socket.inet_ntoa(struct.pack("<L", self.src))
        self.dst_address = socket.inet_ntoa(struct.pack("<L", self.dst))
        try:
            self.protocol = self.protocol_map[self.protocol_num]
        except:
            self.protocol = str(self.protocol_num)

# Use IPPROTO_IP on both platforms to capture all IP packets
socket_protocol = socket.IPPROTO_IP

try:
    sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
    sniffer.bind((host, 0))
    print("[*] Starting packet capture...")
    sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

    # Handle promiscuous mode per platform
    if os.name == "nt":
        sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
    else:
        # Linux: Enable promiscuous mode on the WLAN interface
        # Replace 'wlan0' with your actual WLAN interface (check with `ip link show`)
        interface = b'wlan0'
        SIOCGIFFLAGS = 0x8913
        SIOCSIFFLAGS = 0x8914
        
        # Get current interface flags
        ifreq = struct.pack('16sH', interface, 0)
        flags = fcntl.ioctl(sniffer.fileno(), SIOCGIFFLAGS, ifreq)
        # Set promiscuous mode flag
        new_flags = struct.unpack('16sH', flags)[1] | 0x100  # IFF_PROMISC
        fcntl.ioctl(sniffer.fileno(), SIOCSIFFLAGS, struct.pack('16sH', interface, new_flags))
        print(f"[*] Enabled promiscuous mode on {interface.decode()}")

    while True:
        raw_buffer = sniffer.recvfrom(65565)[0]
        ip_header = IP(raw_buffer[0:20])
        print(f"Protocol: {ip_header.protocol} {ip_header.src_address} -> {ip_header.dst_address}")

except PermissionError:
    print("\n[*] Error: You need root/administrator privileges to run this!")
except KeyboardInterrupt:
    print("\n[*] Stopping capture and cleaning up...")
    # Disable promiscuous mode on exit
    if os.name == "nt":
        sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
    else:
        interface = b'wlan0'
        SIOCGIFFLAGS = 0x8913
        SIOCSIFFLAGS = 0x8914
        ifreq = struct.pack('16sH', interface, 0)
        flags = fcntl.ioctl(sniffer.fileno(), SIOCGIFFLAGS, ifreq)
        new_flags = struct.unpack('16sH', flags)[1] & ~0x100  # Clear IFF_PROMISC
        fcntl.ioctl(sniffer.fileno(), SIOCSIFFLAGS, struct.pack('16sH', interface, new_flags))
except Exception as err:
    print(f"\n[*] Error: {err}")
    # Cleanup on unexpected error
    if os.name == "nt":
        sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
    else:
        interface = b'wlan0'
        SIOCGIFFLAGS = 0x8913
        SIOCSIFFLAGS = 0x8914
        ifreq = struct.pack('16sH', interface, 0)
        flags = fcntl.ioctl(sniffer.fileno(), SIOCGIFFLAGS, ifreq)
        new_flags = struct.unpack('16sH', flags)[1] & ~0x100
        fcntl.ioctl(sniffer.fileno(), SIOCSIFFLAGS, struct.pack('16sH', interface, new_flags))

Important Notes

  • Permissions: On Linux, run this script with sudo; on Windows, run your terminal as Administrator. Raw sockets require elevated privileges.
  • WLAN Interface: On Linux, replace wlan0 with your actual WLAN interface name (find it with ip link show).
  • Capture Scope: Linux raw sockets still won't capture packets the kernel filters out, but this setup will capture most traffic passing through your WLAN adapter.

内容的提问来源于stack exchange,提问作者user12102400

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 15:17:27