xref: /aosp_15_r20/external/scapy/scapy/scapypipes.py (revision 7dc08ffc4802948ccbc861daaf1e81c405c2c4bd)
1*7dc08ffcSJunyu Lai## This file is part of Scapy
2*7dc08ffcSJunyu Lai## See http://www.secdev.org/projects/scapy for more informations
3*7dc08ffcSJunyu Lai## Copyright (C) Philippe Biondi <[email protected]>
4*7dc08ffcSJunyu Lai## This program is published under a GPLv2 license
5*7dc08ffcSJunyu Lai
6*7dc08ffcSJunyu Laifrom __future__ import print_function
7*7dc08ffcSJunyu Laiimport socket
8*7dc08ffcSJunyu Laifrom scapy.modules.six.moves.queue import Queue, Empty
9*7dc08ffcSJunyu Laifrom scapy.pipetool import Source,Drain,Sink
10*7dc08ffcSJunyu Laifrom scapy.config import conf
11*7dc08ffcSJunyu Laifrom scapy.compat import *
12*7dc08ffcSJunyu Laifrom scapy.utils import PcapReader, PcapWriter
13*7dc08ffcSJunyu Laifrom scapy.automaton import recv_error
14*7dc08ffcSJunyu Lai
15*7dc08ffcSJunyu Laiclass SniffSource(Source):
16*7dc08ffcSJunyu Lai    """Read packets from an interface and send them to low exit.
17*7dc08ffcSJunyu Lai     +-----------+
18*7dc08ffcSJunyu Lai  >>-|           |->>
19*7dc08ffcSJunyu Lai     |           |
20*7dc08ffcSJunyu Lai   >-|  [iface]--|->
21*7dc08ffcSJunyu Lai     +-----------+
22*7dc08ffcSJunyu Lai"""
23*7dc08ffcSJunyu Lai    def __init__(self, iface=None, filter=None, name=None):
24*7dc08ffcSJunyu Lai        Source.__init__(self, name=name)
25*7dc08ffcSJunyu Lai        self.iface = iface
26*7dc08ffcSJunyu Lai        self.filter = filter
27*7dc08ffcSJunyu Lai    def start(self):
28*7dc08ffcSJunyu Lai        self.s = conf.L2listen(iface=self.iface, filter=self.filter)
29*7dc08ffcSJunyu Lai    def stop(self):
30*7dc08ffcSJunyu Lai        self.s.close()
31*7dc08ffcSJunyu Lai    def fileno(self):
32*7dc08ffcSJunyu Lai        return self.s.fileno()
33*7dc08ffcSJunyu Lai    def check_recv(self):
34*7dc08ffcSJunyu Lai        return True
35*7dc08ffcSJunyu Lai    def deliver(self):
36*7dc08ffcSJunyu Lai        try:
37*7dc08ffcSJunyu Lai            self._send(self.s.recv())
38*7dc08ffcSJunyu Lai        except recv_error:
39*7dc08ffcSJunyu Lai            if not WINDOWS:
40*7dc08ffcSJunyu Lai                raise
41*7dc08ffcSJunyu Lai
42*7dc08ffcSJunyu Laiclass RdpcapSource(Source):
43*7dc08ffcSJunyu Lai    """Read packets from a PCAP file send them to low exit.
44*7dc08ffcSJunyu Lai     +----------+
45*7dc08ffcSJunyu Lai  >>-|          |->>
46*7dc08ffcSJunyu Lai     |          |
47*7dc08ffcSJunyu Lai   >-|  [pcap]--|->
48*7dc08ffcSJunyu Lai     +----------+
49*7dc08ffcSJunyu Lai"""
50*7dc08ffcSJunyu Lai    def __init__(self, fname, name=None):
51*7dc08ffcSJunyu Lai        Source.__init__(self, name=name)
52*7dc08ffcSJunyu Lai        self.fname = fname
53*7dc08ffcSJunyu Lai        self.f = PcapReader(self.fname)
54*7dc08ffcSJunyu Lai    def start(self):
55*7dc08ffcSJunyu Lai        print("start")
56*7dc08ffcSJunyu Lai        self.f = PcapReader(self.fname)
57*7dc08ffcSJunyu Lai        self.is_exhausted = False
58*7dc08ffcSJunyu Lai    def stop(self):
59*7dc08ffcSJunyu Lai        print("stop")
60*7dc08ffcSJunyu Lai        self.f.close()
61*7dc08ffcSJunyu Lai    def fileno(self):
62*7dc08ffcSJunyu Lai        return self.f.fileno()
63*7dc08ffcSJunyu Lai    def check_recv(self):
64*7dc08ffcSJunyu Lai        return True
65*7dc08ffcSJunyu Lai    def deliver(self):
66*7dc08ffcSJunyu Lai        p = self.f.recv()
67*7dc08ffcSJunyu Lai        print("deliver %r" % p)
68*7dc08ffcSJunyu Lai        if p is None:
69*7dc08ffcSJunyu Lai            self.is_exhausted = True
70*7dc08ffcSJunyu Lai        else:
71*7dc08ffcSJunyu Lai            self._send(p)
72*7dc08ffcSJunyu Lai
73*7dc08ffcSJunyu Lai
74*7dc08ffcSJunyu Laiclass InjectSink(Sink):
75*7dc08ffcSJunyu Lai    """Packets received on low input are injected to an interface
76*7dc08ffcSJunyu Lai     +-----------+
77*7dc08ffcSJunyu Lai  >>-|           |->>
78*7dc08ffcSJunyu Lai     |           |
79*7dc08ffcSJunyu Lai   >-|--[iface]  |->
80*7dc08ffcSJunyu Lai     +-----------+
81*7dc08ffcSJunyu Lai"""
82*7dc08ffcSJunyu Lai    def __init__(self, iface=None, name=None):
83*7dc08ffcSJunyu Lai        Sink.__init__(self, name=name)
84*7dc08ffcSJunyu Lai        if iface == None:
85*7dc08ffcSJunyu Lai            iface = conf.iface
86*7dc08ffcSJunyu Lai        self.iface = iface
87*7dc08ffcSJunyu Lai    def start(self):
88*7dc08ffcSJunyu Lai        self.s = conf.L2socket(iface=self.iface)
89*7dc08ffcSJunyu Lai    def stop(self):
90*7dc08ffcSJunyu Lai        self.s.close()
91*7dc08ffcSJunyu Lai    def push(self, msg):
92*7dc08ffcSJunyu Lai        self.s.send(msg)
93*7dc08ffcSJunyu Lai
94*7dc08ffcSJunyu Laiclass Inject3Sink(InjectSink):
95*7dc08ffcSJunyu Lai    def start(self):
96*7dc08ffcSJunyu Lai        self.s = conf.L3socket(iface=self.iface)
97*7dc08ffcSJunyu Lai
98*7dc08ffcSJunyu Lai
99*7dc08ffcSJunyu Laiclass WrpcapSink(Sink):
100*7dc08ffcSJunyu Lai    """Packets received on low input are written to PCA file
101*7dc08ffcSJunyu Lai     +----------+
102*7dc08ffcSJunyu Lai  >>-|          |->>
103*7dc08ffcSJunyu Lai     |          |
104*7dc08ffcSJunyu Lai   >-|--[pcap]  |->
105*7dc08ffcSJunyu Lai     +----------+
106*7dc08ffcSJunyu Lai"""
107*7dc08ffcSJunyu Lai    def __init__(self, fname, name=None):
108*7dc08ffcSJunyu Lai        Sink.__init__(self, name=name)
109*7dc08ffcSJunyu Lai        self.f = PcapWriter(fname)
110*7dc08ffcSJunyu Lai    def stop(self):
111*7dc08ffcSJunyu Lai        self.f.flush()
112*7dc08ffcSJunyu Lai        self.f.close()
113*7dc08ffcSJunyu Lai    def push(self, msg):
114*7dc08ffcSJunyu Lai        self.f.write(msg)
115*7dc08ffcSJunyu Lai
116*7dc08ffcSJunyu Lai
117*7dc08ffcSJunyu Laiclass UDPDrain(Drain):
118*7dc08ffcSJunyu Lai    """UDP payloads received on high entry are sent over UDP
119*7dc08ffcSJunyu Lai     +-------------+
120*7dc08ffcSJunyu Lai  >>-|--[payload]--|->>
121*7dc08ffcSJunyu Lai     |      X      |
122*7dc08ffcSJunyu Lai   >-|----[UDP]----|->
123*7dc08ffcSJunyu Lai     +-------------+
124*7dc08ffcSJunyu Lai"""
125*7dc08ffcSJunyu Lai    def __init__(self, ip="127.0.0.1", port=1234):
126*7dc08ffcSJunyu Lai        Drain.__init__(self)
127*7dc08ffcSJunyu Lai        self.ip = ip
128*7dc08ffcSJunyu Lai        self.port = port
129*7dc08ffcSJunyu Lai
130*7dc08ffcSJunyu Lai    def push(self, msg):
131*7dc08ffcSJunyu Lai        from scapy.layers.inet import IP, UDP
132*7dc08ffcSJunyu Lai        if IP in msg and msg[IP].proto == 17 and UDP in msg:
133*7dc08ffcSJunyu Lai            payload = msg[UDP].payload
134*7dc08ffcSJunyu Lai            self._high_send(raw(payload))
135*7dc08ffcSJunyu Lai    def high_push(self, msg):
136*7dc08ffcSJunyu Lai        from scapy.layers.inet import IP, UDP
137*7dc08ffcSJunyu Lai        p = IP(dst=self.ip)/UDP(sport=1234,dport=self.port)/msg
138*7dc08ffcSJunyu Lai        self._send(p)
139*7dc08ffcSJunyu Lai
140*7dc08ffcSJunyu Lai
141*7dc08ffcSJunyu Laiclass FDSourceSink(Source):
142*7dc08ffcSJunyu Lai    """Use a file descriptor as source and sink
143*7dc08ffcSJunyu Lai     +-------------+
144*7dc08ffcSJunyu Lai  >>-|             |->>
145*7dc08ffcSJunyu Lai     |             |
146*7dc08ffcSJunyu Lai   >-|-[file desc]-|->
147*7dc08ffcSJunyu Lai     +-------------+
148*7dc08ffcSJunyu Lai"""
149*7dc08ffcSJunyu Lai    def __init__(self, fd, name=None):
150*7dc08ffcSJunyu Lai        Source.__init__(self, name=name)
151*7dc08ffcSJunyu Lai        self.fd = fd
152*7dc08ffcSJunyu Lai    def push(self, msg):
153*7dc08ffcSJunyu Lai        self.fd.write(msg)
154*7dc08ffcSJunyu Lai    def fileno(self):
155*7dc08ffcSJunyu Lai        return self.fd.fileno()
156*7dc08ffcSJunyu Lai    def deliver(self):
157*7dc08ffcSJunyu Lai        self._send(self.fd.read())
158*7dc08ffcSJunyu Lai
159*7dc08ffcSJunyu Lai
160*7dc08ffcSJunyu Laiclass TCPConnectPipe(Source):
161*7dc08ffcSJunyu Lai    """TCP connect to addr:port and use it as source and sink
162*7dc08ffcSJunyu Lai     +-------------+
163*7dc08ffcSJunyu Lai  >>-|             |->>
164*7dc08ffcSJunyu Lai     |             |
165*7dc08ffcSJunyu Lai   >-|-[addr:port]-|->
166*7dc08ffcSJunyu Lai     +-------------+
167*7dc08ffcSJunyu Lai"""
168*7dc08ffcSJunyu Lai    __selectable_force_select__ = True
169*7dc08ffcSJunyu Lai    def __init__(self, addr="", port=0, name=None):
170*7dc08ffcSJunyu Lai        Source.__init__(self, name=name)
171*7dc08ffcSJunyu Lai        self.addr = addr
172*7dc08ffcSJunyu Lai        self.port = port
173*7dc08ffcSJunyu Lai        self.fd = None
174*7dc08ffcSJunyu Lai    def start(self):
175*7dc08ffcSJunyu Lai        self.fd = socket.socket()
176*7dc08ffcSJunyu Lai        self.fd.connect((self.addr,self.port))
177*7dc08ffcSJunyu Lai    def stop(self):
178*7dc08ffcSJunyu Lai        if self.fd:
179*7dc08ffcSJunyu Lai            self.fd.close()
180*7dc08ffcSJunyu Lai    def push(self, msg):
181*7dc08ffcSJunyu Lai        self.fd.send(msg)
182*7dc08ffcSJunyu Lai    def fileno(self):
183*7dc08ffcSJunyu Lai        return self.fd.fileno()
184*7dc08ffcSJunyu Lai    def deliver(self):
185*7dc08ffcSJunyu Lai        try:
186*7dc08ffcSJunyu Lai            msg = self.fd.recv(65536)
187*7dc08ffcSJunyu Lai        except socket.error:
188*7dc08ffcSJunyu Lai            self.stop()
189*7dc08ffcSJunyu Lai            raise
190*7dc08ffcSJunyu Lai        if msg:
191*7dc08ffcSJunyu Lai            self._send(msg)
192*7dc08ffcSJunyu Lai
193*7dc08ffcSJunyu Laiclass TCPListenPipe(TCPConnectPipe):
194*7dc08ffcSJunyu Lai    """TCP listen on [addr:]port and use first connection as source and sink ; send peer address to high output
195*7dc08ffcSJunyu Lai     +------^------+
196*7dc08ffcSJunyu Lai  >>-|    +-[peer]-|->>
197*7dc08ffcSJunyu Lai     |   /         |
198*7dc08ffcSJunyu Lai   >-|-[addr:port]-|->
199*7dc08ffcSJunyu Lai     +-------------+
200*7dc08ffcSJunyu Lai"""
201*7dc08ffcSJunyu Lai    __selectable_force_select__ = True
202*7dc08ffcSJunyu Lai    def __init__(self, addr="", port=0, name=None):
203*7dc08ffcSJunyu Lai        TCPConnectPipe.__init__(self, addr, port, name)
204*7dc08ffcSJunyu Lai        self.connected = False
205*7dc08ffcSJunyu Lai        self.q = Queue()
206*7dc08ffcSJunyu Lai    def start(self):
207*7dc08ffcSJunyu Lai        self.connected = False
208*7dc08ffcSJunyu Lai        self.fd = socket.socket()
209*7dc08ffcSJunyu Lai        self.fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
210*7dc08ffcSJunyu Lai        self.fd.bind((self.addr,self.port))
211*7dc08ffcSJunyu Lai        self.fd.listen(1)
212*7dc08ffcSJunyu Lai    def push(self, msg):
213*7dc08ffcSJunyu Lai        if self.connected:
214*7dc08ffcSJunyu Lai            self.fd.send(msg)
215*7dc08ffcSJunyu Lai        else:
216*7dc08ffcSJunyu Lai            self.q.put(msg)
217*7dc08ffcSJunyu Lai    def deliver(self):
218*7dc08ffcSJunyu Lai        if self.connected:
219*7dc08ffcSJunyu Lai            try:
220*7dc08ffcSJunyu Lai                msg = self.fd.recv(65536)
221*7dc08ffcSJunyu Lai            except socket.error:
222*7dc08ffcSJunyu Lai                self.stop()
223*7dc08ffcSJunyu Lai                raise
224*7dc08ffcSJunyu Lai            if msg:
225*7dc08ffcSJunyu Lai                self._send(msg)
226*7dc08ffcSJunyu Lai        else:
227*7dc08ffcSJunyu Lai            fd,frm = self.fd.accept()
228*7dc08ffcSJunyu Lai            self._high_send(frm)
229*7dc08ffcSJunyu Lai            self.fd.close()
230*7dc08ffcSJunyu Lai            self.fd = fd
231*7dc08ffcSJunyu Lai            self.connected = True
232*7dc08ffcSJunyu Lai            self._trigger(frm)
233*7dc08ffcSJunyu Lai            while True:
234*7dc08ffcSJunyu Lai                try:
235*7dc08ffcSJunyu Lai                    self.fd.send(self.q.get(block=False))
236*7dc08ffcSJunyu Lai                except Empty:
237*7dc08ffcSJunyu Lai                    break
238*7dc08ffcSJunyu Lai
239*7dc08ffcSJunyu Lai
240*7dc08ffcSJunyu Laiclass TriggeredMessage(Drain):
241*7dc08ffcSJunyu Lai    """Send a preloaded message when triggered and trigger in chain
242*7dc08ffcSJunyu Lai     +------^------+
243*7dc08ffcSJunyu Lai  >>-|      | /----|->>
244*7dc08ffcSJunyu Lai     |      |/     |
245*7dc08ffcSJunyu Lai   >-|-[ message ]-|->
246*7dc08ffcSJunyu Lai     +------^------+
247*7dc08ffcSJunyu Lai"""
248*7dc08ffcSJunyu Lai    def __init__(self, msg, name=None):
249*7dc08ffcSJunyu Lai        Drain.__init__(self, name=name)
250*7dc08ffcSJunyu Lai        self.msg = msg
251*7dc08ffcSJunyu Lai    def on_trigger(self, trigmsg):
252*7dc08ffcSJunyu Lai        self._send(self.msg)
253*7dc08ffcSJunyu Lai        self._high_send(self.msg)
254*7dc08ffcSJunyu Lai        self._trigger(trigmsg)
255*7dc08ffcSJunyu Lai
256*7dc08ffcSJunyu Laiclass TriggerDrain(Drain):
257*7dc08ffcSJunyu Lai    """Pass messages and trigger when a condition is met
258*7dc08ffcSJunyu Lai     +------^------+
259*7dc08ffcSJunyu Lai  >>-|-[condition]-|->>
260*7dc08ffcSJunyu Lai     |      |      |
261*7dc08ffcSJunyu Lai   >-|-[condition]-|->
262*7dc08ffcSJunyu Lai     +-------------+
263*7dc08ffcSJunyu Lai"""
264*7dc08ffcSJunyu Lai    def __init__(self, f, name=None):
265*7dc08ffcSJunyu Lai        Drain.__init__(self, name=name)
266*7dc08ffcSJunyu Lai        self.f = f
267*7dc08ffcSJunyu Lai    def push(self, msg):
268*7dc08ffcSJunyu Lai        v = self.f(msg)
269*7dc08ffcSJunyu Lai        if v:
270*7dc08ffcSJunyu Lai            self._trigger(v)
271*7dc08ffcSJunyu Lai        self._send(msg)
272*7dc08ffcSJunyu Lai    def high_push(self, msg):
273*7dc08ffcSJunyu Lai        v = self.f(msg)
274*7dc08ffcSJunyu Lai        if v:
275*7dc08ffcSJunyu Lai            self._trigger(v)
276*7dc08ffcSJunyu Lai        self._high_send(msg)
277*7dc08ffcSJunyu Lai
278*7dc08ffcSJunyu Laiclass TriggeredValve(Drain):
279*7dc08ffcSJunyu Lai    """Let messages alternatively pass or not, changing on trigger
280*7dc08ffcSJunyu Lai     +------^------+
281*7dc08ffcSJunyu Lai  >>-|-[pass/stop]-|->>
282*7dc08ffcSJunyu Lai     |      |      |
283*7dc08ffcSJunyu Lai   >-|-[pass/stop]-|->
284*7dc08ffcSJunyu Lai     +------^------+
285*7dc08ffcSJunyu Lai"""
286*7dc08ffcSJunyu Lai    def __init__(self, start_state=True, name=None):
287*7dc08ffcSJunyu Lai        Drain.__init__(self, name=name)
288*7dc08ffcSJunyu Lai        self.opened = start_state
289*7dc08ffcSJunyu Lai    def push(self, msg):
290*7dc08ffcSJunyu Lai        if self.opened:
291*7dc08ffcSJunyu Lai            self._send(msg)
292*7dc08ffcSJunyu Lai    def high_push(self, msg):
293*7dc08ffcSJunyu Lai        if self.opened:
294*7dc08ffcSJunyu Lai            self._high_send(msg)
295*7dc08ffcSJunyu Lai    def on_trigger(self, msg):
296*7dc08ffcSJunyu Lai        self.opened ^= True
297*7dc08ffcSJunyu Lai        self._trigger(msg)
298*7dc08ffcSJunyu Lai
299*7dc08ffcSJunyu Laiclass TriggeredQueueingValve(Drain):
300*7dc08ffcSJunyu Lai    """Let messages alternatively pass or queued, changing on trigger
301*7dc08ffcSJunyu Lai     +------^-------+
302*7dc08ffcSJunyu Lai  >>-|-[pass/queue]-|->>
303*7dc08ffcSJunyu Lai     |      |       |
304*7dc08ffcSJunyu Lai   >-|-[pass/queue]-|->
305*7dc08ffcSJunyu Lai     +------^-------+
306*7dc08ffcSJunyu Lai"""
307*7dc08ffcSJunyu Lai    def __init__(self, start_state=True, name=None):
308*7dc08ffcSJunyu Lai        Drain.__init__(self, name=name)
309*7dc08ffcSJunyu Lai        self.opened = start_state
310*7dc08ffcSJunyu Lai        self.q = Queue()
311*7dc08ffcSJunyu Lai    def start(self):
312*7dc08ffcSJunyu Lai        self.q = Queue()
313*7dc08ffcSJunyu Lai    def push(self, msg):
314*7dc08ffcSJunyu Lai        if self.opened:
315*7dc08ffcSJunyu Lai            self._send(msg)
316*7dc08ffcSJunyu Lai        else:
317*7dc08ffcSJunyu Lai            self.q.put((True,msg))
318*7dc08ffcSJunyu Lai    def high_push(self, msg):
319*7dc08ffcSJunyu Lai        if self.opened:
320*7dc08ffcSJunyu Lai            self._send(msg)
321*7dc08ffcSJunyu Lai        else:
322*7dc08ffcSJunyu Lai            self.q.put((False,msg))
323*7dc08ffcSJunyu Lai    def on_trigger(self, msg):
324*7dc08ffcSJunyu Lai        self.opened ^= True
325*7dc08ffcSJunyu Lai        self._trigger(msg)
326*7dc08ffcSJunyu Lai        while True:
327*7dc08ffcSJunyu Lai            try:
328*7dc08ffcSJunyu Lai                low,msg = self.q.get(block=False)
329*7dc08ffcSJunyu Lai            except Empty:
330*7dc08ffcSJunyu Lai                break
331*7dc08ffcSJunyu Lai            else:
332*7dc08ffcSJunyu Lai                if low:
333*7dc08ffcSJunyu Lai                    self._send(msg)
334*7dc08ffcSJunyu Lai                else:
335*7dc08ffcSJunyu Lai                    self._high_send(msg)
336*7dc08ffcSJunyu Lai
337*7dc08ffcSJunyu Laiclass TriggeredSwitch(Drain):
338*7dc08ffcSJunyu Lai    """Let messages alternatively high or low, changing on trigger
339*7dc08ffcSJunyu Lai     +------^------+
340*7dc08ffcSJunyu Lai  >>-|-\    |    /-|->>
341*7dc08ffcSJunyu Lai     |  [up/down]  |
342*7dc08ffcSJunyu Lai   >-|-/    |    \-|->
343*7dc08ffcSJunyu Lai     +------^------+
344*7dc08ffcSJunyu Lai"""
345*7dc08ffcSJunyu Lai    def __init__(self, start_state=True, name=None):
346*7dc08ffcSJunyu Lai        Drain.__init__(self, name=name)
347*7dc08ffcSJunyu Lai        self.low = start_state
348*7dc08ffcSJunyu Lai    def push(self, msg):
349*7dc08ffcSJunyu Lai        if self.low:
350*7dc08ffcSJunyu Lai            self._send(msg)
351*7dc08ffcSJunyu Lai        else:
352*7dc08ffcSJunyu Lai            self._high_send(msg)
353*7dc08ffcSJunyu Lai    high_push = push
354*7dc08ffcSJunyu Lai    def on_trigger(self, msg):
355*7dc08ffcSJunyu Lai        self.low ^= True
356*7dc08ffcSJunyu Lai        self._trigger(msg)
357