Skip to content
Snippets Groups Projects
Commit 0dfb5bfb authored by n1nj4sec's avatar n1nj4sec Committed by Pierre LALET
Browse files

Windows: use Winpcap, drop DNET dependency

parent 6ac34c68
No related branches found
No related tags found
No related merge requests found
...@@ -16,8 +16,306 @@ from scapy.utils import warning ...@@ -16,8 +16,306 @@ from scapy.utils import warning
from scapy.supersocket import SuperSocket from scapy.supersocket import SuperSocket
from scapy.error import Scapy_Exception from scapy.error import Scapy_Exception
import scapy.arch import scapy.arch
import socket
if conf.use_winpcapy:
#mostly code from https://github.com/phaethon/scapy translated to python2.X
try:
from .winpcapy import *
def winpcapy_get_if_list():
err = create_string_buffer(PCAP_ERRBUF_SIZE)
devs = POINTER(pcap_if_t)()
ret = []
if pcap_findalldevs(byref(devs), err) < 0:
return ret
try:
p = devs
while p:
ret.append(p.contents.name.decode('ascii'))
p = p.contents.next
return ret
finally:
pcap_freealldevs(devs)
except OSError as e:
if conf.interactive:
log_loading.error("Unable to import libpcap library: %s" % e)
conf.use_winpcapy = False
else:
raise
# From BSD net/bpf.h
#BIOCIMMEDIATE=0x80044270
BIOCIMMEDIATE=-2147204496
class PcapTimeoutElapsed(Scapy_Exception):
pass
def get_if_raw_hwaddr(iff):
err = create_string_buffer(PCAP_ERRBUF_SIZE)
devs = POINTER(pcap_if_t)()
ret = "\0\0\0\0\0\0"
if pcap_findalldevs(byref(devs), err) < 0:
return ret
try:
p = devs
while p:
if p.contents.name.endswith(iff):
a = p.contents.addresses
while a:
if hasattr(socket, 'AF_LINK') and a.contents.addr.contents.sa_family == socket.AF_LINK:
ap = a.contents.addr
val = cast(ap, POINTER(sockaddr_dl))
ret = str(val.contents.sdl_data[ val.contents.sdl_nlen : val.contents.sdl_nlen + val.contents.sdl_alen ])
a = a.contents.next
break
p = p.contents.next
return ret
finally:
pcap_freealldevs(devs)
def get_if_raw_addr(iff):
err = create_string_buffer(PCAP_ERRBUF_SIZE)
devs = POINTER(pcap_if_t)()
ret = "\0\0\0\0"
if pcap_findalldevs(byref(devs), err) < 0:
return ret
try:
p = devs
while p:
if p.contents.name.endswith(iff):
a = p.contents.addresses
while a:
if a.contents.addr.contents.sa_family == socket.AF_INET:
ap = a.contents.addr
val = cast(ap, POINTER(sockaddr_in))
#ret = bytes(val.contents.sin_addr[:4])
ret = "".join([chr(x) for x in val.contents.sin_addr[:4]])
a = a.contents.next
break
p = p.contents.next
return ret
finally:
pcap_freealldevs(devs)
get_if_list = winpcapy_get_if_list
def in6_getifaddr():
err = create_string_buffer(PCAP_ERRBUF_SIZE)
devs = POINTER(pcap_if_t)()
ret = []
if pcap_findalldevs(byref(devs), err) < 0:
return ret
try:
p = devs
ret = []
while p:
a = p.contents.addresses
while a:
if a.contents.addr.contents.sa_family == socket.AF_INET6:
ap = a.contents.addr
val = cast(ap, POINTER(sockaddr_in6))
addr = socket.inet_ntop(socket.AF_INET6, str(val.contents.sin6_addr[:]))
scope = scapy.utils6.in6_getscope(addr)
ret.append((addr, scope, p.contents.name.decode('ascii')))
a = a.contents.next
p = p.contents.next
return ret
finally:
pcap_freealldevs(devs)
from ctypes import POINTER, byref, create_string_buffer
class _PcapWrapper_pypcap:
def __init__(self, device, snaplen, promisc, to_ms):
self.errbuf = create_string_buffer(PCAP_ERRBUF_SIZE)
self.iface = create_string_buffer(device)
self.pcap = pcap_open_live(self.iface, snaplen, promisc, to_ms, self.errbuf)
self.header = POINTER(pcap_pkthdr)()
self.pkt_data = POINTER(c_ubyte)()
self.bpf_program = bpf_program()
def next(self):
c = pcap_next_ex(self.pcap, byref(self.header), byref(self.pkt_data))
if not c > 0:
return
ts = self.header.contents.ts.tv_sec
pkt = "".join([ chr(i) for i in self.pkt_data[:self.header.contents.len] ])
#pkt = bytes(self.pkt_data[:self.header.contents.len])
return ts, pkt
def datalink(self):
return pcap_datalink(self.pcap)
def fileno(self):
if sys.platform.startswith("win"):
error("Cannot get selectable PCAP fd on Windows")
return 0
return pcap_get_selectable_fd(self.pcap)
def setfilter(self, f):
filter_exp = create_string_buffer(f)
if pcap_compile(self.pcap, byref(self.bpf_program), filter_exp, 0, -1) == -1:
error("Could not compile filter expression %s" % f)
return False
else:
if pcap_setfilter(self.pcap, byref(self.bpf_program)) == -1:
error("Could not install filter %s" % f)
return False
return True
def setnonblock(self, i):
pcap_setnonblock(self.pcap, i, self.errbuf)
def send(self, x):
pcap_sendpacket(self.pcap, x, len(x))
def close(self):
pcap_close(self.pcap)
open_pcap = lambda *args,**kargs: _PcapWrapper_pypcap(*args,**kargs)
class PcapTimeoutElapsed(Scapy_Exception):
pass
class L2pcapListenSocket(SuperSocket):
desc = "read packets at layer 2 using libpcap"
def __init__(self, iface = None, type = ETH_P_ALL, promisc=None, filter=None):
self.type = type
self.outs = None
self.iface = iface
if iface is None:
iface = conf.iface
if promisc is None:
promisc = conf.sniff_promisc
self.promisc = promisc
self.ins = open_pcap(iface, 1600, self.promisc, 100)
try:
ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1))
except:
pass
if type == ETH_P_ALL: # Do not apply any filter if Ethernet type is given
if conf.except_filter:
if filter:
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
else:
filter = "not (%s)" % conf.except_filter
if filter:
self.ins.setfilter(filter)
def close(self):
self.ins.close()
def recv(self, x=MTU):
ll = self.ins.datalink()
if ll in conf.l2types:
cls = conf.l2types[ll]
else:
cls = conf.default_l2
warning("Unable to guess datalink type (interface=%s linktype=%i). Using %s" % (self.iface, ll, cls.name))
pkt = None
while pkt is None:
pkt = self.ins.next()
if pkt is not None:
ts,pkt = pkt
if scapy.arch.WINDOWS and pkt is None:
raise PcapTimeoutElapsed
try:
pkt = cls(pkt)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
raise
pkt = conf.raw_layer(pkt)
pkt.time = ts
return pkt
def send(self, x):
raise Scapy_Exception("Can't send anything with L2pcapListenSocket")
conf.L2listen = L2pcapListenSocket
class L2pcapSocket(SuperSocket):
desc = "read/write packets at layer 2 using only libpcap"
def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0):
if iface is None:
iface = conf.iface
self.iface = iface
self.ins = open_pcap(iface, 1600, 0, 100)
try:
ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1))
except:
pass
if nofilter:
if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap
filter = "ether proto %i" % type
else:
filter = None
else:
if conf.except_filter:
if filter:
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
else:
filter = "not (%s)" % conf.except_filter
if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap
if filter:
filter = "(ether proto %i) and (%s)" % (type,filter)
else:
filter = "ether proto %i" % type
if filter:
self.ins.setfilter(filter)
def send(self, x):
sx = str(x)
if hasattr(x, "sent_time"):
x.sent_time = time.time()
return self.ins.send(sx)
def recv(self,x=MTU):
ll = self.ins.datalink()
if ll in conf.l2types:
cls = conf.l2types[ll]
else:
cls = conf.default_l2
warning("Unable to guess datalink type (interface=%s linktype=%i). Using %s" % (self.iface, ll, cls.name))
pkt = self.ins.next()
if pkt is not None:
ts,pkt = pkt
if pkt is None:
return
try:
pkt = cls(pkt)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
raise
pkt = conf.raw_layer(pkt)
pkt.time = ts
return pkt
def nonblock_recv(self):
self.ins.setnonblock(1)
p = self.recv(MTU)
self.ins.setnonblock(0)
return p
def close(self):
if hasattr(self, "ins"):
self.ins.close()
if hasattr(self, "outs"):
self.outs.close()
class L3pcapSocket(L2pcapSocket):
#def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0):
# L2pcapSocket.__init__(self, iface, type, filter, nofilter)
def recv(self, x = MTU):
r = L2pcapSocket.recv(self, x)
if r:
return r.payload
else:
return
def send(self, x):
cls = conf.l2types[1]
sx = str(cls()/x)
if hasattr(x, "sent_time"):
x.sent_time = time.time()
return self.ins.send(sx)
conf.L2socket=L2pcapSocket
conf.L3socket=L3pcapSocket
if conf.use_pcap: if conf.use_pcap:
......
...@@ -7,19 +7,33 @@ ...@@ -7,19 +7,33 @@
Customizations needed to support Microsoft Windows. Customizations needed to support Microsoft Windows.
""" """
import os,re,sys,socket,time import os,re,sys,socket,time, itertools
import subprocess as sp
from glob import glob from glob import glob
from scapy.config import conf,ConfClass from scapy.config import conf,ConfClass
from scapy.error import Scapy_Exception,log_loading,log_runtime from scapy.error import Scapy_Exception,log_loading,log_runtime
from scapy.utils import atol, inet_aton, inet_ntoa, PcapReader from scapy.utils import atol, itom, inet_aton, inet_ntoa, PcapReader
from scapy.base_classes import Gen, Net, SetGen from scapy.base_classes import Gen, Net, SetGen
import scapy.plist as plist import scapy.plist as plist
from scapy.sendrecv import debug, srp1 from scapy.sendrecv import debug, srp1
from scapy.layers.l2 import Ether, ARP from scapy.layers.l2 import Ether, ARP
from scapy.data import MTU, ETHER_BROADCAST, ETH_P_ARP from scapy.data import MTU, ETHER_BROADCAST, ETH_P_ARP
conf.use_pcap = 1 conf.use_pcap = False
conf.use_dnet = 1 conf.use_dnet = False
conf.use_winpcapy = True
#hot-patching socket for missing variables on Windows
import socket
if not hasattr(socket, 'IPPROTO_IPIP'):
socket.IPPROTO_IPIP=4
if not hasattr(socket, 'IPPROTO_AH'):
socket.IPPROTO_AH=51
if not hasattr(socket, 'IPPROTO_ESP'):
socket.IPPROTO_ESP=50
from scapy.arch import pcapdnet from scapy.arch import pcapdnet
from scapy.arch.pcapdnet import * from scapy.arch.pcapdnet import *
...@@ -69,119 +83,136 @@ class WinProgPath(ConfClass): ...@@ -69,119 +83,136 @@ class WinProgPath(ConfClass):
conf.prog = WinProgPath() conf.prog = WinProgPath()
import _winreg
class PcapNameNotFoundError(Scapy_Exception): class PcapNameNotFoundError(Scapy_Exception):
pass pass
import platform
def is_interface_valid(iface):
if "guid" in iface and iface["guid"]:
return True
return False
def get_windows_if_list():
if platform.release()=="post2008Server" or platform.release()=="8":
# This works only starting from Windows 8/2012 and up. For older Windows another solution is needed
ps = sp.Popen(['powershell', 'Get-NetAdapter', '|', 'select Name, InterfaceIndex, InterfaceDescription, InterfaceGuid, MacAddress', '|', 'fl'], stdout = sp.PIPE, universal_newlines = True)
else:
ps = sp.Popen(['powershell', 'Get-WmiObject', 'Win32_NetworkAdapter', '|', 'select Name, InterfaceIndex, InterfaceDescription, GUID, MacAddress', '|', 'fl'], stdout = sp.PIPE, universal_newlines = True)
#no solution implemented for xp
stdout, stdin = ps.communicate()
current_interface = None
interface_list = []
for i in stdout.split('\n'):
if not i.strip():
continue
if i.find(':')<0:
continue
name, value = [ j.strip() for j in i.split(':',1) ]
if name == 'Name':
if current_interface and is_interface_valid(current_interface):
interface_list.append(current_interface)
current_interface = {}
current_interface['name'] = value
elif name == 'InterfaceIndex':
current_interface['win_index'] = int(value)
elif name == 'InterfaceDescription':
current_interface['description'] = value
elif name == 'InterfaceGuid':
current_interface['guid'] = value
elif name == 'GUID':
current_interface['guid'] = value
elif name == 'MacAddress':
current_interface['mac'] = ':'.join([ j for j in value.split('-')])
if current_interface and is_interface_valid(current_interface):
interface_list.append(current_interface)
return interface_list
def get_ip_from_name(ifname, v6=False):
ps = sp.Popen(['powershell', 'Get-WmiObject', 'Win32_NetworkAdapterConfiguration', '|', 'select Description, IPAddress', '|', 'fl'], stdout = sp.PIPE, universal_newlines = True)
stdout, stdin = ps.communicate()
selected=False
for i in stdout.split('\n'):
if not i.strip():
continue
if i.find(':')<0:
continue
name, value = [ j.strip() for j in i.split(':',1) ]
if name=="Description" and value.strip()==ifname.strip():
selected=True
elif selected:
if v6:
return value.split(",",1)[1].strip('{}').strip()
else:
return value.split(",",1)[0].strip('{}').strip()
class NetworkInterface(object): class NetworkInterface(object):
"""A network interface of your local host""" """A network interface of your local host"""
def __init__(self, dnetdict=None): def __init__(self, data=None):
self.name = None self.name = None
self.ip = None self.ip = None
self.mac = None self.mac = None
self.pcap_name = None self.pcap_name = None
self.win_name = None self.description = None
self.uuid = None self.data = data
self.dnetdict = dnetdict if data is not None:
if dnetdict is not None: self.update(data)
self.update(dnetdict)
def update(self, dnetdict): def update(self, data):
"""Update info about network interface according to given dnet dictionary""" """Update info about network interface according to given dnet dictionary"""
self.name = dnetdict["name"] self.name = data["name"]
self.description = data['description']
self.win_index = data['win_index']
# Other attributes are optional # Other attributes are optional
self._update_pcapdata()
try: try:
self.ip = socket.inet_ntoa(dnetdict["addr"].ip) self.ip = socket.inet_ntoa(get_if_raw_addr(data['guid']))
except (KeyError, AttributeError, NameError): except (KeyError, AttributeError, NameError):
pass pass
try: try:
self.mac = dnetdict["link_addr"] if not self.ip:
self.ip=get_ip_from_name(data['name'])
except (KeyError, AttributeError, NameError) as e:
print e
try:
self.mac = data['mac']
except KeyError: except KeyError:
pass pass
self._update_pcapdata()
def _update_pcapdata(self): def _update_pcapdata(self):
"""Supplement more info from pypcap and the Windows registry""" for i in winpcapy_get_if_list():
if i.endswith(self.data['guid']):
# XXX: We try eth0 - eth29 by bruteforce and match by IP address, self.pcap_name = i
# because only the IP is available in both pypcap and dnet. return
# This may not work with unorthodox network configurations and is
# slow because we have to walk through the Windows registry.
for n in xrange(30):
guess = "eth%s" % n
win_name = pcapdnet.pcap.ex_name(guess)
if win_name.endswith("}"):
try:
uuid = win_name[win_name.index("{"):win_name.index("}")+1]
keyname = r"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\%s" % uuid
try:
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyname)
except WindowsError:
log_loading.debug("Couldn't open 'HKEY_LOCAL_MACHINE\\%s' (for guessed pcap iface name '%s')." % (keyname, guess))
continue
try:
fixed_ip = _winreg.QueryValueEx(key, "IPAddress")[0][0].encode("utf-8")
except (WindowsError, UnicodeDecodeError, IndexError):
fixed_ip = None
try:
dhcp_ip = _winreg.QueryValueEx(key, "DhcpIPAddress")[0].encode("utf-8")
except (WindowsError, UnicodeDecodeError, IndexError):
dhcp_ip = None
# "0.0.0.0" or None means the value is not set (at least not correctly).
# If both fixed_ip and dhcp_ip are set, fixed_ip takes precedence
if fixed_ip is not None and fixed_ip != "0.0.0.0":
ip = fixed_ip
elif dhcp_ip is not None and dhcp_ip != "0.0.0.0":
ip = dhcp_ip
else:
continue
except IOError:
continue
else:
if ip == self.ip:
self.pcap_name = guess
self.win_name = win_name
self.uuid = uuid
break
else:
raise PcapNameNotFoundError raise PcapNameNotFoundError
def __repr__(self): def __repr__(self):
return "<%s: %s %s %s pcap_name=%s win_name=%s>" % (self.__class__.__name__, return "<%s: %s %s %s pcap_name=%s description=%s>" % (self.__class__.__name__,
self.name, self.ip, self.mac, self.pcap_name, self.win_name) self.name, self.ip, self.mac, repr(self.pcap_name), repr(self.description))
from UserDict import IterableUserDict from UserDict import UserDict
class NetworkInterfaceDict(IterableUserDict): class NetworkInterfaceDict(UserDict):
"""Store information about network interfaces and convert between names""" """Store information about network interfaces and convert between names"""
def load_from_powershell(self):
def load_from_dnet(self): for i in get_windows_if_list():
"""Populate interface table via dnet"""
for i in pcapdnet.dnet.intf():
try: try:
# XXX: Only Ethernet for the moment: localhost is not supported by dnet and pcap interface = NetworkInterface(i)
# We only take interfaces that have an IP address, because the IP self.data[interface.name] = interface
# is used for the mapping between dnet and pcap interface names
# and this significantly improves Scapy's startup performance
if i["name"].startswith("eth") and "addr" in i:
self.data[i["name"]] = NetworkInterface(i)
except (KeyError, PcapNameNotFoundError): except (KeyError, PcapNameNotFoundError):
pass pass
if len(self.data) == 0: if len(self.data) == 0:
log_loading.warning("No match between your pcap and dnet network interfaces found. " log_loading.warning("No match between your pcap and windows network interfaces found. "
"You probably won't be able to send packets. " "You probably won't be able to send packets. "
"Deactivating unneeded interfaces and restarting Scapy might help.") "Deactivating unneeded interfaces and restarting Scapy might help."
"Check your winpcap and powershell installation, and access rights.")
def pcap_name(self, devname): def pcap_name(self, devname):
"""Return pypcap device name for given libdnet/Scapy device name """Return pcap device name for given Windows device name."""
This mapping is necessary because pypcap numbers the devices differently."""
try: try:
pcap_name = self.data[devname].pcap_name pcap_name = self.data[devname].pcap_name
...@@ -191,30 +222,37 @@ class NetworkInterfaceDict(IterableUserDict): ...@@ -191,30 +222,37 @@ class NetworkInterfaceDict(IterableUserDict):
return pcap_name return pcap_name
def devname(self, pcap_name): def devname(self, pcap_name):
"""Return libdnet/Scapy device name for given pypcap device name """Return Windows device name for given pcap device name."""
This mapping is necessary because pypcap numbers the devices differently."""
for devname, iface in self.items(): for devname, iface in self.items():
if iface.pcap_name == pcap_name: if iface.pcap_name == pcap_name:
return iface.name return iface.name
raise ValueError("Unknown pypcap network interface %r" % pcap_name) raise ValueError("Unknown pypcap network interface %r" % pcap_name)
def devname_from_index(self, if_index):
"""Return interface name from interface index"""
for devname, iface in self.items():
if iface.win_index == if_index:
return iface.name
raise ValueError("Unknown network interface index %r" % if_index)
def show(self, resolve_mac=True): def show(self, resolve_mac=True):
"""Print list of available network interfaces in human readable form""" """Print list of available network interfaces in human readable form"""
print "%s %s %s" % ("IFACE".ljust(5), "IP".ljust(15), "MAC") print "%s %s %s %s" % ("INDEX".ljust(5), "IFACE".ljust(35), "IP".ljust(15), "MAC")
for iface_name in sorted(self.data.keys()): for iface_name in sorted(self.data.keys()):
dev = self.data[iface_name] dev = self.data[iface_name]
mac = str(dev.mac) mac = dev.mac
if resolve_mac: if resolve_mac:
mac = conf.manufdb._resolve_MAC(mac) mac = conf.manufdb._resolve_MAC(mac)
print "%s %s %s" % (str(dev.name).ljust(5), str(dev.ip).ljust(15), mac) print "%s %s %s %s" % (str(dev.win_index).ljust(5), str(dev.name).ljust(35), str(dev.ip).ljust(15), mac)
ifaces = NetworkInterfaceDict() ifaces = NetworkInterfaceDict()
ifaces.load_from_dnet() ifaces.load_from_powershell()
def pcap_name(devname): def pcap_name(devname):
"""Return pypcap device name for given libdnet/Scapy device name""" """Return pypcap device name for given libdnet/Scapy device name"""
if type(devname) is NetworkInterface:
return devname.pcap_name
try: try:
pcap_name = ifaces.pcap_name(devname) pcap_name = ifaces.pcap_name(devname)
except ValueError: except ValueError:
...@@ -226,6 +264,10 @@ def devname(pcap_name): ...@@ -226,6 +264,10 @@ def devname(pcap_name):
"""Return libdnet/Scapy device name for given pypcap device name""" """Return libdnet/Scapy device name for given pypcap device name"""
return ifaces.devname(pcap_name) return ifaces.devname(pcap_name)
def devname_from_index(if_index):
"""Return Windows adapter name for given Windows interface index"""
return ifaces.devname_from_index(if_index)
def show_interfaces(resolve_mac=True): def show_interfaces(resolve_mac=True):
"""Print list of available network interfaces""" """Print list of available network interfaces"""
return ifaces.show(resolve_mac) return ifaces.show(resolve_mac)
...@@ -233,86 +275,93 @@ def show_interfaces(resolve_mac=True): ...@@ -233,86 +275,93 @@ def show_interfaces(resolve_mac=True):
_orig_open_pcap = pcapdnet.open_pcap _orig_open_pcap = pcapdnet.open_pcap
pcapdnet.open_pcap = lambda iface,*args,**kargs: _orig_open_pcap(pcap_name(iface),*args,**kargs) pcapdnet.open_pcap = lambda iface,*args,**kargs: _orig_open_pcap(pcap_name(iface),*args,**kargs)
_orig_get_if_raw_hwaddr = pcapdnet.get_if_raw_hwaddr
pcapdnet.get_if_raw_hwaddr = lambda iface,*args,**kargs: (ARPHDR_ETHER,''.join([ chr(int(i, 16)) for i in ifaces[iface].mac.split(':') ]))
get_if_raw_hwaddr = pcapdnet.get_if_raw_hwaddr
def read_routes_7():
routes=[]
ps = sp.Popen(['powershell', 'Get-WmiObject', 'win32_IP4RouteTable', '|', 'select Name,Mask,NextHop,InterfaceIndex', '|', 'fl'], stdout = sp.PIPE, universal_newlines = True)
stdout, stdin = ps.communicate()
dest=None
mask=None
gw=None
ifIndex=None
for i in stdout.split('\n'):
if not i.strip():
continue
if i.find(':')<0:
continue
name, value = [ j.strip().lower() for j in i.split(':',1) ]
if name=="name":
dest=atol(value)
elif name=="mask":
mask=atol(value)
elif name=="nexthop":
gw=value
elif name=="interfaceindex":
ifIndex=value
try:
iface = devname_from_index(int(ifIndex))
except ValueError:
continue
addr = ifaces[iface].ip
routes.append((dest, mask, gw, iface, addr))
return routes
def read_routes(): def read_routes():
ok = 0
routes=[] routes=[]
ip = '(\d+\.\d+\.\d+\.\d+)' try:
# On Vista and Windows 7 the gateway can be IP or 'On-link'. if platform.release()=="post2008Server" or platform.release()=="8":
# But the exact 'On-link' string depends on the locale, so we allow any text. routes=read_routes_post2008()
gw_pattern = '(.+)' else:
routes=read_routes_7()
except Exception as e:
log_loading.warning("Error building scapy routing table : %s"%str(e))
else:
if not routes:
log_loading.warning("No default IPv4 routes found. Your Windows release may no be supported and you have to enter your routes manually")
return routes
def read_routes_post2008():
routes = []
if_index = '(\d+)'
dest = '(\d+\.\d+\.\d+\.\d+)/(\d+)'
next_hop = '(\d+\.\d+\.\d+\.\d+)'
metric_pattern = "(\d+)" metric_pattern = "(\d+)"
delim = "\s+" # The columns are separated by whitespace delim = "\s+" # The columns are separated by whitespace
netstat_line = delim.join([ip, ip, gw_pattern, ip, metric_pattern]) netstat_line = delim.join([if_index, dest, next_hop, metric_pattern])
pattern = re.compile(netstat_line) pattern = re.compile(netstat_line)
f=os.popen("netstat -rn") # This works only starting from Windows 8/2012 and up. For older Windows another solution is needed
for l in f.readlines(): ps = sp.Popen(['powershell', 'Get-NetRoute', '-AddressFamily IPV4', '|', 'select ifIndex, DestinationPrefix, NextHop, RouteMetric'], stdout = sp.PIPE, universal_newlines = True)
stdout, stdin = ps.communicate()
for l in stdout.split('\n'):
match = re.search(pattern,l) match = re.search(pattern,l)
if match: if match:
dest = match.group(1)
mask = match.group(2)
gw = match.group(3)
netif = match.group(4)
metric = match.group(5)
try: try:
intf = pcapdnet.dnet.intf().get_dst(pcapdnet.dnet.addr(type=2, addrtxt=dest)) iface = devname_from_index(int(match.group(1)))
except OSError: addr = ifaces[iface].ip
log_loading.warning("Building Scapy's routing table: Couldn't get outgoing interface for destination %s" % dest) except:
continue continue
if not intf.has_key("addr"): dest = atol(match.group(2))
break mask = itom(int(match.group(3)))
addr = str(intf["addr"]) gw = match.group(4)
addr = addr.split("/")[0] # try:
# intf = pcapdnet.dnet.intf().get_dst(pcapdnet.dnet.addr(type=2, addrtxt=dest))
dest = atol(dest) # except OSError:
mask = atol(mask) # log_loading.warning("Building Scapy's routing table: Couldn't get outgoing interface for destination %s" % dest)
# If the gateway is no IP we assume it's on-link # continue
gw_ipmatch = re.search('\d+\.\d+\.\d+\.\d+', gw) routes.append((dest, mask, gw, iface, addr))
if gw_ipmatch:
gw = gw_ipmatch.group(0)
else:
gw = netif
routes.append((dest,mask,gw, str(intf["name"]), addr))
f.close()
return routes return routes
def read_routes6(): def read_routes6():
return [] return []
def getmacbyip(ip, chainCC=0): if conf.interactive_shell != 'ipython':
"""Return MAC address corresponding to a given IP address""" try:
if isinstance(ip,Net): __IPYTHON__
ip = iter(ip).next() except NameError:
tmp = map(ord, inet_aton(ip))
if (tmp[0] & 0xf0) == 0xe0: # mcast @
return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])
iff,a,gw = conf.route.route(ip)
if ( (iff == LOOPBACK_NAME) or (ip == conf.route.get_if_bcast(iff)) ):
return "ff:ff:ff:ff:ff:ff"
# Windows uses local IP instead of 0.0.0.0 to represent locally reachable addresses
ifip = str(pcapdnet.dnet.intf().get(iff)['addr'])
if gw != ifip.split('/')[0]:
ip = gw
mac = conf.netcache.arp_cache.get(ip)
if mac:
return mac
res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip),
type=ETH_P_ARP,
iface = iff,
timeout=2,
verbose=0,
chainCC=chainCC,
nofilter=1)
if res is not None:
mac = res.payload.hwsrc
conf.netcache.arp_cache[ip] = mac
return mac
return None
import scapy.layers.l2
scapy.layers.l2.getmacbyip = getmacbyip
try: try:
import readline import readline
console = readline.GetOutputFile() console = readline.GetOutputFile()
...@@ -323,10 +372,6 @@ else: ...@@ -323,10 +372,6 @@ else:
orig_stdout = sys.stdout orig_stdout = sys.stdout
sys.stdout = console sys.stdout = console
def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, multi=0): def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, multi=0):
if not isinstance(pkt, Gen): if not isinstance(pkt, Gen):
pkt = SetGen(pkt) pkt = SetGen(pkt)
...@@ -395,7 +440,6 @@ def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, m ...@@ -395,7 +440,6 @@ def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, m
else: else:
stoptime = 0 stoptime = 0
remaintime = None remaintime = None
inmask = [pks.ins.fd]
try: try:
try: try:
while 1: while 1:
...@@ -442,9 +486,9 @@ def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, m ...@@ -442,9 +486,9 @@ def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, m
finally: finally:
pass pass
remain = reduce(list.__add__, hsent.values(), []) remain = list(itertools.chain(*[ i for i in hsent.values() ]))
if multi: if multi:
remain = filter(lambda p: not hasattr(p, '_answered'), remain); remain = [ p for p in remain if not hasattr(p, '_answered')]
if autostop and len(remain) > 0 and len(remain) != len(tobesent): if autostop and len(remain) > 0 and len(remain) != len(tobesent):
retry = autostop retry = autostop
...@@ -475,7 +519,7 @@ scapy.sendrecv.sndrcv = sndrcv ...@@ -475,7 +519,7 @@ scapy.sendrecv.sndrcv = sndrcv
def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, *arg, **karg): def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, *arg, **karg):
"""Sniff packets """Sniff packets
sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets
Select interface to sniff by setting conf.iface. Use show_interfaces() to see interface names.
count: number of packets to capture. 0 means infinity count: number of packets to capture. 0 means infinity
store: wether to store sniffed packets or discard them store: wether to store sniffed packets or discard them
prn: function to apply to each packet. If something is returned, prn: function to apply to each packet. If something is returned,
...@@ -491,6 +535,7 @@ L2socket: use the provided L2socket ...@@ -491,6 +535,7 @@ L2socket: use the provided L2socket
c = 0 c = 0
if offline is None: if offline is None:
log_runtime.info('Sniffing on %s' % conf.iface)
if L2socket is None: if L2socket is None:
L2socket = conf.L2listen L2socket = conf.L2listen
s = L2socket(type=ETH_P_ALL, *arg, **karg) s = L2socket(type=ETH_P_ALL, *arg, **karg)
...@@ -533,11 +578,17 @@ L2socket: use the provided L2socket ...@@ -533,11 +578,17 @@ L2socket: use the provided L2socket
import scapy.sendrecv import scapy.sendrecv
scapy.sendrecv.sniff = sniff scapy.sendrecv.sniff = sniff
def get_if_list():
return sorted(ifaces.keys())
def get_working_if(): def get_working_if():
try: try:
return devname(pcap.lookupdev()) if 'Ethernet' in ifaces and ifaces['Ethernet'].ip != '0.0.0.0':
except Exception: return 'Ethernet'
return 'lo0' elif 'Wi-Fi' in ifaces and ifaces['Wi-Fi'].ip != '0.0.0.0':
return 'Wi-Fi'
elif len(ifaces) > 0:
return ifaces[list(ifaces.keys())[0]]
else:
return LOOPBACK_NAME
except:
return LOOPBACK_NAME
conf.iface = get_working_if()
...@@ -360,6 +360,7 @@ extensions_paths: path or list of paths where extensions are to be looked for ...@@ -360,6 +360,7 @@ extensions_paths: path or list of paths where extensions are to be looked for
emph = Emphasize() emph = Emphasize()
use_pcap = False use_pcap = False
use_dnet = False use_dnet = False
use_winpcapy = False
ipv6_enabled = socket.has_ipv6 ipv6_enabled = socket.has_ipv6
ethertypes = ETHER_TYPES ethertypes = ETHER_TYPES
protocols = IP_PROTOS protocols = IP_PROTOS
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment