Skip to content
Snippets Groups Projects
Commit 1a67eb8a authored by Phil's avatar Phil
Browse files

Created a NetCache and Neighbour object to abstract link layer address resolution

parent 7c79ad9d
Branches
No related tags found
No related merge requests found
......@@ -371,55 +371,3 @@ def get_if_hwaddr(iff):
#####################
## ARP cache stuff ##
#####################
ARPTIMEOUT=120
if 0 and DNET: ## XXX Can't use this because it does not resolve IPs not in cache
dnet_arp_object = dnet.arp()
def getmacbyip(ip, chainCC=0):
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 = config.conf.route.route(ip)
if iff == "lo":
return "ff:ff:ff:ff:ff:ff"
if gw != "0.0.0.0":
ip = gw
res = dnet_arp_object.get(dnet.addr(ip))
if res is None:
return None
else:
return res.ntoa()
else:
def getmacbyip(ip, chainCC=0):
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 = config.conf.route.route(ip)
if ( (iff == "lo") or (ip == config.conf.route.get_if_bcast(iff)) ):
return "ff:ff:ff:ff:ff:ff"
if gw != "0.0.0.0":
ip = gw
if config.conf.arp_cache.has_key(ip):
mac, timeout = config.conf.arp_cache[ip]
if not timeout or (time.time()-timeout < ARPTIMEOUT):
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
config.conf.arp_cache[ip] = (mac,time.time())
return mac
return None
import os
import os,time
from data import *
import base_classes
import arch,themes
......@@ -106,6 +106,65 @@ class LayersList(list):
self.append(layer)
class CacheInstance(dict):
def __init__(self, name="noname", timeout=None):
self.timeout = timeout
self.name = name
self._timetable = {}
def __getitem__(self, item):
val = dict.__getitem__(self,item)
if self.timeout is not None:
t = self._timetable[item]
if time.time()-t > self.timeout:
raise KeyError(item)
return val
def get(self, item, default=None):
try:
return self[item]
except KeyError:
return default
def __setitem__(self, item, v):
self._timetable[item] = time.time()
dict.__setitem__(self, item,v)
def __repr__(self):
if self.timeout is None:
n = len(self)
else:
n = 0
t0 = time.time()
for t,v in self.itervalues():
if t0-t <= self.timeout:
n += 1
return "%s: %i valid items. Timeout=%rs" % (self.name, n, self.timeout)
class NetCache:
def __init__(self):
self._caches_list = []
def add_cache(self, cache):
self._caches_list.append(cache)
setattr(self,cache.name,cache)
def new_cache(self, name, timeout=None):
c = CacheInstance(name=name, timeout=timeout)
self.add_cache(c)
def __delattr__(self, attr):
raise AttributeError("Cannot delete attributes")
def update(self, other):
for co in other._caches_list:
if hasattr(self, co.name):
getattr(self,co.name).update(co)
else:
self.add_cache(co.copy())
def flush(self):
for c in self._caches_list:
c.flush()
def __repr__(self):
return "\n".join(repr(c) for c in self._caches_list)
class Conf(ConfClass):
"""This object contains the configuration of scapy.
......@@ -173,7 +232,8 @@ extensions_paths: path or list of paths where extensions are to be looked for
manufdb = load_manuf("/usr/share/wireshark/wireshark/manuf")
stats_classic_protocols = []
stats_dot11_protocols = []
arp_cache = {}
netcache = NetCache()
conf=Conf()
......
......@@ -6,7 +6,7 @@ from scapy.fields import *
from scapy.packet import *
from scapy.volatile import *
from scapy.config import conf
from scapy.sendrecv import sr,sr1
from scapy.sendrecv import sr,sr1,srp1
from scapy.plist import PacketList,SndRcvList
import scapy.as_resolvers
......@@ -504,6 +504,9 @@ conf.l3types.register(ETH_P_IP, IP)
conf.l3types.register_num2layer(ETH_P_ALL, IP)
conf.neighbor.register_l3(Ether, IP, lambda l2,l3: getmacbyip(l3.dst))
###################
## Fragmentation ##
###################
......
......@@ -6,6 +6,61 @@ from scapy.plist import SndRcvList
from scapy.fields import *
from scapy.sendrecv import srp,srp1
#################
## Tools ##
#################
class Neighbor:
def __init__(self):
self.resolvers = {}
def register_l3(self, l2, l3, resolve_method):
self.resolvers[l2,l3]=resolve_method
def resolve(self, l2inst, l3inst):
return self.resolvers[l2inst.__class__,l3inst.__class__](l2inst,l3inst)
def __repr__(self):
return "\n".join("%-15s -> %-15s" % (l2.__name__, l3.__name__) for l2,l3 in self.resolvers)
conf.neighbor = Neighbor()
conf.netcache.new_cache("arp_cache", 120) # cache entries expire after 120s
def getmacbyip(ip, chainCC=0):
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 = config.conf.route.route(ip)
if ( (iff == "lo") or (ip == config.conf.route.get_if_bcast(iff)) ):
return "ff:ff:ff:ff:ff:ff"
if gw != "0.0.0.0":
ip = gw
mac = config.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
config.conf.netcache.arp_cache[ip] = mac
return mac
return None
### Fields
class DestMACField(MACField):
......@@ -13,23 +68,10 @@ class DestMACField(MACField):
MACField.__init__(self, name, None)
def i2h(self, pkt, x):
if x is None:
dstip = None
if isinstance(pkt.payload, IPv6):
dstip = pkt.payload.dst
elif isinstance(pkt.payload, IP):
dstip = pkt.payload.dst
elif isinstance(pkt.payload, ARP):
dstip = pkt.payload.pdst
if isinstance(dstip, Gen):
dstip = dstip.__iter__().next()
if dstip is not None:
if isinstance(pkt.payload, IPv6):
x = getmacbyip6(dstip, chainCC=1)
else:
x = getmacbyip(dstip, chainCC=1)
x = conf.neighbor.resolve(pkt,pkt.payload)
if x is None:
x = "ff:ff:ff:ff:ff:ff"
warning("Mac address to reach %s not found\n"%dstip)
warning("Mac address to reach destination not found")
return MACField.i2h(self, pkt, x)
def i2m(self, pkt, x):
return MACField.i2m(self, pkt, self.i2h(pkt, x))
......@@ -48,6 +90,7 @@ class SourceMACField(MACField):
dstip = pkt.payload.pdst
if isinstance(dstip, Gen):
dstip = dstip.__iter__().next()
if dstip is not None:
if isinstance(pkt.payload, IPv6):
iff,a,nh = conf.route6.route(dstip)
......@@ -296,7 +339,7 @@ class ARP(Packet):
else:
return "ARP %ARP.op% %ARP.psrc% > %ARP.pdst%"
conf.neighbor.register_l3(Ether, ARP, lambda l2,l3: getmacbyip(l3.pdst))
class GRE(Packet):
name = "GRE"
......@@ -352,6 +395,13 @@ conf.l2types.register(144, CookedLinux) # called LINUX_IRDA, similar to CookedL
conf.l3types.register(ETH_P_ARP, ARP)
### Technics
def arpcachepoison(target, victim, interval=60):
"""Poison target's cache with (your MAC,victim's IP) couple
arpcachepoison(target, victim, [interval=60]) -> None
......
......@@ -85,8 +85,7 @@ class Route:
self.routes[i] = (the_net,the_msk,gw,iface,the_addr)
else:
self.routes[i] = (net,msk,gw,iface,the_addr)
for i in conf.arp_cache.keys():
del(conf.arp_cache[i])
conf.netcache.flush()
......
......@@ -92,7 +92,7 @@ def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, m
try:
os.setpgrp() # Chance process group to avoid ctrl-C
sent_times = [p.sent_time for p in all_stimuli if p.sent_time]
cPickle.dump( (conf.arp_cache,sent_times), wrpipe )
cPickle.dump( (conf.netcache,sent_times), wrpipe )
wrpipe.close()
except:
pass
......@@ -158,11 +158,11 @@ def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, m
raise
finally:
try:
ac,sent_times = cPickle.load(rdpipe)
nc,sent_times = cPickle.load(rdpipe)
except EOFError:
warning("Child died unexpectedly. Packets may have not been sent %i"%os.getpid())
else:
conf.arp_cache.update(ac)
conf.netcache.update(nc)
for p,t in zip(all_stimuli, sent_times):
p.sent_time = t
os.waitpid(pid,0)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment