2012-11-07 1 views
1

ctype을 통해 libpcap을 사용하여 C에서 Python으로 스니퍼를 이식 중입니다. 다음은 파이썬 코드입니다.ctypes를 통해 pcap을 사용하는 파이썬 분할 오류

import ctypes, sys 
from ctypes.util import find_library 

if sys.platform == "darwin": 
    _pcap = ctypes.cdll.LoadLibrary(find_library("libpcap")) 
elif sys.platform == "linux2": 
    _pcap = ctypes.cdll.LoadLibrary("libpcap.so") 

errbuf = ctypes.create_string_buffer(256) 

pcap_lookupdev = _pcap.pcap_lookupdev 
pcap_lookupdev.restype = ctypes.c_char_p 
dev = pcap_lookupdev(errbuf) 
print dev 

# create handler 
pcap_create = _pcap.pcap_create 
handle = pcap_create(dev, errbuf) 
print handle 
if not handle: 
    print "failed creating handler:",errbuf 
    exit() 

# monitor mode 
pcap_can_set_rfmon = _pcap.pcap_can_set_rfmon 
print "can rfmon:",pcap_can_set_rfmon(handle) 

리눅스에서는 완벽하게 작동하지만 Mac OS X에서는 핸들을 사용할 때 세그먼트 화 오류가 발생합니다. handle의 값은 때로는 음수이고 때로는 양수입니다. 이미 pcap_create의 반환 유형을 부호없는 int로 변경하려고 시도했지만 도움이되지 않았지만 OS X에서 잘못된 유형을 반환한다고 생각합니다.

두 시스템에서 모두 printf("size of pcap_t: %zu\n", sizeof(pcap_t *)); pcap_t 핸들러 유형의 크기. 리눅스에서는 4와 OS X 8을 말합니다. 그러나이 시점에서 어떻게 진행해야할지 모르겠습니다 ...

아니면 잘못된 경로에 있습니까? 누구나 아이디어가 있습니까?

+0

은 당신의 파이썬은 32 또는 64 비트를 설치합니까? libpcap은 Mac에서는 64 비트이고 Linux에서는 32 비트와 같습니다. int가 올바르게 매핑되지 않았을 수 있습니까? –

+0

네, sys.maxsize> 2 ** 32, Mac의 경우 64 비트, Linux의 경우 32로 확인했습니다. 그러나 어떻게 처리해야 하는가. 그 장군을 만드는 방법? 32 비트와 64 비트 시스템에서 모두 실행해야합니다. – Cravid

+0

libpcap은 OS X에서 64 비트가 아니며 32 비트 * 및 * 64 비트입니다. OS X은 "fat binaries"를 지원하고 libpcap 공유 라이브러리는 fat binary입니다. 최소한 Mountain Lion에서는'/ usr/bin/python'도 너무 뚱뚱하기 때문에 32 비트 *와 * 64 비트이기도합니다. user1758827은 64 비트 시스템에 있으므로 64 비트 버전의 Python과 libpcap을 모두 사용해야합니다. –

답변

1

데이터 유형이 중요합니다.

pcap_create()의 리턴 값이 포인터임을 ctypes에 알려야하고, pcap_can_set_rfmon()에 대한 인수가 포인터임을 알릴 필요가 있습니다.

당신은

# create handler 
pcap_create = _pcap.pcap_create 
pcap_create.restype = ctypes.c_void_p 
handle = pcap_create(dev, errbuf) 
print handle 
if not handle: 
    print "failed creating handler:",errbuf 
    exit() 

# monitor mode 
pcap_can_set_rfmon = _pcap.pcap_can_set_rfmon 
pcap_can_set_rfmon.argtypes = [ctypes.c_void_p] 
print "can rfmon:",pcap_can_set_rfmon(handle) 

pcap_create.restype = ctypes.c_void_p 

pcap_can_set_rfmon.argtypes = [ctypes.c_void_p] 

여기에 필요한 라인을 수행하여이 작업을 수행. 이 코드는 32 비트 및 64 비트 포인터에서 모두 사용할 수 있으므로 32 비트 및 64 비트 Linux와 32 비트 및 64 비트 OS X (및 32 비트 및 64 비트 Solaris 및 32 비트 및 64 비트 FreeBSD 및 ... 라이브러리를로드하기 위해 코드를 변경해야하는 경우 - 대부분의 Un * xes 공유 라이브러리에서 이름이 ".so"로 끝나기 때문에 원하지 않는 경우 다른 Un * xes에 find_library을 사용하려면 Linux 코드로 충분할 수 있습니다.

+0

감사합니다. 매우 유용한 답변과 의견입니다 (위). pcap_create의 반환 유형을 c_void_p로 한 번 설정했지만 argtypes를 설정하지 않았으므로 여전히 작동하지 않았습니다. 하지만 지금은 그렇습니다. 다시 한번 감사드립니다. – Cravid

+0

그래, 먼저 반환 형식을 수정하려고 시도했지만 여전히 충돌이 발생 했으므로 argtypes를 수정하려고 시도했습니다.libpcap/WinPcap 용 파이썬 래퍼가 새로운'pcap_create()'/'pcap_activate()'기반의 API를 지원하는지는 모르겠다. 그것들에 대한 문서는 그다지 좋은 것은 아니지만, 파이썬에서 libpcap/WinPcap을 사용하는 가장 좋은 방법 일 것입니다. –

0

OS X에서도이 문제를 겪고 있었기 때문에 정말 여기에 올 때가되었습니다. 난 당신의 코드로 발견 된 문제는 다음과 같습니다

handle = pcap_create(dev, errbuf)

당신은 restype을 설정해야합니다, 여기이 길 아래에 당신의 몇 가지 도움이 될 나의 예입니다 https://github.com/killswitch-GUI/NIX-Sniffer-Examples

import ctypes 
    import threading 
    import sys 
    import os 
    import errno 


    OSX_PCAP_DYLIB = '/usr/lib/libpcap.A.dylib' 
    OSX_LIBC_DYLIB = '/usr/lib/libSystem.B.dylib' 
    PCAP_ERRBUF_SIZE = 256 
    packet_count_limit = ctypes.c_int(1) 
    timeout_limit = ctypes.c_int(1000) # In milliseconds 
    err_buf = ctypes.create_string_buffer(PCAP_ERRBUF_SIZE) 

    class bpf_program(ctypes.Structure): 
     _fields_ = [("bf_len", ctypes.c_int),("bf_insns", ctypes.c_void_p)] 

    class pcap_pkthdr(ctypes.Structure): 
     _fields_ = [("tv_sec", ctypes.c_long), ("tv_usec", ctypes.c_long), ("caplen", ctypes.c_uint), ("len", ctypes.c_uint)] 

    class pcap_stat(ctypes.Structure): 
     _fields_ = [("ps_recv",ctypes.c_uint), ("ps_drop",ctypes.c_uint), ("ps_ifdrop", ctypes.c_int)] 

    def pkthandler(pkthdr,packet): 
     print("In callback:") 
     print("pkthdr[0:7]:",pkthdr.contents.len) 
     print(pkthdr.contents.tv_sec,pkthdr.contents.caplen,pkthdr.contents.len) 
     print(packet.contents[:10]) 
     print() 

    print "-------------------------------------------" 
    libc = ctypes.CDLL(OSX_LIBC_DYLIB, use_errno=True) 
    if not libc: 
     print "Error loading C libary: %s" % errno.errorcode[ctypes.get_errno()] 
    print "* C runtime libary loaded: %s" % OSX_LIBC_DYLIB 
    pcap = ctypes.CDLL(OSX_PCAP_DYLIB, use_errno=True) 
    if not pcap: 
     print "Error loading C libary: %s" % errno.errorcode[ctypes.get_errno()] 
    print "* C runtime libary loaded: %s" % OSX_PCAP_DYLIB 
    print "* C runtime handle at: %s" % pcap 

    print "-------------------------------------------" 
    pcap_lookupdev = pcap.pcap_lookupdev 
    pcap_lookupdev.restype = ctypes.c_char_p 
    dev = pcap.pcap_lookupdev() 
    print "* Device handle at: %s" % dev 

    net = ctypes.c_uint() 
    mask = ctypes.c_uint() 
    pcap.pcap_lookupnet(dev,ctypes.byref(net),ctypes.byref(mask),err_buf) 
    print "* Device IP to bind: %s" % net 
    print "* Device net mask: %s" % mask 

    #pcap_t *pcap_open_live(const char *device, int snaplen,int promisc, int to_ms, char *errbuf) 
    pcap_open_live = pcap.pcap_open_live 
    pcap_open_live.restype = ctypes.POINTER(ctypes.c_void_p) 
    pcap_create = pcap.pcap_create 
    pcap_create.restype = ctypes.c_void_p 
    #pcap_handle = pcap.pcap_create(dev, err_buf) 
    pcap_handle = pcap.pcap_open_live(dev, 1024, packet_count_limit, timeout_limit, err_buf) 
    print "* Live capture device handle at: %s" % pcap_handle 

    pcap_can_set_rfmon = pcap.pcap_can_set_rfmon 
    pcap_can_set_rfmon.argtypes = [ctypes.c_void_p] 
    if (pcap_can_set_rfmon(pcap_handle) == 1): 
     print "* Can set interface in monitor mode" 

    pcap_pkthdr_p = ctypes.POINTER(pcap_pkthdr)() 
    packetdata = ctypes.POINTER(ctypes.c_ubyte*65536)() 
    #print pcap.pcap_next(pcap_handle,ctypes.byref(pcap_pkthdr_p)) 

    if (pcap.pcap_next_ex(pcap_handle, ctypes.byref(pcap_pkthdr_p), ctypes.byref(packetdata)) == 1): 
     print "* Packet captured!" 
     pkthandler(pcap_pkthdr_p,packetdata)