import socket
import os
import struct
import sys
from ctypes import *
# host to listen on
host = sys.argv[1]
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_ulong),
("dst", c_ulong)
]
def __new__(self, socket_buffer=None):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer=None):
# map protocol constants to their names
self.protocol_map = {1:"ICMP", 6:"TCP", 17:"UDP"}
# human readable IP addresses
self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst))
# human readable protocol
try:
self.protocol = self.protocol_map[self.protocol_num]
except:
self.protocol = str(self.protocol_num)
# create a raw socket and bind it to the public interface
if os.name == "nt":
socket_protocol = socket.IPPROTO_IP
else:
socket_protocol = socket.IPPROTO_ICMP
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
# we want the IP headers included in the capture
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# if we're on Windows we need to send some ioctls
# to setup promiscuous mode
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
try:
while True:
# read in a single packet
raw_buffer = sniffer.recvfrom(65565)[0]
# create an IP header from the first 20 bytes of the buffer
ip_header = IP(raw_buffer[0:20])
print "Protocol: %s %s -> %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address)
except KeyboardInterrupt:
# if we're on Windows turn off promiscuous mode
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
Это код из книги Black Hat Python. Этот код должен обнюхать с сырыми сокетами и отображать информацию из IP-заголовка. Он отлично работает для меня в Windows (с использованием Windows 8.1 64 бит). Когда я пытаюсь запустить это на linux (Kali linux 1.1.0-amd64), я получаю следующую ошибку:
ValueError: Buffer size too small (20 instead of at least 32 bytes)
Чтобы обойти это, я добавил 12 пробелов в буфер, как этот
ip_header = IP(raw_buffer[0:20]+' '*12)
Когда я делаю это, я получаю следующую ошибку
struct.error: 'L' format requires 0 <= number <= 4294967295
Это происходит на линии
self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
Я попытался изменить символ до L до > и! и я попробовал это с помощью L, все они дают мне ту же проблему. Я также попытался обернуть self.src в ntohs, как это сделать
self.src_address = socket.inet_ntoa(struct.pack("<L",socket.ntohs(self.src)))
Я думаю, что это имеет какое-то отношение к контенту, но я не уверен. Любая помощь будет принята с благодарностью.
ПРИМЕЧАНИЕ. В окнах вы должны запускаться как администратор, а на Linux вы должны запускаться как суперпользователь из-за сырых сокетов. Если вы запустите это на linux, откройте еще один терминал и выполните ping www.google.com, чтобы вы могли генерировать некоторые ICMP-пакеты для его захвата.
EDIT: Я также попытался перевернуть буфер с помощью
ip_header = IP(raw_buffer[0:20][::-1]+' '*12)
РЕДАКТИРОВАТЬ 2: Я попытался выполнить как 65535, так и 65534 в строке ниже, прежде чем выполнять какие-либо другие пункты, перечисленные здесь.
raw_buffer = sniffer.recvfrom(65565)[0]
EDIT 3: Это работало на машине ubuntu с запуском python 2.7.6, а мой дистрибутив kali был 2.7.3, поэтому я решил получить последнюю версию python на моем ящике kali, который, как оказалось, равен 2.7.9. Еще не повезло.
Я поместил следующий код в функцию new в моей структуре, чтобы просмотреть размер буфера
print sizeof(self)
На моих машинах Ubuntu и windows это было 20, однако на моей машине Kali это было 32