Changeset 922:6901b30c8ac0

Show
Ignore:
Timestamp:
09/12/08 17:57:20 (4 months ago)
Author:
Phil <phil@secdev.org>
Message:

Split IPv6 neighbor cache

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • scapy/layers/inet6.py

    r921 r922  
    4747########################## 
    4848 
    49 NEIGHTIMEOUT=120 
     49conf.netcache.new_cache("in6_neighbor", 120) 
    5050 
    5151def neighsol(addr, src, iface, timeout=1, chainCC=0): 
     
    7171    return res 
    7272 
    73 class neighborCache: 
    74  
    75     # TODO : add some method to modify default value for timeout 
    76     # TODO : See what we can do for updating the neighbor cache 
    77     #        when receiving a packet. 
    78  
    79     # Note: internally, our neighbor cache is scapy's arp_cache. This allows us 
    80     #       to have it updated when returning from sr() (a fork is done where a 
    81     #       fork is done and the updated cache returned at the end. 
    82      
    83     def __init__(self): 
    84         self.neighcache = {} 
    85  
    86     def flush(self, statictoo=True): 
    87         self.neighcache = {} 
    88          
    89     def __repr__(self): 
    90         res = [("Peer", "Link layer address", "State")] 
    91         for addr in self.neighcache.keys(): 
    92             try: 
    93                 inet_pton(socket.AF_INET6, addr) 
    94             except: 
    95                 continue 
    96             cur_entry = self.neighcache[addr] 
    97             status = "REACHABLE" 
    98             last_contact = cur_entry[1] 
    99             if last_contact == 0: 
    100                 status = "STATIC" 
    101             elif ((time.time() - last_contact) < NEIGHTIMEOUT): 
    102                 status = "REACHABLE" 
    103             else: 
    104                 status = "STALE" 
    105             res.append((addr, cur_entry[0], status)) 
    106  
    107         colwidth = map(lambda x: max(map(lambda y: len(y), x)), apply(zip, res)) 
    108         fmt = "  ".join(map(lambda x: "%%-%ds"%x, colwidth)) 
    109         res = "\n".join(map(lambda x: fmt % x, res)) 
    110         return res 
    111  
    112     def addNeighbor(self, ip6, mac, static=False): 
    113         """ 
    114         Add a neighbor to the cache. If optional parameter 'static' is not  
    115         set to True (the default), the entry will expire in 2 minutes. If  
    116         'static' is set to True, the entry in the neighbor cache is made  
    117         static. This is practical in those cases : 
    118  
    119         - peer's address is not advertised to be on-link 
    120         - peer doed not answer to NS 
    121         - you don't want to make queries to keep time or be stealthy, ... 
    122         """ 
    123         t = 0 
    124         if not static: 
    125             t = time.time() 
    126         self.neighcache[ip6] = (mac, t) 
    127  
    128     def makeStatic(self, ip6): 
    129         """ 
    130         make the entry static in Scapy6 internal neighbor cache for  
    131         'ip6' neighbor. 
    132         """ 
    133         if self.neighcache.has_key(ip6): 
    134             mac = self.neighcache[ip6][0] 
    135             self.neighcache[ip6] = (mac, 0) 
    136         else: 
    137             warning("Unable to make neighbor cache entry for %s static. It does not exist." % ip6) 
    138  
    139     def removeStatic(self, ip6): 
    140         """ 
    141         remove the static status for 'ip6' entry in Scapy6 internal  
    142         neighbor cache. 
    143         """ 
    144         if self.neighcache.has_key(ip6): 
    145             mac = self.neighcache[ip6][0] 
    146             self.neighcache[ip6] = (mac, time.time()) 
    147         else: 
    148             warning("Unable to make neighbor cache entry for %s static. It does not exist." % ip6) 
    149  
    150     def get(self, ip6, chainCC=0): 
    151         """ 
    152         Returns the link layer address to use for IPv6 traffic to 'ip6' address.  
    153         If searched IPv6 address is multicast, then, ethernet address is computed. 
    154         If that's not the case, Scapy6 routing table is used to find next hop for 
    155         provided address. If one is found, cache is searched. If a valid (REACHABLE  
    156         or STATIC) entry exist, content is returned. Else, resolution is performed 
    157         by sending a Neighbor Solicitation.  
    158  
    159         In all cases, if lookup fails, None is returned. 
    160         """ 
    161  
    162         if in6_ismaddr(ip6): # Multicast  
    163             mac = in6_getnsmac(inet_pton(socket.AF_INET6, ip6)) 
    164             return mac 
    165      
    166         iff,a,nh = conf.route6.route(ip6, dev=conf.iface6) 
    167  
    168         if iff == LOOPBACK_NAME: 
    169             return "ff:ff:ff:ff:ff:ff" 
    170  
    171         if nh != '::':  
    172             ip6 = nh # Found next hop 
    173  
    174         if self.neighcache.has_key(ip6): # search the cache 
    175             mac, timeout = self.neighcache[ip6] 
    176             if timeout and (time.time()-timeout < NEIGHTIMEOUT): 
    177                 return mac 
    178  
    179         res = neighsol(ip6, a, iff, chainCC=chainCC) 
    180  
    181         if res is not None: 
    182             mac = res.src 
    183             self.neighcache[ip6] = (mac,time.time()) 
    184             return mac 
    185  
    186         return None 
    187  
    188 ip6_neigh_cache = neighborCache() 
    189  
    19073def getmacbyip6(ip6, chainCC=0): 
    19174    """ 
     
    19780     used to perform the resolution, if needed) 
    19881    """ 
    199     return ip6_neigh_cache.get(ip6, chainCC=chainCC) 
     82 
     83    if in6_ismaddr(ip6): # Multicast  
     84        mac = in6_getnsmac(inet_pton(socket.AF_INET6, ip6)) 
     85        return mac 
     86 
     87    iff,a,nh = conf.route6.route(ip6, dev=conf.iface6) 
     88 
     89    if iff == LOOPBACK_NAME: 
     90        return "ff:ff:ff:ff:ff:ff" 
     91 
     92    if nh != '::':  
     93        ip6 = nh # Found next hop 
     94 
     95    mac = conf.netcache.in6_neighbor.get(ip6) 
     96    if mac: 
     97        return mac 
     98 
     99    res = neighsol(ip6, a, iff, chainCC=chainCC) 
     100 
     101    if res is not None: 
     102        mac = res.src 
     103        conf.netcache.in6_neighbor[ip6] = mac 
     104        return mac 
     105 
     106    return None 
    200107 
    201108