1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Philippe Biondi <phil@secdev.org>
5
6"""
7Functions common to different architectures
8"""
9
10import socket
11import ctypes
12
13from scapy.config import conf
14from scapy.data import MTU, ARPHDR_ETHER, ARPHRD_TO_DLT
15from scapy.error import Scapy_Exception
16from scapy.interfaces import network_name, resolve_iface, NetworkInterface
17from scapy.libs.structures import bpf_program
18from scapy.pton_ntop import inet_pton
19from scapy.utils import decode_locale_str
20
21# Type imports
22import scapy
23from typing import (
24 Optional,
25 Union,
26)
27
28# From if.h
29_iff_flags = [
30 "UP",
31 "BROADCAST",
32 "DEBUG",
33 "LOOPBACK",
34 "POINTTOPOINT",
35 "NOTRAILERS",
36 "RUNNING",
37 "NOARP",
38 "PROMISC",
39 "ALLMULTI",
40 "MASTER",
41 "SLAVE",
42 "MULTICAST",
43 "PORTSEL",
44 "AUTOMEDIA",
45 "DYNAMIC",
46 "LOWER_UP",
47 "DORMANT",
48 "ECHO"
49]
50
51
52def get_if_raw_addr(iff):
53 # type: (Union[NetworkInterface, str]) -> bytes
54 """Return the raw IPv4 address of interface"""
55 iff = resolve_iface(iff)
56 if not iff.ip:
57 return b"\x00" * 4
58 return inet_pton(socket.AF_INET, iff.ip)
59
60
61# BPF HANDLERS
62
63
64def compile_filter(filter_exp, # type: str
65 iface=None, # type: Optional[Union[str, 'scapy.interfaces.NetworkInterface']] # noqa: E501
66 linktype=None, # type: Optional[int]
67 promisc=False # type: bool
68 ):
69 # type: (...) -> bpf_program
70 """Asks libpcap to parse the filter, then build the matching
71 BPF bytecode.
72
73 :param iface: if provided, use the interface to compile
74 :param linktype: if provided, use the linktype to compile
75 """
76 try:
77 from scapy.libs.winpcapy import (
78 PCAP_ERRBUF_SIZE,
79 pcap_open_live,
80 pcap_compile,
81 pcap_compile_nopcap,
82 pcap_close
83 )
84 except OSError:
85 raise ImportError(
86 "libpcap is not available. Cannot compile filter !"
87 )
88 from ctypes import create_string_buffer
89 bpf = bpf_program()
90 bpf_filter = create_string_buffer(filter_exp.encode("utf8"))
91 if not linktype:
92 # Try to guess linktype to avoid root
93 if not iface:
94 if not conf.iface:
95 raise Scapy_Exception(
96 "Please provide an interface or linktype!"
97 )
98 iface = conf.iface
99 # Try to guess linktype to avoid requiring root
100 from scapy.arch import get_if_raw_hwaddr
101 try:
102 arphd = get_if_raw_hwaddr(iface)[0]
103 linktype = ARPHRD_TO_DLT.get(arphd)
104 except Exception:
105 # Failed to use linktype: use the interface
106 pass
107 if not linktype and conf.use_bpf:
108 linktype = ARPHDR_ETHER
109 if linktype is not None:
110 ret = pcap_compile_nopcap(
111 MTU, linktype, ctypes.byref(bpf), bpf_filter, 1, -1
112 )
113 elif iface:
114 err = create_string_buffer(PCAP_ERRBUF_SIZE)
115 iface_b = create_string_buffer(network_name(iface).encode("utf8"))
116 pcap = pcap_open_live(
117 iface_b, MTU, promisc, 0, err
118 )
119 error = decode_locale_str(bytearray(err).strip(b"\x00"))
120 if error:
121 raise OSError(error)
122 ret = pcap_compile(
123 pcap, ctypes.byref(bpf), bpf_filter, 1, -1
124 )
125 pcap_close(pcap)
126 if ret == -1:
127 raise Scapy_Exception(
128 "Failed to compile filter expression %s (%s)" % (filter_exp, ret)
129 )
130 return bpf