|
phil@1104
|
1 |
## This file is part of Scapy
|
|
phil@1104
|
2 |
## See http://www.secdev.org/projects/scapy for more informations
|
|
phil@1104
|
3 |
## Copyright (C) Philippe Biondi <phil@secdev.org>
|
|
phil@1104
|
4 |
## This program is published under a GPLv2 license
|
|
phil@1104
|
5 |
|
|
mail@1192
|
6 |
import os,re,sys,socket,time
|
|
phil@1104
|
7 |
from glob import glob
|
|
phil@1104
|
8 |
from scapy.config import conf,ConfClass
|
|
mail@1191
|
9 |
from scapy.error import Scapy_Exception,log_loading,log_runtime
|
|
mail@1192
|
10 |
from scapy.utils import atol, inet_aton, inet_ntoa, PcapReader
|
|
mail@1192
|
11 |
from scapy.base_classes import Gen, Net, SetGen
|
|
mail@1107
|
12 |
import scapy.plist as plist
|
|
mail@1192
|
13 |
from scapy.sendrecv import debug, srp1
|
|
mail@1192
|
14 |
from scapy.layers.l2 import Ether, ARP
|
|
mail@1192
|
15 |
from scapy.data import MTU, ETHER_BROADCAST, ETH_P_ARP
|
|
phil@1104
|
16 |
|
|
phil@1104
|
17 |
conf.use_pcap = 1
|
|
phil@1104
|
18 |
conf.use_dnet = 1
|
|
phil@1104
|
19 |
from scapy.arch import pcapdnet
|
|
phil@1104
|
20 |
from scapy.arch.pcapdnet import *
|
|
phil@1104
|
21 |
|
|
phil@1104
|
22 |
LOOPBACK_NAME="lo0"
|
|
mail@1192
|
23 |
WINDOWS = True
|
|
phil@1104
|
24 |
|
|
phil@1104
|
25 |
|
|
phil@1104
|
26 |
def _where(filename, dirs=[], env="PATH"):
|
|
phil@1104
|
27 |
"""Find file in current dir or system path"""
|
|
phil@1104
|
28 |
if not isinstance(dirs, list):
|
|
phil@1104
|
29 |
dirs = [dirs]
|
|
phil@1104
|
30 |
if glob(filename):
|
|
phil@1104
|
31 |
return filename
|
|
phil@1104
|
32 |
paths = [os.curdir] + os.environ[env].split(os.path.pathsep) + dirs
|
|
phil@1104
|
33 |
for path in paths:
|
|
phil@1104
|
34 |
for match in glob(os.path.join(path, filename)):
|
|
phil@1104
|
35 |
if match:
|
|
phil@1104
|
36 |
return os.path.normpath(match)
|
|
phil@1104
|
37 |
raise IOError("File not found: %s" % filename)
|
|
phil@1104
|
38 |
|
|
phil@1104
|
39 |
def win_find_exe(filename, installsubdir=None, env="ProgramFiles"):
|
|
phil@1104
|
40 |
"""Find executable in current dir, system path or given ProgramFiles subdir"""
|
|
phil@1104
|
41 |
for fn in [filename, filename+".exe"]:
|
|
phil@1104
|
42 |
try:
|
|
phil@1104
|
43 |
if installsubdir is None:
|
|
phil@1104
|
44 |
path = _where(fn)
|
|
phil@1104
|
45 |
else:
|
|
phil@1104
|
46 |
path = _where(fn, dirs=[os.path.join(os.environ[env], installsubdir)])
|
|
phil@1104
|
47 |
except IOError:
|
|
phil@1104
|
48 |
path = filename
|
|
phil@1104
|
49 |
else:
|
|
phil@1104
|
50 |
break
|
|
phil@1104
|
51 |
return path
|
|
phil@1104
|
52 |
|
|
phil@1104
|
53 |
|
|
phil@1104
|
54 |
class WinProgPath(ConfClass):
|
|
phil@1104
|
55 |
_default = "<System default>"
|
|
phil@1104
|
56 |
# We try some magic to find the appropriate executables
|
|
mail@1194
|
57 |
pdfreader = win_find_exe("AcroRd32")
|
|
mail@1194
|
58 |
psreader = win_find_exe("gsview32.exe", "Ghostgum/gsview")
|
|
phil@1104
|
59 |
dot = win_find_exe("dot", "ATT/Graphviz/bin")
|
|
phil@1104
|
60 |
tcpdump = win_find_exe("windump")
|
|
phil@1104
|
61 |
tcpreplay = win_find_exe("tcpreplay")
|
|
phil@1104
|
62 |
display = _default
|
|
phil@1104
|
63 |
hexedit = win_find_exe("hexer")
|
|
phil@1104
|
64 |
wireshark = win_find_exe("wireshark", "wireshark")
|
|
phil@1104
|
65 |
|
|
phil@1104
|
66 |
conf.prog = WinProgPath()
|
|
phil@1104
|
67 |
|
|
phil@1104
|
68 |
|
|
phil@1104
|
69 |
|
|
phil@1104
|
70 |
import _winreg
|
|
phil@1104
|
71 |
|
|
phil@1104
|
72 |
|
|
phil@1104
|
73 |
|
|
phil@1104
|
74 |
class PcapNameNotFoundError(Scapy_Exception):
|
|
phil@1104
|
75 |
pass
|
|
phil@1104
|
76 |
|
|
phil@1104
|
77 |
class NetworkInterface(object):
|
|
phil@1104
|
78 |
"""A network interface of your local host"""
|
|
phil@1104
|
79 |
|
|
phil@1104
|
80 |
def __init__(self, dnetdict=None):
|
|
phil@1104
|
81 |
self.name = None
|
|
phil@1104
|
82 |
self.ip = None
|
|
phil@1104
|
83 |
self.mac = None
|
|
phil@1104
|
84 |
self.pcap_name = None
|
|
phil@1104
|
85 |
self.win_name = None
|
|
phil@1104
|
86 |
self.uuid = None
|
|
phil@1104
|
87 |
self.dnetdict = dnetdict
|
|
phil@1104
|
88 |
if dnetdict is not None:
|
|
phil@1104
|
89 |
self.update(dnetdict)
|
|
phil@1104
|
90 |
|
|
phil@1104
|
91 |
def update(self, dnetdict):
|
|
phil@1104
|
92 |
"""Update info about network interface according to given dnet dictionary"""
|
|
phil@1104
|
93 |
self.name = dnetdict["name"]
|
|
phil@1104
|
94 |
# Other attributes are optional
|
|
phil@1104
|
95 |
try:
|
|
phil@1104
|
96 |
self.ip = socket.inet_ntoa(dnetdict["addr"].ip)
|
|
phil@1104
|
97 |
except (KeyError, AttributeError, NameError):
|
|
phil@1104
|
98 |
pass
|
|
phil@1104
|
99 |
try:
|
|
phil@1104
|
100 |
self.mac = dnetdict["link_addr"]
|
|
phil@1104
|
101 |
except KeyError:
|
|
phil@1104
|
102 |
pass
|
|
phil@1104
|
103 |
self._update_pcapdata()
|
|
phil@1104
|
104 |
|
|
phil@1104
|
105 |
def _update_pcapdata(self):
|
|
phil@1104
|
106 |
"""Supplement more info from pypcap and the Windows registry"""
|
|
phil@1104
|
107 |
|
|
mail@1185
|
108 |
# XXX: We try eth0 - eth29 by bruteforce and match by IP address,
|
|
phil@1104
|
109 |
# because only the IP is available in both pypcap and dnet.
|
|
phil@1104
|
110 |
# This may not work with unorthodox network configurations and is
|
|
phil@1104
|
111 |
# slow because we have to walk through the Windows registry.
|
|
mail@1185
|
112 |
for n in range(30):
|
|
phil@1104
|
113 |
guess = "eth%s" % n
|
|
phil@1104
|
114 |
win_name = pcapdnet.pcap.ex_name(guess)
|
|
phil@1104
|
115 |
if win_name.endswith("}"):
|
|
phil@1104
|
116 |
try:
|
|
phil@1104
|
117 |
uuid = win_name[win_name.index("{"):win_name.index("}")+1]
|
|
phil@1104
|
118 |
keyname = r"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\%s" % uuid
|
|
phil@1104
|
119 |
try:
|
|
phil@1104
|
120 |
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyname)
|
|
phil@1104
|
121 |
except WindowsError:
|
|
phil@1104
|
122 |
log_loading.debug("Couldn't open 'HKEY_LOCAL_MACHINE\\%s' (for guessed pcap iface name '%s')." % (keyname, guess))
|
|
phil@1104
|
123 |
continue
|
|
phil@1104
|
124 |
try:
|
|
phil@1104
|
125 |
fixed_ip = _winreg.QueryValueEx(key, "IPAddress")[0][0].encode("utf-8")
|
|
phil@1104
|
126 |
except (WindowsError, UnicodeDecodeError, IndexError):
|
|
phil@1104
|
127 |
fixed_ip = None
|
|
phil@1104
|
128 |
try:
|
|
phil@1104
|
129 |
dhcp_ip = _winreg.QueryValueEx(key, "DhcpIPAddress")[0].encode("utf-8")
|
|
phil@1104
|
130 |
except (WindowsError, UnicodeDecodeError, IndexError):
|
|
phil@1104
|
131 |
dhcp_ip = None
|
|
phil@1104
|
132 |
# "0.0.0.0" or None means the value is not set (at least not correctly).
|
|
phil@1104
|
133 |
# If both fixed_ip and dhcp_ip are set, fixed_ip takes precedence
|
|
phil@1104
|
134 |
if fixed_ip is not None and fixed_ip != "0.0.0.0":
|
|
phil@1104
|
135 |
ip = fixed_ip
|
|
phil@1104
|
136 |
elif dhcp_ip is not None and dhcp_ip != "0.0.0.0":
|
|
phil@1104
|
137 |
ip = dhcp_ip
|
|
phil@1104
|
138 |
else:
|
|
phil@1104
|
139 |
continue
|
|
phil@1104
|
140 |
except IOError:
|
|
phil@1104
|
141 |
continue
|
|
phil@1104
|
142 |
else:
|
|
phil@1104
|
143 |
if ip == self.ip:
|
|
phil@1104
|
144 |
self.pcap_name = guess
|
|
phil@1104
|
145 |
self.win_name = win_name
|
|
phil@1104
|
146 |
self.uuid = uuid
|
|
phil@1104
|
147 |
break
|
|
phil@1104
|
148 |
else:
|
|
phil@1104
|
149 |
raise PcapNameNotFoundError
|
|
phil@1104
|
150 |
|
|
phil@1104
|
151 |
def __repr__(self):
|
|
phil@1104
|
152 |
return "<%s: %s %s %s pcap_name=%s win_name=%s>" % (self.__class__.__name__,
|
|
phil@1104
|
153 |
self.name, self.ip, self.mac, self.pcap_name, self.win_name)
|
|
phil@1104
|
154 |
|
|
phil@1104
|
155 |
from UserDict import IterableUserDict
|
|
phil@1104
|
156 |
|
|
phil@1104
|
157 |
class NetworkInterfaceDict(IterableUserDict):
|
|
phil@1104
|
158 |
"""Store information about network interfaces and convert between names"""
|
|
phil@1104
|
159 |
|
|
phil@1104
|
160 |
def load_from_dnet(self):
|
|
phil@1104
|
161 |
"""Populate interface table via dnet"""
|
|
phil@1104
|
162 |
for i in pcapdnet.dnet.intf():
|
|
phil@1104
|
163 |
try:
|
|
phil@1104
|
164 |
# XXX: Only Ethernet for the moment: localhost is not supported by dnet and pcap
|
|
mail@1187
|
165 |
# We only take interfaces that have an IP address, because the IP
|
|
mail@1187
|
166 |
# is used for the mapping between dnet and pcap interface names
|
|
mail@1187
|
167 |
# and this significantly improves Scapy's startup performance
|
|
mail@1187
|
168 |
if i["name"].startswith("eth") and "addr" in i:
|
|
phil@1104
|
169 |
self.data[i["name"]] = NetworkInterface(i)
|
|
phil@1104
|
170 |
except (KeyError, PcapNameNotFoundError):
|
|
phil@1104
|
171 |
pass
|
|
phil@1104
|
172 |
if len(self.data) == 0:
|
|
phil@1104
|
173 |
log_loading.warning("No match between your pcap and dnet network interfaces found. "
|
|
phil@1104
|
174 |
"You probably won't be able to send packets. "
|
|
phil@1104
|
175 |
"Deactivating unneeded interfaces and restarting Scapy might help.")
|
|
phil@1104
|
176 |
|
|
phil@1104
|
177 |
def pcap_name(self, devname):
|
|
phil@1104
|
178 |
"""Return pypcap device name for given libdnet/Scapy device name
|
|
phil@1104
|
179 |
|
|
phil@1104
|
180 |
This mapping is necessary because pypcap numbers the devices differently."""
|
|
phil@1104
|
181 |
|
|
phil@1104
|
182 |
try:
|
|
phil@1104
|
183 |
pcap_name = self.data[devname].pcap_name
|
|
phil@1104
|
184 |
except KeyError:
|
|
phil@1104
|
185 |
raise ValueError("Unknown network interface %r" % devname)
|
|
phil@1104
|
186 |
else:
|
|
phil@1104
|
187 |
return pcap_name
|
|
phil@1104
|
188 |
|
|
phil@1104
|
189 |
def devname(self, pcap_name):
|
|
phil@1104
|
190 |
"""Return libdnet/Scapy device name for given pypcap device name
|
|
phil@1104
|
191 |
|
|
phil@1104
|
192 |
This mapping is necessary because pypcap numbers the devices differently."""
|
|
phil@1104
|
193 |
|
|
phil@1104
|
194 |
for devname, iface in self.items():
|
|
phil@1104
|
195 |
if iface.pcap_name == pcap_name:
|
|
phil@1104
|
196 |
return iface.name
|
|
phil@1104
|
197 |
raise ValueError("Unknown pypcap network interface %r" % pcap_name)
|
|
phil@1104
|
198 |
|
|
phil@1104
|
199 |
def show(self, resolve_mac=True):
|
|
phil@1104
|
200 |
"""Print list of available network interfaces in human readable form"""
|
|
phil@1104
|
201 |
print "%s %s %s" % ("IFACE".ljust(5), "IP".ljust(15), "MAC")
|
|
phil@1104
|
202 |
for iface_name in sorted(self.data.keys()):
|
|
phil@1104
|
203 |
dev = self.data[iface_name]
|
|
phil@1104
|
204 |
mac = str(dev.mac)
|
|
phil@1104
|
205 |
if resolve_mac:
|
|
phil@1104
|
206 |
mac = conf.manufdb._resolve_MAC(mac)
|
|
phil@1104
|
207 |
print "%s %s %s" % (str(dev.name).ljust(5), str(dev.ip).ljust(15), mac)
|
|
phil@1104
|
208 |
|
|
phil@1104
|
209 |
ifaces = NetworkInterfaceDict()
|
|
phil@1104
|
210 |
ifaces.load_from_dnet()
|
|
phil@1104
|
211 |
|
|
phil@1104
|
212 |
def pcap_name(devname):
|
|
phil@1104
|
213 |
"""Return pypcap device name for given libdnet/Scapy device name"""
|
|
phil@1104
|
214 |
try:
|
|
phil@1104
|
215 |
pcap_name = ifaces.pcap_name(devname)
|
|
phil@1104
|
216 |
except ValueError:
|
|
phil@1104
|
217 |
# pcap.pcap() will choose a sensible default for sniffing if iface=None
|
|
phil@1104
|
218 |
pcap_name = None
|
|
phil@1104
|
219 |
return pcap_name
|
|
phil@1104
|
220 |
|
|
phil@1104
|
221 |
def devname(pcap_name):
|
|
phil@1104
|
222 |
"""Return libdnet/Scapy device name for given pypcap device name"""
|
|
phil@1104
|
223 |
return ifaces.devname(pcap_name)
|
|
phil@1104
|
224 |
|
|
phil@1104
|
225 |
def show_interfaces(resolve_mac=True):
|
|
phil@1104
|
226 |
"""Print list of available network interfaces"""
|
|
phil@1104
|
227 |
return ifaces.show(resolve_mac)
|
|
phil@1104
|
228 |
|
|
phil@1104
|
229 |
_orig_open_pcap = pcapdnet.open_pcap
|
|
phil@1104
|
230 |
pcapdnet.open_pcap = lambda iface,*args,**kargs: _orig_open_pcap(pcap_name(iface),*args,**kargs)
|
|
phil@1104
|
231 |
|
|
phil@1104
|
232 |
def read_routes():
|
|
phil@1104
|
233 |
ok = 0
|
|
phil@1104
|
234 |
routes = []
|
|
mail@1139
|
235 |
ip = '(\d+\.\d+\.\d+\.\d+)'
|
|
mail@1139
|
236 |
# On Vista and Windows 7 the gateway can be IP or 'On-link'.
|
|
mail@1139
|
237 |
# But the exact 'On-link' string depends on the locale, so we allow any text.
|
|
mail@1139
|
238 |
gw_pattern = '(.+)'
|
|
mail@1139
|
239 |
metric_pattern = "(\d+)"
|
|
mail@1139
|
240 |
delim = "\s+" # The columns are separated by whitespace
|
|
mail@1139
|
241 |
netstat_line = delim.join([ip, ip, gw_pattern, ip, metric_pattern])
|
|
phil@1104
|
242 |
pattern = re.compile(netstat_line)
|
|
phil@1104
|
243 |
f=os.popen("netstat -rn")
|
|
phil@1104
|
244 |
for l in f.readlines():
|
|
phil@1104
|
245 |
match = re.search(pattern,l)
|
|
phil@1104
|
246 |
if match:
|
|
phil@1104
|
247 |
dest = match.group(1)
|
|
phil@1104
|
248 |
mask = match.group(2)
|
|
phil@1104
|
249 |
gw = match.group(3)
|
|
phil@1104
|
250 |
netif = match.group(4)
|
|
phil@1104
|
251 |
metric = match.group(5)
|
|
mail@1188
|
252 |
try:
|
|
mail@1188
|
253 |
intf = pcapdnet.dnet.intf().get_dst(pcapdnet.dnet.addr(type=2, addrtxt=dest))
|
|
mail@1188
|
254 |
except OSError:
|
|
mail@1188
|
255 |
log_loading.warning("Building Scapy's routing table: Couldn't get outgoing interface for destination %s" % dest)
|
|
mail@1188
|
256 |
continue
|
|
phil@1104
|
257 |
if not intf.has_key("addr"):
|
|
phil@1104
|
258 |
break
|
|
phil@1104
|
259 |
addr = str(intf["addr"])
|
|
phil@1104
|
260 |
addr = addr.split("/")[0]
|
|
phil@1104
|
261 |
|
|
phil@1104
|
262 |
dest = atol(dest)
|
|
phil@1104
|
263 |
mask = atol(mask)
|
|
mail@1108
|
264 |
# If the gateway is no IP we assume it's on-link
|
|
mail@1108
|
265 |
gw_ipmatch = re.search('\d+\.\d+\.\d+\.\d+', gw)
|
|
mail@1108
|
266 |
if gw_ipmatch:
|
|
mail@1108
|
267 |
gw = gw_ipmatch.group(0)
|
|
mail@1108
|
268 |
else:
|
|
mail@1108
|
269 |
gw = netif
|
|
phil@1104
|
270 |
routes.append((dest,mask,gw, str(intf["name"]), addr))
|
|
phil@1104
|
271 |
f.close()
|
|
phil@1104
|
272 |
return routes
|
|
phil@1104
|
273 |
|
|
phil@1104
|
274 |
def read_routes6():
|
|
phil@1104
|
275 |
return []
|
|
phil@1104
|
276 |
|
|
phil@1104
|
277 |
def getmacbyip(ip, chainCC=0):
|
|
mail@1112
|
278 |
"""Return MAC address corresponding to a given IP address"""
|
|
mail@1112
|
279 |
if isinstance(ip,Net):
|
|
mail@1112
|
280 |
ip = iter(ip).next()
|
|
mail@1112
|
281 |
tmp = map(ord, inet_aton(ip))
|
|
mail@1112
|
282 |
if (tmp[0] & 0xf0) == 0xe0: # mcast @
|
|
mail@1112
|
283 |
return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])
|
|
phil@1104
|
284 |
iff,a,gw = conf.route.route(ip)
|
|
mail@1112
|
285 |
if ( (iff == LOOPBACK_NAME) or (ip == conf.route.get_if_bcast(iff)) ):
|
|
phil@1104
|
286 |
return "ff:ff:ff:ff:ff:ff"
|
|
mail@1112
|
287 |
# Windows uses local IP instead of 0.0.0.0 to represent locally reachable addresses
|
|
phil@1104
|
288 |
ifip = str(pcapdnet.dnet.intf().get(iff)['addr'])
|
|
phil@1104
|
289 |
if gw != ifip.split('/')[0]:
|
|
phil@1104
|
290 |
ip = gw
|
|
mail@1112
|
291 |
|
|
mail@1112
|
292 |
mac = conf.netcache.arp_cache.get(ip)
|
|
mail@1112
|
293 |
if mac:
|
|
mail@1112
|
294 |
return mac
|
|
mail@1112
|
295 |
|
|
phil@1104
|
296 |
res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip),
|
|
phil@1104
|
297 |
type=ETH_P_ARP,
|
|
phil@1104
|
298 |
iface = iff,
|
|
phil@1104
|
299 |
timeout=2,
|
|
phil@1104
|
300 |
verbose=0,
|
|
phil@1104
|
301 |
chainCC=chainCC,
|
|
phil@1104
|
302 |
nofilter=1)
|
|
phil@1104
|
303 |
if res is not None:
|
|
phil@1104
|
304 |
mac = res.payload.hwsrc
|
|
mail@1112
|
305 |
conf.netcache.arp_cache[ip] = mac
|
|
phil@1104
|
306 |
return mac
|
|
phil@1104
|
307 |
return None
|
|
phil@1104
|
308 |
|
|
mail@1186
|
309 |
import scapy.layers.l2
|
|
mail@1186
|
310 |
scapy.layers.l2.getmacbyip = getmacbyip
|
|
mail@1186
|
311 |
|
|
phil@1104
|
312 |
try:
|
|
phil@1104
|
313 |
import readline
|
|
phil@1104
|
314 |
console = readline.GetOutputFile()
|
|
phil@1104
|
315 |
except (ImportError, AttributeError):
|
|
phil@1104
|
316 |
log_loading.info("Could not get readline console. Will not interpret ANSI color codes.")
|
|
phil@1104
|
317 |
else:
|
|
phil@1105
|
318 |
conf.readfunc = readline.rl.readline
|
|
phil@1104
|
319 |
orig_stdout = sys.stdout
|
|
phil@1104
|
320 |
sys.stdout = console
|
|
phil@1104
|
321 |
|
|
phil@1104
|
322 |
|
|
phil@1104
|
323 |
|
|
phil@1104
|
324 |
|
|
phil@1104
|
325 |
|
|
phil@1104
|
326 |
def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, multi=0):
|
|
phil@1104
|
327 |
if not isinstance(pkt, Gen):
|
|
phil@1104
|
328 |
pkt = SetGen(pkt)
|
|
phil@1104
|
329 |
|
|
phil@1104
|
330 |
if verbose is None:
|
|
phil@1104
|
331 |
verbose = conf.verb
|
|
phil@1104
|
332 |
debug.recv = plist.PacketList([],"Unanswered")
|
|
phil@1104
|
333 |
debug.sent = plist.PacketList([],"Sent")
|
|
phil@1104
|
334 |
debug.match = plist.SndRcvList([])
|
|
phil@1104
|
335 |
nbrecv=0
|
|
phil@1104
|
336 |
ans = []
|
|
phil@1104
|
337 |
# do it here to fix random fields, so that parent and child have the same
|
|
phil@1104
|
338 |
all_stimuli = tobesent = [p for p in pkt]
|
|
phil@1104
|
339 |
notans = len(tobesent)
|
|
phil@1104
|
340 |
|
|
phil@1104
|
341 |
hsent={}
|
|
phil@1104
|
342 |
for i in tobesent:
|
|
phil@1104
|
343 |
h = i.hashret()
|
|
phil@1104
|
344 |
if h in hsent:
|
|
phil@1104
|
345 |
hsent[h].append(i)
|
|
phil@1104
|
346 |
else:
|
|
phil@1104
|
347 |
hsent[h] = [i]
|
|
phil@1104
|
348 |
if retry < 0:
|
|
phil@1104
|
349 |
retry = -retry
|
|
phil@1104
|
350 |
autostop=retry
|
|
phil@1104
|
351 |
else:
|
|
phil@1104
|
352 |
autostop=0
|
|
phil@1104
|
353 |
|
|
phil@1104
|
354 |
|
|
phil@1104
|
355 |
while retry >= 0:
|
|
phil@1104
|
356 |
found=0
|
|
phil@1104
|
357 |
|
|
phil@1104
|
358 |
if timeout < 0:
|
|
phil@1104
|
359 |
timeout = None
|
|
phil@1104
|
360 |
|
|
phil@1104
|
361 |
pid=1
|
|
phil@1104
|
362 |
try:
|
|
phil@1104
|
363 |
if WINDOWS or pid == 0:
|
|
phil@1104
|
364 |
try:
|
|
phil@1104
|
365 |
try:
|
|
phil@1104
|
366 |
i = 0
|
|
phil@1104
|
367 |
if verbose:
|
|
phil@1104
|
368 |
print "Begin emission:"
|
|
phil@1104
|
369 |
for p in tobesent:
|
|
phil@1104
|
370 |
pks.send(p)
|
|
phil@1104
|
371 |
i += 1
|
|
phil@1104
|
372 |
time.sleep(inter)
|
|
phil@1104
|
373 |
if verbose:
|
|
phil@1104
|
374 |
print "Finished to send %i packets." % i
|
|
phil@1104
|
375 |
except SystemExit:
|
|
phil@1104
|
376 |
pass
|
|
phil@1104
|
377 |
except KeyboardInterrupt:
|
|
phil@1104
|
378 |
pass
|
|
phil@1104
|
379 |
except:
|
|
phil@1104
|
380 |
log_runtime.exception("--- Error sending packets")
|
|
phil@1104
|
381 |
log_runtime.info("--- Error sending packets")
|
|
phil@1104
|
382 |
finally:
|
|
phil@1104
|
383 |
try:
|
|
phil@1104
|
384 |
sent_times = [p.sent_time for p in all_stimuli if p.sent_time]
|
|
phil@1104
|
385 |
except:
|
|
phil@1104
|
386 |
pass
|
|
phil@1104
|
387 |
if WINDOWS or pid > 0:
|
|
phil@1104
|
388 |
# Timeout starts after last packet is sent (as in Unix version)
|
|
phil@1104
|
389 |
if timeout:
|
|
phil@1104
|
390 |
stoptime = time.time()+timeout
|
|
phil@1104
|
391 |
else:
|
|
phil@1104
|
392 |
stoptime = 0
|
|
phil@1104
|
393 |
remaintime = None
|
|
phil@1104
|
394 |
inmask = [pks.ins.fd]
|
|
phil@1104
|
395 |
try:
|
|
phil@1104
|
396 |
try:
|
|
phil@1104
|
397 |
while 1:
|
|
phil@1104
|
398 |
if stoptime:
|
|
phil@1104
|
399 |
remaintime = stoptime-time.time()
|
|
phil@1104
|
400 |
if remaintime <= 0:
|
|
phil@1104
|
401 |
break
|
|
phil@1104
|
402 |
r = pks.recv(MTU)
|
|
phil@1104
|
403 |
if r is None:
|
|
phil@1104
|
404 |
continue
|
|
phil@1104
|
405 |
ok = 0
|
|
phil@1104
|
406 |
h = r.hashret()
|
|
phil@1104
|
407 |
if h in hsent:
|
|
phil@1104
|
408 |
hlst = hsent[h]
|
|
phil@1104
|
409 |
for i in range(len(hlst)):
|
|
phil@1104
|
410 |
if r.answers(hlst[i]):
|
|
phil@1104
|
411 |
ans.append((hlst[i],r))
|
|
phil@1104
|
412 |
if verbose > 1:
|
|
phil@1104
|
413 |
os.write(1, "*")
|
|
phil@1104
|
414 |
ok = 1
|
|
phil@1104
|
415 |
if not multi:
|
|
phil@1104
|
416 |
del(hlst[i])
|
|
phil@1104
|
417 |
notans -= 1;
|
|
phil@1104
|
418 |
else:
|
|
phil@1104
|
419 |
if not hasattr(hlst[i], '_answered'):
|
|
phil@1104
|
420 |
notans -= 1;
|
|
phil@1104
|
421 |
hlst[i]._answered = 1;
|
|
phil@1104
|
422 |
break
|
|
phil@1104
|
423 |
if notans == 0 and not multi:
|
|
phil@1104
|
424 |
break
|
|
phil@1104
|
425 |
if not ok:
|
|
phil@1104
|
426 |
if verbose > 1:
|
|
phil@1104
|
427 |
os.write(1, ".")
|
|
phil@1104
|
428 |
nbrecv += 1
|
|
phil@1104
|
429 |
if conf.debug_match:
|
|
phil@1104
|
430 |
debug.recv.append(r)
|
|
phil@1104
|
431 |
except KeyboardInterrupt:
|
|
phil@1104
|
432 |
if chainCC:
|
|
phil@1104
|
433 |
raise
|
|
phil@1104
|
434 |
finally:
|
|
phil@1104
|
435 |
if WINDOWS:
|
|
phil@1104
|
436 |
for p,t in zip(all_stimuli, sent_times):
|
|
phil@1104
|
437 |
p.sent_time = t
|
|
phil@1104
|
438 |
finally:
|
|
phil@1104
|
439 |
pass
|
|
phil@1104
|
440 |
|
|
phil@1104
|
441 |
remain = reduce(list.__add__, hsent.values(), [])
|
|
phil@1104
|
442 |
if multi:
|
|
phil@1104
|
443 |
remain = filter(lambda p: not hasattr(p, '_answered'), remain);
|
|
phil@1104
|
444 |
|
|
phil@1104
|
445 |
if autostop and len(remain) > 0 and len(remain) != len(tobesent):
|
|
phil@1104
|
446 |
retry = autostop
|
|
phil@1104
|
447 |
|
|
phil@1104
|
448 |
tobesent = remain
|
|
phil@1104
|
449 |
if len(tobesent) == 0:
|
|
phil@1104
|
450 |
break
|
|
phil@1104
|
451 |
retry -= 1
|
|
phil@1104
|
452 |
|
|
phil@1104
|
453 |
if conf.debug_match:
|
|
phil@1104
|
454 |
debug.sent=plist.PacketList(remain[:],"Sent")
|
|
phil@1104
|
455 |
debug.match=plist.SndRcvList(ans[:])
|
|
phil@1104
|
456 |
|
|
phil@1104
|
457 |
#clean the ans list to delete the field _answered
|
|
phil@1104
|
458 |
if (multi):
|
|
phil@1104
|
459 |
for s,r in ans:
|
|
phil@1104
|
460 |
if hasattr(s, '_answered'):
|
|
phil@1104
|
461 |
del(s._answered)
|
|
phil@1104
|
462 |
|
|
phil@1104
|
463 |
if verbose:
|
|
phil@1104
|
464 |
print "\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans)
|
|
mail@1111
|
465 |
return plist.SndRcvList(ans),plist.PacketList(remain,"Unanswered")
|
|
phil@1104
|
466 |
|
|
phil@1104
|
467 |
|
|
phil@1104
|
468 |
import scapy.sendrecv
|
|
phil@1104
|
469 |
scapy.sendrecv.sndrcv = sndrcv
|
|
mail@1115
|
470 |
|
|
mail@1116
|
471 |
def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, *arg, **karg):
|
|
mail@1116
|
472 |
"""Sniff packets
|
|
mail@1116
|
473 |
sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets
|
|
mail@1116
|
474 |
|
|
mail@1116
|
475 |
count: number of packets to capture. 0 means infinity
|
|
mail@1116
|
476 |
store: wether to store sniffed packets or discard them
|
|
mail@1116
|
477 |
prn: function to apply to each packet. If something is returned,
|
|
mail@1116
|
478 |
it is displayed. Ex:
|
|
mail@1116
|
479 |
ex: prn = lambda x: x.summary()
|
|
mail@1116
|
480 |
lfilter: python function applied to each packet to determine
|
|
mail@1116
|
481 |
if further action may be done
|
|
mail@1116
|
482 |
ex: lfilter = lambda x: x.haslayer(Padding)
|
|
mail@1116
|
483 |
offline: pcap file to read packets from, instead of sniffing them
|
|
mail@1116
|
484 |
timeout: stop sniffing after a given time (default: None)
|
|
mail@1116
|
485 |
L2socket: use the provided L2socket
|
|
mail@1116
|
486 |
"""
|
|
mail@1116
|
487 |
c = 0
|
|
mail@1116
|
488 |
|
|
mail@1116
|
489 |
if offline is None:
|
|
mail@1116
|
490 |
if L2socket is None:
|
|
mail@1116
|
491 |
L2socket = conf.L2listen
|
|
mail@1116
|
492 |
s = L2socket(type=ETH_P_ALL, *arg, **karg)
|
|
mail@1116
|
493 |
else:
|
|
mail@1116
|
494 |
s = PcapReader(offline)
|
|
mail@1116
|
495 |
|
|
mail@1116
|
496 |
lst = []
|
|
mail@1116
|
497 |
if timeout is not None:
|
|
mail@1116
|
498 |
stoptime = time.time()+timeout
|
|
mail@1116
|
499 |
remain = None
|
|
mail@1116
|
500 |
while 1:
|
|
mail@1116
|
501 |
try:
|
|
mail@1116
|
502 |
if timeout is not None:
|
|
mail@1116
|
503 |
remain = stoptime-time.time()
|
|
mail@1116
|
504 |
if remain <= 0:
|
|
mail@1116
|
505 |
break
|
|
mail@1116
|
506 |
|
|
mail@1116
|
507 |
try:
|
|
mail@1116
|
508 |
p = s.recv(MTU)
|
|
mail@1116
|
509 |
except PcapTimeoutElapsed:
|
|
mail@1116
|
510 |
continue
|
|
mail@1116
|
511 |
if p is None:
|
|
mail@1116
|
512 |
break
|
|
mail@1116
|
513 |
if lfilter and not lfilter(p):
|
|
mail@1116
|
514 |
continue
|
|
mail@1116
|
515 |
if store:
|
|
mail@1116
|
516 |
lst.append(p)
|
|
mail@1116
|
517 |
c += 1
|
|
mail@1116
|
518 |
if prn:
|
|
mail@1116
|
519 |
r = prn(p)
|
|
mail@1116
|
520 |
if r is not None:
|
|
d@1216
|
521 |
print r
|
|
mail@1116
|
522 |
if count > 0 and c >= count:
|
|
mail@1116
|
523 |
break
|
|
mail@1116
|
524 |
except KeyboardInterrupt:
|
|
mail@1116
|
525 |
break
|
|
mail@1116
|
526 |
s.close()
|
|
mail@1189
|
527 |
return plist.PacketList(lst,"Sniffed")
|
|
mail@1116
|
528 |
|
|
mail@1116
|
529 |
import scapy.sendrecv
|
|
mail@1116
|
530 |
scapy.sendrecv.sniff = sniff
|
|
mail@1116
|
531 |
|
|
mail@1115
|
532 |
def get_if_list():
|
|
mail@1115
|
533 |
return sorted(ifaces.keys())
|
|
mail@1115
|
534 |
|
|
mail@1115
|
535 |
def get_working_if():
|
|
mail@1115
|
536 |
try:
|
|
mail@1115
|
537 |
return devname(pcap.lookupdev())
|
|
mail@1115
|
538 |
except Exception:
|
|
mail@1115
|
539 |
return 'lo0'
|