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