1## This file is part of Scapy 2## See http://www.secdev.org/projects/scapy for more informations 3## Copyright (C) Philippe Biondi <phil@secdev.org> 4## This program is published under a GPLv2 license 5 6""" 7SuperSocket. 8""" 9 10from __future__ import absolute_import 11import os 12import socket 13import subprocess 14import struct 15import time 16 17from scapy.config import conf 18from scapy.consts import LINUX, OPENBSD, BSD, DARWIN, WINDOWS 19from scapy.data import * 20from scapy.compat import * 21from scapy.error import warning, log_runtime 22import scapy.modules.six as six 23import scapy.packet 24from scapy.utils import PcapReader, tcpdump 25 26class _SuperSocket_metaclass(type): 27 def __repr__(self): 28 if self.desc is not None: 29 return "<%s: %s>" % (self.__name__,self.desc) 30 else: 31 return "<%s>" % self.__name__ 32 33 34class SuperSocket(six.with_metaclass(_SuperSocket_metaclass)): 35 desc = None 36 closed=0 37 def __init__(self, family=socket.AF_INET,type=socket.SOCK_STREAM, proto=0): 38 self.ins = socket.socket(family, type, proto) 39 self.outs = self.ins 40 self.promisc=None 41 def send(self, x): 42 sx = raw(x) 43 if hasattr(x, "sent_time"): 44 x.sent_time = time.time() 45 return self.outs.send(sx) 46 def recv(self, x=MTU): 47 return conf.raw_layer(self.ins.recv(x)) 48 def fileno(self): 49 return self.ins.fileno() 50 def close(self): 51 if self.closed: 52 return 53 self.closed = True 54 if hasattr(self, "outs"): 55 if not hasattr(self, "ins") or self.ins != self.outs: 56 if self.outs and self.outs.fileno() != -1: 57 self.outs.close() 58 if hasattr(self, "ins"): 59 if self.ins and self.ins.fileno() != -1: 60 self.ins.close() 61 def sr(self, *args, **kargs): 62 from scapy import sendrecv 63 return sendrecv.sndrcv(self, *args, **kargs) 64 def sr1(self, *args, **kargs): 65 from scapy import sendrecv 66 a,b = sendrecv.sndrcv(self, *args, **kargs) 67 if len(a) > 0: 68 return a[0][1] 69 else: 70 return None 71 def sniff(self, *args, **kargs): 72 from scapy import sendrecv 73 return sendrecv.sniff(opened_socket=self, *args, **kargs) 74 75class L3RawSocket(SuperSocket): 76 desc = "Layer 3 using Raw sockets (PF_INET/SOCK_RAW)" 77 def __init__(self, type = ETH_P_IP, filter=None, iface=None, promisc=None, nofilter=0): 78 self.outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) 79 self.outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1) 80 self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) 81 if iface is not None: 82 self.ins.bind((iface, type)) 83 def recv(self, x=MTU): 84 pkt, sa_ll = self.ins.recvfrom(x) 85 if sa_ll[2] == socket.PACKET_OUTGOING: 86 return None 87 if sa_ll[3] in conf.l2types: 88 cls = conf.l2types[sa_ll[3]] 89 lvl = 2 90 elif sa_ll[1] in conf.l3types: 91 cls = conf.l3types[sa_ll[1]] 92 lvl = 3 93 else: 94 cls = conf.default_l2 95 warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s", sa_ll[0], sa_ll[1], sa_ll[3], cls.name) 96 lvl = 3 97 98 try: 99 pkt = cls(pkt) 100 except KeyboardInterrupt: 101 raise 102 except: 103 if conf.debug_dissector: 104 raise 105 pkt = conf.raw_layer(pkt) 106 if lvl == 2: 107 pkt = pkt.payload 108 109 if pkt is not None: 110 from scapy.arch import get_last_packet_timestamp 111 pkt.time = get_last_packet_timestamp(self.ins) 112 return pkt 113 def send(self, x): 114 try: 115 sx = raw(x) 116 x.sent_time = time.time() 117 self.outs.sendto(sx,(x.dst,0)) 118 except socket.error as msg: 119 log_runtime.error(msg) 120 121class SimpleSocket(SuperSocket): 122 desc = "wrapper around a classic socket" 123 def __init__(self, sock): 124 self.ins = sock 125 self.outs = sock 126 127 128class StreamSocket(SimpleSocket): 129 desc = "transforms a stream socket into a layer 2" 130 def __init__(self, sock, basecls=None): 131 if basecls is None: 132 basecls = conf.raw_layer 133 SimpleSocket.__init__(self, sock) 134 self.basecls = basecls 135 136 def recv(self, x=MTU): 137 pkt = self.ins.recv(x, socket.MSG_PEEK) 138 x = len(pkt) 139 if x == 0: 140 raise socket.error((100,"Underlying stream socket tore down")) 141 pkt = self.basecls(pkt) 142 pad = pkt.getlayer(conf.padding_layer) 143 if pad is not None and pad.underlayer is not None: 144 del(pad.underlayer.payload) 145 from scapy.packet import NoPayload 146 while pad is not None and not isinstance(pad, NoPayload): 147 x -= len(pad.load) 148 pad = pad.payload 149 self.ins.recv(x) 150 return pkt 151 152class SSLStreamSocket(StreamSocket): 153 desc = "similar usage than StreamSocket but specialized for handling SSL-wrapped sockets" 154 155 def __init__(self, sock, basecls=None): 156 self._buf = b"" 157 super(SSLStreamSocket, self).__init__(sock, basecls) 158 159 #65535, the default value of x is the maximum length of a TLS record 160 def recv(self, x=65535): 161 pkt = None 162 if self._buf != b"": 163 try: 164 pkt = self.basecls(self._buf) 165 except: 166 # We assume that the exception is generated by a buffer underflow 167 pass 168 169 if not pkt: 170 buf = self.ins.recv(x) 171 if len(buf) == 0: 172 raise socket.error((100,"Underlying stream socket tore down")) 173 self._buf += buf 174 175 x = len(self._buf) 176 pkt = self.basecls(self._buf) 177 pad = pkt.getlayer(conf.padding_layer) 178 179 if pad is not None and pad.underlayer is not None: 180 del(pad.underlayer.payload) 181 while pad is not None and not isinstance(pad, scapy.packet.NoPayload): 182 x -= len(pad.load) 183 pad = pad.payload 184 self._buf = self._buf[x:] 185 return pkt 186 187 188class L2ListenTcpdump(SuperSocket): 189 desc = "read packets at layer 2 using tcpdump" 190 191 def __init__(self, iface=None, promisc=None, filter=None, nofilter=False, 192 prog=None, *arg, **karg): 193 self.outs = None 194 args = ['-w', '-', '-s', '65535'] 195 if iface is not None: 196 if WINDOWS: 197 try: 198 args.extend(['-i', iface.pcap_name]) 199 except AttributeError: 200 args.extend(['-i', iface]) 201 else: 202 args.extend(['-i', iface]) 203 elif WINDOWS or DARWIN: 204 args.extend(['-i', conf.iface.pcap_name if WINDOWS else conf.iface]) 205 if not promisc: 206 args.append('-p') 207 if not nofilter: 208 if conf.except_filter: 209 if filter: 210 filter = "(%s) and not (%s)" % (filter, conf.except_filter) 211 else: 212 filter = "not (%s)" % conf.except_filter 213 if filter is not None: 214 args.append(filter) 215 self.tcpdump_proc = tcpdump(None, prog=prog, args=args, getproc=True) 216 self.ins = PcapReader(self.tcpdump_proc.stdout) 217 def recv(self, x=MTU): 218 return self.ins.recv(x) 219 def close(self): 220 SuperSocket.close(self) 221 self.tcpdump_proc.kill() 222 223 224class TunTapInterface(SuperSocket): 225 """A socket to act as the host's peer of a tun / tap interface. 226 227 """ 228 desc = "Act as the host's peer of a tun / tap interface" 229 230 def __init__(self, iface=None, mode_tun=None, *arg, **karg): 231 self.iface = conf.iface if iface is None else iface 232 self.mode_tun = ("tun" in iface) if mode_tun is None else mode_tun 233 self.closed = True 234 self.open() 235 236 def __enter__(self): 237 return self 238 239 def __del__(self): 240 self.close() 241 242 def __exit__(self, *_): 243 self.close() 244 245 def open(self): 246 """Open the TUN or TAP device.""" 247 if not self.closed: 248 return 249 self.outs = self.ins = open( 250 "/dev/net/tun" if LINUX else ("/dev/%s" % self.iface), "r+b", 251 buffering=0 252 ) 253 if LINUX: 254 from fcntl import ioctl 255 # TUNSETIFF = 0x400454ca 256 # IFF_TUN = 0x0001 257 # IFF_TAP = 0x0002 258 # IFF_NO_PI = 0x1000 259 ioctl(self.ins, 0x400454ca, struct.pack( 260 "16sH", raw(self.iface), 0x0001 if self.mode_tun else 0x1002, 261 )) 262 self.closed = False 263 264 def __call__(self, *arg, **karg): 265 """Needed when using an instantiated TunTapInterface object for 266conf.L2listen, conf.L2socket or conf.L3socket. 267 268 """ 269 return self 270 271 def recv(self, x=MTU): 272 if self.mode_tun: 273 data = os.read(self.ins.fileno(), x + 4) 274 proto = struct.unpack('!H', data[2:4])[0] 275 return conf.l3types.get(proto, conf.raw_layer)(data[4:]) 276 return conf.l2types.get(1, conf.raw_layer)( 277 os.read(self.ins.fileno(), x) 278 ) 279 280 def send(self, x): 281 sx = raw(x) 282 if hasattr(x, "sent_time"): 283 x.sent_time = time.time() 284 if self.mode_tun: 285 try: 286 proto = conf.l3types[type(x)] 287 except KeyError: 288 log_runtime.warning( 289 "Cannot find layer 3 protocol value to send %s in " 290 "conf.l3types, using 0", 291 x.name if hasattr(x, "name") else type(x).__name__ 292 ) 293 proto = 0 294 sx = struct.pack('!HH', 0, proto) + sx 295 try: 296 os.write(self.outs.fileno(), sx) 297 except socket.error: 298 log_runtime.error("%s send", self.__class__.__name__, exc_info=True) 299 300 301if conf.L3socket is None: 302 conf.L3socket = L3RawSocket 303