• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"""
7Linux specific functions.
8"""
9
10from __future__ import absolute_import
11
12
13import array
14import ctypes
15from fcntl import ioctl
16import os
17from select import select
18import socket
19import struct
20import sys
21import time
22
23
24from scapy.compat import *
25from scapy.consts import LOOPBACK_NAME, IS_64BITS
26import scapy.utils
27import scapy.utils6
28from scapy.packet import Packet, Padding
29from scapy.config import conf
30from scapy.data import *
31from scapy.supersocket import SuperSocket
32import scapy.arch
33from scapy.error import warning, Scapy_Exception, log_interactive, log_loading
34from scapy.arch.common import get_if, get_bpf_pointer
35from scapy.modules.six.moves import range
36
37
38
39# From bits/ioctls.h
40SIOCGIFHWADDR  = 0x8927          # Get hardware address
41SIOCGIFADDR    = 0x8915          # get PA address
42SIOCGIFNETMASK = 0x891b          # get network PA mask
43SIOCGIFNAME    = 0x8910          # get iface name
44SIOCSIFLINK    = 0x8911          # set iface channel
45SIOCGIFCONF    = 0x8912          # get iface list
46SIOCGIFFLAGS   = 0x8913          # get flags
47SIOCSIFFLAGS   = 0x8914          # set flags
48SIOCGIFINDEX   = 0x8933          # name -> if_index mapping
49SIOCGIFCOUNT   = 0x8938          # get number of devices
50SIOCGSTAMP     = 0x8906          # get packet timestamp (as a timeval)
51
52# From if.h
53IFF_UP = 0x1               # Interface is up.
54IFF_BROADCAST = 0x2        # Broadcast address valid.
55IFF_DEBUG = 0x4            # Turn on debugging.
56IFF_LOOPBACK = 0x8         # Is a loopback net.
57IFF_POINTOPOINT = 0x10     # Interface is point-to-point link.
58IFF_NOTRAILERS = 0x20      # Avoid use of trailers.
59IFF_RUNNING = 0x40         # Resources allocated.
60IFF_NOARP = 0x80           # No address resolution protocol.
61IFF_PROMISC = 0x100        # Receive all packets.
62
63# From netpacket/packet.h
64PACKET_ADD_MEMBERSHIP  = 1
65PACKET_DROP_MEMBERSHIP = 2
66PACKET_RECV_OUTPUT     = 3
67PACKET_RX_RING         = 5
68PACKET_STATISTICS      = 6
69PACKET_MR_MULTICAST    = 0
70PACKET_MR_PROMISC      = 1
71PACKET_MR_ALLMULTI     = 2
72
73# From bits/socket.h
74SOL_PACKET = 263
75# From asm/socket.h
76SO_ATTACH_FILTER = 26
77
78# From net/route.h
79RTF_UP = 0x0001  # Route usable
80RTF_REJECT = 0x0200
81
82# From if_packet.h
83PACKET_HOST = 0  # To us
84PACKET_BROADCAST = 1  # To all
85PACKET_MULTICAST = 2  # To group
86PACKET_OTHERHOST = 3  # To someone else
87PACKET_OUTGOING = 4  # Outgoing of any type
88PACKET_LOOPBACK = 5  # MC/BRD frame looped back
89PACKET_USER = 6  # To user space
90PACKET_KERNEL = 7  # To kernel space
91PACKET_FASTROUTE = 6  # Fastrouted frame
92# Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space
93
94
95with os.popen("%s -V 2> /dev/null" % conf.prog.tcpdump) as _f:
96    if _f.close() >> 8 == 0x7f:
97        log_loading.warning("Failed to execute tcpdump. Check it is installed and in the PATH")
98        TCPDUMP=0
99    else:
100        TCPDUMP=1
101del(_f)
102
103
104def get_if_raw_hwaddr(iff):
105    return struct.unpack("16xh6s8x",get_if(iff,SIOCGIFHWADDR))
106
107def get_if_raw_addr(iff):
108    try:
109        return get_if(iff, SIOCGIFADDR)[20:24]
110    except IOError:
111        return b"\0\0\0\0"
112
113
114def get_if_list():
115    try:
116        f=open("/proc/net/dev", "rb")
117    except IOError:
118        warning("Can't open /proc/net/dev !")
119        return []
120    lst = []
121    f.readline()
122    f.readline()
123    for l in f:
124        l = plain_str(l)
125        lst.append(l.split(":")[0].strip())
126    return lst
127def get_working_if():
128    for i in get_if_list():
129        if i == LOOPBACK_NAME:
130            continue
131        ifflags = struct.unpack("16xH14x",get_if(i,SIOCGIFFLAGS))[0]
132        if ifflags & IFF_UP:
133            return i
134    return LOOPBACK_NAME
135
136def attach_filter(s, bpf_filter, iface):
137    # XXX We generate the filter on the interface conf.iface
138    # because tcpdump open the "any" interface and ppp interfaces
139    # in cooked mode. As we use them in raw mode, the filter will not
140    # work... one solution could be to use "any" interface and translate
141    # the filter from cooked mode to raw mode
142    # mode
143    if not TCPDUMP:
144        return
145    try:
146        f = os.popen("%s -i %s -ddd -s %d '%s'" % (
147            conf.prog.tcpdump,
148            conf.iface if iface is None else iface,
149            MTU,
150            bpf_filter,
151        ))
152    except OSError:
153        log_interactive.warning("Failed to attach filter.",
154                                exc_info=True)
155        return
156    lines = f.readlines()
157    ret = f.close()
158    if ret:
159        log_interactive.warning(
160            "Failed to attach filter: tcpdump returned %d", ret
161        )
162        return
163
164    bp = get_bpf_pointer(lines)
165    s.setsockopt(socket.SOL_SOCKET, SO_ATTACH_FILTER, bp)
166
167def set_promisc(s,iff,val=1):
168    mreq = struct.pack("IHH8s", get_if_index(iff), PACKET_MR_PROMISC, 0, b"")
169    if val:
170        cmd = PACKET_ADD_MEMBERSHIP
171    else:
172        cmd = PACKET_DROP_MEMBERSHIP
173    s.setsockopt(SOL_PACKET, cmd, mreq)
174
175
176def get_alias_address(iface_name, ip_mask, gw_str, metric):
177    """
178    Get the correct source IP address of an interface alias
179    """
180
181    # Detect the architecture
182    if scapy.consts.IS_64BITS:
183        offset, name_len = 16, 40
184    else:
185        offset, name_len = 32, 32
186
187    # Retrieve interfaces structures
188    sck = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
189    names = array.array('B', b'\0' * 4096)
190    ifreq = ioctl(sck.fileno(), SIOCGIFCONF,
191                  struct.pack("iL", len(names), names.buffer_info()[0]))
192
193    # Extract interfaces names
194    out = struct.unpack("iL", ifreq)[0]
195    names = names.tostring()
196    names = [names[i:i+offset].split(b'\0', 1)[0] for i in range(0, out, name_len)]
197
198    # Look for the IP address
199    for ifname in names:
200        # Only look for a matching interface name
201        if not ifname.decode("utf8").startswith(iface_name):
202            continue
203
204        # Retrieve and convert addresses
205        ifreq = ioctl(sck, SIOCGIFADDR, struct.pack("16s16x", ifname))
206        ifaddr = struct.unpack(">I", ifreq[20:24])[0]
207        ifreq = ioctl(sck, SIOCGIFNETMASK, struct.pack("16s16x", ifname))
208        msk = struct.unpack(">I", ifreq[20:24])[0]
209
210        # Get the full interface name
211        ifname = plain_str(ifname)
212        if ':' in ifname:
213            ifname = ifname[:ifname.index(':')]
214        else:
215            continue
216
217        # Check if the source address is included in the network
218        if (ifaddr & msk) == ip_mask:
219            sck.close()
220            return (ifaddr & msk, msk, gw_str, ifname,
221                    scapy.utils.ltoa(ifaddr), metric)
222
223    sck.close()
224    return
225
226
227def read_routes():
228    try:
229        f=open("/proc/net/route", "rb")
230    except IOError:
231        warning("Can't open /proc/net/route !")
232        return []
233    routes = []
234    s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
235    ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x", LOOPBACK_NAME.encode("utf8")))
236    addrfamily = struct.unpack("h",ifreq[16:18])[0]
237    if addrfamily == socket.AF_INET:
238        ifreq2 = ioctl(s, SIOCGIFNETMASK,struct.pack("16s16x", LOOPBACK_NAME.encode("utf8")))
239        msk = socket.ntohl(struct.unpack("I",ifreq2[20:24])[0])
240        dst = socket.ntohl(struct.unpack("I",ifreq[20:24])[0]) & msk
241        ifaddr = scapy.utils.inet_ntoa(ifreq[20:24])
242        routes.append((dst, msk, "0.0.0.0", LOOPBACK_NAME, ifaddr, 1))
243    else:
244        warning("Interface lo: unkown address family (%i)"% addrfamily)
245
246    for l in f.readlines()[1:]:
247        l = plain_str(l)
248        iff,dst,gw,flags,x,x,metric,msk,x,x,x = l.split()
249        flags = int(flags,16)
250        if flags & RTF_UP == 0:
251            continue
252        if flags & RTF_REJECT:
253            continue
254        try:
255            ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x", iff.encode("utf8")))
256        except IOError: # interface is present in routing tables but does not have any assigned IP
257            ifaddr="0.0.0.0"
258        else:
259            addrfamily = struct.unpack("h",ifreq[16:18])[0]
260            if addrfamily == socket.AF_INET:
261                ifaddr = scapy.utils.inet_ntoa(ifreq[20:24])
262            else:
263                warning("Interface %s: unkown address family (%i)", iff, addrfamily)
264                continue
265
266        # Attempt to detect an interface alias based on addresses inconsistencies
267        dst_int = socket.htonl(int(dst, 16)) & 0xffffffff
268        msk_int = socket.htonl(int(msk, 16)) & 0xffffffff
269        ifaddr_int = struct.unpack("!I", ifreq[20:24])[0]
270        gw_str = scapy.utils.inet_ntoa(struct.pack("I", int(gw, 16)))
271        metric = int(metric)
272
273        if ifaddr_int & msk_int != dst_int:
274            tmp_route = get_alias_address(iff, dst_int, gw_str, metric)
275            if tmp_route:
276                routes.append(tmp_route)
277            else:
278                routes.append((dst_int, msk_int, gw_str, iff, ifaddr, metric))
279
280        else:
281            routes.append((dst_int, msk_int, gw_str, iff, ifaddr, metric))
282
283    f.close()
284    return routes
285
286############
287### IPv6 ###
288############
289
290def in6_getifaddr():
291    """
292    Returns a list of 3-tuples of the form (addr, scope, iface) where
293    'addr' is the address of scope 'scope' associated to the interface
294    'ifcace'.
295
296    This is the list of all addresses of all interfaces available on
297    the system.
298    """
299    ret = []
300    try:
301        fdesc = open("/proc/net/if_inet6", "rb")
302    except IOError as err:
303        return ret
304    for line in fdesc:
305        # addr, index, plen, scope, flags, ifname
306        tmp = plain_str(line).split()
307        addr = scapy.utils6.in6_ptop(
308            b':'.join(
309                struct.unpack('4s4s4s4s4s4s4s4s', tmp[0].encode())
310            ).decode()
311        )
312        # (addr, scope, iface)
313        ret.append((addr, int(tmp[3], 16), tmp[5]))
314    return ret
315
316def read_routes6():
317    try:
318        f = open("/proc/net/ipv6_route","rb")
319    except IOError as err:
320        return []
321    # 1. destination network
322    # 2. destination prefix length
323    # 3. source network displayed
324    # 4. source prefix length
325    # 5. next hop
326    # 6. metric
327    # 7. reference counter (?!?)
328    # 8. use counter (?!?)
329    # 9. flags
330    # 10. device name
331    routes = []
332    def proc2r(p):
333        ret = struct.unpack('4s4s4s4s4s4s4s4s', raw(p))
334        ret = b':'.join(ret).decode()
335        return scapy.utils6.in6_ptop(ret)
336
337    lifaddr = in6_getifaddr()
338    for l in f.readlines():
339        l = plain_str(l)
340        d,dp,s,sp,nh,metric,rc,us,fl,dev = l.split()
341        metric = int(metric, 16)
342        fl = int(fl, 16)
343
344        if fl & RTF_UP == 0:
345            continue
346        if fl & RTF_REJECT:
347            continue
348
349        d = proc2r(d) ; dp = int(dp, 16)
350        s = proc2r(s) ; sp = int(sp, 16)
351        nh = proc2r(nh)
352
353        cset = [] # candidate set (possible source addresses)
354        if dev == LOOPBACK_NAME:
355            if d == '::':
356                continue
357            cset = ['::1']
358        else:
359            devaddrs = (x for x in lifaddr if x[2] == dev)
360            cset = scapy.utils6.construct_source_candidate_set(d, dp, devaddrs)
361
362        if len(cset) != 0:
363            routes.append((d, dp, nh, dev, cset, metric))
364    f.close()
365    return routes
366
367
368def get_if_index(iff):
369    return int(struct.unpack("I",get_if(iff, SIOCGIFINDEX)[16:20])[0])
370
371if os.uname()[4] in [ 'x86_64', 'aarch64' ]:
372    def get_last_packet_timestamp(sock):
373        ts = ioctl(sock, SIOCGSTAMP, "1234567890123456")
374        s,us = struct.unpack("QQ",ts)
375        return s+us/1000000.0
376else:
377    def get_last_packet_timestamp(sock):
378        ts = ioctl(sock, SIOCGSTAMP, "12345678")
379        s,us = struct.unpack("II",ts)
380        return s+us/1000000.0
381
382
383def _flush_fd(fd):
384    if hasattr(fd, 'fileno'):
385        fd = fd.fileno()
386    while True:
387        r,w,e = select([fd],[],[],0)
388        if r:
389            os.read(fd,MTU)
390        else:
391            break
392
393
394
395
396
397class L3PacketSocket(SuperSocket):
398    desc = "read/write packets at layer 3 using Linux PF_PACKET sockets"
399    def __init__(self, type = ETH_P_ALL, filter=None, promisc=None, iface=None, nofilter=0):
400        self.type = type
401        self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
402        self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0)
403        if iface:
404            self.ins.bind((iface, type))
405        if not nofilter:
406            if conf.except_filter:
407                if filter:
408                    filter = "(%s) and not (%s)" % (filter, conf.except_filter)
409                else:
410                    filter = "not (%s)" % conf.except_filter
411            if filter is not None:
412                attach_filter(self.ins, filter, iface)
413        _flush_fd(self.ins)
414        self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
415        self.outs = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
416        self.outs.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2**30)
417        self.promisc = conf.promisc if promisc is None else promisc
418        if self.promisc:
419            if iface is None:
420                self.iff = get_if_list()
421            elif isinstance(iface, list):
422                self.iff = iface
423            else:
424                self.iff = [iface]
425            for i in self.iff:
426                set_promisc(self.ins, i)
427    def close(self):
428        if self.closed:
429            return
430        self.closed = 1
431        if self.promisc:
432            for i in self.iff:
433                set_promisc(self.ins, i, 0)
434        SuperSocket.close(self)
435    def recv(self, x=MTU):
436        pkt, sa_ll = self.ins.recvfrom(x)
437        if sa_ll[2] == socket.PACKET_OUTGOING:
438            return None
439        if sa_ll[3] in conf.l2types:
440            cls = conf.l2types[sa_ll[3]]
441            lvl = 2
442        elif sa_ll[1] in conf.l3types:
443            cls = conf.l3types[sa_ll[1]]
444            lvl = 3
445        else:
446            cls = conf.default_l2
447            warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s", sa_ll[0], sa_ll[1], sa_ll[3], cls.name)
448            lvl = 2
449
450        try:
451            pkt = cls(pkt)
452        except KeyboardInterrupt:
453            raise
454        except:
455            if conf.debug_dissector:
456                raise
457            pkt = conf.raw_layer(pkt)
458        if lvl == 2:
459            pkt = pkt.payload
460
461        if pkt is not None:
462            pkt.time = get_last_packet_timestamp(self.ins)
463        return pkt
464
465    def send(self, x):
466        iff,a,gw  = x.route()
467        if iff is None:
468            iff = conf.iface
469        sdto = (iff, self.type)
470        self.outs.bind(sdto)
471        sn = self.outs.getsockname()
472        ll = lambda x:x
473        if type(x) in conf.l3types:
474            sdto = (iff, conf.l3types[type(x)])
475        if sn[3] in conf.l2types:
476            ll = lambda x:conf.l2types[sn[3]]()/x
477        sx = raw(ll(x))
478        x.sent_time = time.time()
479        try:
480            self.outs.sendto(sx, sdto)
481        except socket.error as msg:
482            if msg[0] == 22 and len(sx) < conf.min_pkt_size:
483                self.outs.send(sx + b"\x00" * (conf.min_pkt_size - len(sx)))
484            elif conf.auto_fragment and msg[0] == 90:
485                for p in x.fragment():
486                    self.outs.sendto(raw(ll(p)), sdto)
487            else:
488                raise
489
490
491
492class L2Socket(SuperSocket):
493    desc = "read/write packets at layer 2 using Linux PF_PACKET sockets"
494    def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilter=0):
495        self.iface = conf.iface if iface is None else iface
496        self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
497        self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0)
498        if not nofilter:
499            if conf.except_filter:
500                if filter:
501                    filter = "(%s) and not (%s)" % (filter, conf.except_filter)
502                else:
503                    filter = "not (%s)" % conf.except_filter
504            if filter is not None:
505                attach_filter(self.ins, filter, iface)
506        self.promisc = conf.sniff_promisc if promisc is None else promisc
507        if self.promisc:
508            set_promisc(self.ins, self.iface)
509        self.ins.bind((self.iface, type))
510        _flush_fd(self.ins)
511        self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
512        self.outs = self.ins
513        self.outs.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2**30)
514        sa_ll = self.outs.getsockname()
515        if sa_ll[3] in conf.l2types:
516            self.LL = conf.l2types[sa_ll[3]]
517        elif sa_ll[1] in conf.l3types:
518            self.LL = conf.l3types[sa_ll[1]]
519        else:
520            self.LL = conf.default_l2
521            warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s", sa_ll[0], sa_ll[1], sa_ll[3], self.LL.name)
522    def close(self):
523        if self.closed:
524            return
525        self.closed = 1
526        if self.promisc:
527            set_promisc(self.ins, self.iface, 0)
528        SuperSocket.close(self)
529    def recv(self, x=MTU):
530        pkt, sa_ll = self.ins.recvfrom(x)
531        if sa_ll[2] == socket.PACKET_OUTGOING:
532            return None
533        try:
534            q = self.LL(pkt)
535        except KeyboardInterrupt:
536            raise
537        except:
538            if conf.debug_dissector:
539                raise
540            q = conf.raw_layer(pkt)
541        q.time = get_last_packet_timestamp(self.ins)
542        return q
543    def send(self, x):
544        try:
545            return SuperSocket.send(self, x)
546        except socket.error as msg:
547            if msg[0] == 22 and len(x) < conf.min_pkt_size:
548                padding = b"\x00" * (conf.min_pkt_size - len(x))
549                if isinstance(x, Packet):
550                    return SuperSocket.send(self, x / Padding(load=padding))
551                else:
552                    return SuperSocket.send(self, raw(x) + padding)
553            raise
554
555
556class L2ListenSocket(SuperSocket):
557    desc = "read packets at layer 2 using Linux PF_PACKET sockets"
558    def __init__(self, iface = None, type = ETH_P_ALL, promisc=None, filter=None, nofilter=0):
559        self.type = type
560        self.outs = None
561        self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
562        self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0)
563        if iface is not None:
564            self.ins.bind((iface, type))
565        if not nofilter:
566            if conf.except_filter:
567                if filter:
568                    filter = "(%s) and not (%s)" % (filter, conf.except_filter)
569                else:
570                    filter = "not (%s)" % conf.except_filter
571            if filter is not None:
572                attach_filter(self.ins, filter, iface)
573        if promisc is None:
574            promisc = conf.sniff_promisc
575        self.promisc = promisc
576        if iface is None:
577            self.iff = get_if_list()
578        elif isinstance(iface, list):
579            self.iff = iface
580        else:
581            self.iff = [iface]
582        if self.promisc:
583            for i in self.iff:
584                set_promisc(self.ins, i)
585        _flush_fd(self.ins)
586        self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
587    def close(self):
588        if self.promisc:
589            for i in self.iff:
590                set_promisc(self.ins, i, 0)
591        SuperSocket.close(self)
592
593    def recv(self, x=MTU):
594        pkt, sa_ll = self.ins.recvfrom(x)
595        if sa_ll[3] in conf.l2types :
596            cls = conf.l2types[sa_ll[3]]
597        elif sa_ll[1] in conf.l3types:
598            cls = conf.l3types[sa_ll[1]]
599        else:
600            cls = conf.default_l2
601            warning("Unable to guess type (interface=%s protocol=%#x "
602                    "family=%i). Using %s", sa_ll[0], sa_ll[1], sa_ll[3],
603                                              cls.name)
604
605        try:
606            pkt = cls(pkt)
607        except KeyboardInterrupt:
608            raise
609        except:
610            if conf.debug_dissector:
611                raise
612            pkt = conf.raw_layer(pkt)
613        pkt.time = get_last_packet_timestamp(self.ins)
614        pkt.direction = sa_ll[2]
615        return pkt
616
617    def send(self, x):
618        raise Scapy_Exception("Can't send anything with L2ListenSocket")
619
620
621conf.L3socket = L3PacketSocket
622conf.L2socket = L2Socket
623conf.L2listen = L2ListenSocket
624