Skip to content

Commit d5b2e6e

Browse files
committed
Merge pull request #1 from p-l-/feature-winpcap
Windows: use Winpcap, drop DNET dependency self-merge since @guedou is OK and @n1nj4sec agrees.
2 parents 0446249 + 00d6c02 commit d5b2e6e

File tree

4 files changed

+1378
-211
lines changed

4 files changed

+1378
-211
lines changed

scapy/arch/pcapdnet.py

100644100755
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,307 @@
1616
from scapy.supersocket import SuperSocket
1717
from scapy.error import Scapy_Exception
1818
import scapy.arch
19+
import socket
1920

2021

22+
if conf.use_winpcapy:
23+
#mostly code from https://github.com/phaethon/scapy translated to python2.X
24+
try:
25+
from .winpcapy import *
26+
def winpcapy_get_if_list():
27+
err = create_string_buffer(PCAP_ERRBUF_SIZE)
28+
devs = POINTER(pcap_if_t)()
29+
ret = []
30+
if pcap_findalldevs(byref(devs), err) < 0:
31+
return ret
32+
try:
33+
p = devs
34+
while p:
35+
ret.append(p.contents.name.decode('ascii'))
36+
p = p.contents.next
37+
return ret
38+
finally:
39+
pcap_freealldevs(devs)
2140

41+
except OSError as e:
42+
if conf.interactive:
43+
log_loading.error("Unable to import libpcap library: %s" % e)
44+
conf.use_winpcapy = False
45+
else:
46+
raise
47+
48+
# From BSD net/bpf.h
49+
#BIOCIMMEDIATE=0x80044270
50+
BIOCIMMEDIATE=-2147204496
51+
52+
class PcapTimeoutElapsed(Scapy_Exception):
53+
pass
54+
55+
def get_if_raw_hwaddr(iff):
56+
err = create_string_buffer(PCAP_ERRBUF_SIZE)
57+
devs = POINTER(pcap_if_t)()
58+
ret = "\0\0\0\0\0\0"
59+
60+
if pcap_findalldevs(byref(devs), err) < 0:
61+
return ret
62+
try:
63+
p = devs
64+
while p:
65+
if p.contents.name.endswith(iff):
66+
a = p.contents.addresses
67+
while a:
68+
if hasattr(socket, 'AF_LINK') and a.contents.addr.contents.sa_family == socket.AF_LINK:
69+
ap = a.contents.addr
70+
val = cast(ap, POINTER(sockaddr_dl))
71+
ret = str(val.contents.sdl_data[ val.contents.sdl_nlen : val.contents.sdl_nlen + val.contents.sdl_alen ])
72+
a = a.contents.next
73+
break
74+
p = p.contents.next
75+
return ret
76+
finally:
77+
pcap_freealldevs(devs)
78+
def get_if_raw_addr(iff):
79+
err = create_string_buffer(PCAP_ERRBUF_SIZE)
80+
devs = POINTER(pcap_if_t)()
81+
ret = "\0\0\0\0"
82+
83+
if pcap_findalldevs(byref(devs), err) < 0:
84+
return ret
85+
try:
86+
p = devs
87+
while p:
88+
if p.contents.name.endswith(iff):
89+
a = p.contents.addresses
90+
while a:
91+
if a.contents.addr.contents.sa_family == socket.AF_INET:
92+
ap = a.contents.addr
93+
val = cast(ap, POINTER(sockaddr_in))
94+
#ret = bytes(val.contents.sin_addr[:4])
95+
ret = "".join([chr(x) for x in val.contents.sin_addr[:4]])
96+
a = a.contents.next
97+
break
98+
p = p.contents.next
99+
return ret
100+
finally:
101+
pcap_freealldevs(devs)
102+
get_if_list = winpcapy_get_if_list
103+
def in6_getifaddr():
104+
err = create_string_buffer(PCAP_ERRBUF_SIZE)
105+
devs = POINTER(pcap_if_t)()
106+
ret = []
107+
if pcap_findalldevs(byref(devs), err) < 0:
108+
return ret
109+
try:
110+
p = devs
111+
ret = []
112+
while p:
113+
a = p.contents.addresses
114+
while a:
115+
if a.contents.addr.contents.sa_family == socket.AF_INET6:
116+
ap = a.contents.addr
117+
val = cast(ap, POINTER(sockaddr_in6))
118+
addr = socket.inet_ntop(socket.AF_INET6, str(val.contents.sin6_addr[:]))
119+
scope = scapy.utils6.in6_getscope(addr)
120+
ret.append((addr, scope, p.contents.name.decode('ascii')))
121+
a = a.contents.next
122+
p = p.contents.next
123+
return ret
124+
finally:
125+
pcap_freealldevs(devs)
126+
127+
from ctypes import POINTER, byref, create_string_buffer
128+
class _PcapWrapper_pypcap:
129+
def __init__(self, device, snaplen, promisc, to_ms):
130+
self.errbuf = create_string_buffer(PCAP_ERRBUF_SIZE)
131+
self.iface = create_string_buffer(device)
132+
self.pcap = pcap_open_live(self.iface, snaplen, promisc, to_ms, self.errbuf)
133+
self.header = POINTER(pcap_pkthdr)()
134+
self.pkt_data = POINTER(c_ubyte)()
135+
self.bpf_program = bpf_program()
136+
def next(self):
137+
c = pcap_next_ex(self.pcap, byref(self.header), byref(self.pkt_data))
138+
if not c > 0:
139+
return
140+
ts = self.header.contents.ts.tv_sec
141+
pkt = "".join([ chr(i) for i in self.pkt_data[:self.header.contents.len] ])
142+
#pkt = bytes(self.pkt_data[:self.header.contents.len])
143+
return ts, pkt
144+
def datalink(self):
145+
return pcap_datalink(self.pcap)
146+
def fileno(self):
147+
if sys.platform.startswith("win"):
148+
error("Cannot get selectable PCAP fd on Windows")
149+
return 0
150+
return pcap_get_selectable_fd(self.pcap)
151+
def setfilter(self, f):
152+
filter_exp = create_string_buffer(f)
153+
if pcap_compile(self.pcap, byref(self.bpf_program), filter_exp, 0, -1) == -1:
154+
error("Could not compile filter expression %s" % f)
155+
return False
156+
else:
157+
if pcap_setfilter(self.pcap, byref(self.bpf_program)) == -1:
158+
error("Could not install filter %s" % f)
159+
return False
160+
return True
161+
def setnonblock(self, i):
162+
pcap_setnonblock(self.pcap, i, self.errbuf)
163+
def send(self, x):
164+
pcap_sendpacket(self.pcap, x, len(x))
165+
def close(self):
166+
pcap_close(self.pcap)
167+
open_pcap = lambda *args,**kargs: _PcapWrapper_pypcap(*args,**kargs)
168+
class PcapTimeoutElapsed(Scapy_Exception):
169+
pass
170+
171+
class L2pcapListenSocket(SuperSocket):
172+
desc = "read packets at layer 2 using libpcap"
173+
def __init__(self, iface = None, type = ETH_P_ALL, promisc=None, filter=None):
174+
self.type = type
175+
self.outs = None
176+
self.iface = iface
177+
if iface is None:
178+
iface = conf.iface
179+
if promisc is None:
180+
promisc = conf.sniff_promisc
181+
self.promisc = promisc
182+
self.ins = open_pcap(iface, 1600, self.promisc, 100)
183+
try:
184+
ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1))
185+
except:
186+
pass
187+
if type == ETH_P_ALL: # Do not apply any filter if Ethernet type is given
188+
if conf.except_filter:
189+
if filter:
190+
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
191+
else:
192+
filter = "not (%s)" % conf.except_filter
193+
if filter:
194+
self.ins.setfilter(filter)
195+
196+
def close(self):
197+
self.ins.close()
198+
199+
def recv(self, x=MTU):
200+
ll = self.ins.datalink()
201+
if ll in conf.l2types:
202+
cls = conf.l2types[ll]
203+
else:
204+
cls = conf.default_l2
205+
warning("Unable to guess datalink type (interface=%s linktype=%i). Using %s" % (self.iface, ll, cls.name))
206+
207+
pkt = None
208+
while pkt is None:
209+
pkt = self.ins.next()
210+
if pkt is not None:
211+
ts,pkt = pkt
212+
if scapy.arch.WINDOWS and pkt is None:
213+
raise PcapTimeoutElapsed
214+
try:
215+
pkt = cls(pkt)
216+
except KeyboardInterrupt:
217+
raise
218+
except:
219+
if conf.debug_dissector:
220+
raise
221+
pkt = conf.raw_layer(pkt)
222+
pkt.time = ts
223+
return pkt
224+
225+
def send(self, x):
226+
raise Scapy_Exception("Can't send anything with L2pcapListenSocket")
227+
228+
229+
conf.L2listen = L2pcapListenSocket
230+
class L2pcapSocket(SuperSocket):
231+
desc = "read/write packets at layer 2 using only libpcap"
232+
def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0):
233+
if iface is None:
234+
iface = conf.iface
235+
self.iface = iface
236+
self.ins = open_pcap(iface, 1600, 0, 100)
237+
try:
238+
ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1))
239+
except:
240+
pass
241+
if nofilter:
242+
if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap
243+
filter = "ether proto %i" % type
244+
else:
245+
filter = None
246+
else:
247+
if conf.except_filter:
248+
if filter:
249+
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
250+
else:
251+
filter = "not (%s)" % conf.except_filter
252+
if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap
253+
if filter:
254+
filter = "(ether proto %i) and (%s)" % (type,filter)
255+
else:
256+
filter = "ether proto %i" % type
257+
if filter:
258+
self.ins.setfilter(filter)
259+
def send(self, x):
260+
sx = str(x)
261+
if hasattr(x, "sent_time"):
262+
x.sent_time = time.time()
263+
return self.ins.send(sx)
264+
265+
def recv(self,x=MTU):
266+
ll = self.ins.datalink()
267+
if ll in conf.l2types:
268+
cls = conf.l2types[ll]
269+
else:
270+
cls = conf.default_l2
271+
warning("Unable to guess datalink type (interface=%s linktype=%i). Using %s" % (self.iface, ll, cls.name))
272+
273+
pkt = self.ins.next()
274+
if pkt is not None:
275+
ts,pkt = pkt
276+
if pkt is None:
277+
return
278+
279+
try:
280+
pkt = cls(pkt)
281+
except KeyboardInterrupt:
282+
raise
283+
except:
284+
if conf.debug_dissector:
285+
raise
286+
pkt = conf.raw_layer(pkt)
287+
pkt.time = ts
288+
return pkt
289+
290+
def nonblock_recv(self):
291+
self.ins.setnonblock(1)
292+
p = self.recv(MTU)
293+
self.ins.setnonblock(0)
294+
return p
295+
296+
def close(self):
297+
if hasattr(self, "ins"):
298+
self.ins.close()
299+
if hasattr(self, "outs"):
300+
self.outs.close()
301+
302+
class L3pcapSocket(L2pcapSocket):
303+
#def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0):
304+
# L2pcapSocket.__init__(self, iface, type, filter, nofilter)
305+
def recv(self, x = MTU):
306+
r = L2pcapSocket.recv(self, x)
307+
if r:
308+
return r.payload
309+
else:
310+
return
311+
def send(self, x):
312+
cls = conf.l2types[1]
313+
sx = str(cls()/x)
314+
if hasattr(x, "sent_time"):
315+
x.sent_time = time.time()
316+
return self.ins.send(sx)
317+
conf.L2socket=L2pcapSocket
318+
conf.L3socket=L3pcapSocket
319+
22320
if conf.use_pcap:
23321

24322

0 commit comments

Comments
 (0)