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"""
7Operating system specific functionality.
8"""
9
10import socket
11import sys
12
13from scapy.compat import orb
14from scapy.config import conf, _set_conf_sockets
15from scapy.consts import LINUX, SOLARIS, WINDOWS, BSD
16from scapy.data import (
17 ARPHDR_ETHER,
18 ARPHDR_LOOPBACK,
19 ARPHDR_PPP,
20 ARPHDR_TUN,
21 IPV6_ADDR_GLOBAL
22)
23from scapy.error import log_loading, Scapy_Exception
24from scapy.interfaces import _GlobInterfaceType, network_name
25from scapy.pton_ntop import inet_pton, inet_ntop
26
27from scapy.libs.extcap import load_extcap
28
29# Typing imports
30from typing import (
31 List,
32 Optional,
33 Tuple,
34 Union,
35 TYPE_CHECKING,
36)
37
38if TYPE_CHECKING:
39 from scapy.interfaces import NetworkInterface
40
41# Note: the typing of this file is heavily ignored because MyPy doesn't allow
42# to import the same function from different files.
43
44# This list only includes imports that are common across all platforms.
45__all__ = [ # noqa: F405
46 "get_if_addr",
47 "get_if_addr6",
48 "get_if_hwaddr",
49 "get_if_list",
50 "get_if_raw_addr",
51 "get_if_raw_addr6",
52 "get_if_raw_hwaddr",
53 "get_working_if",
54 "in6_getifaddr",
55 "read_nameservers",
56 "read_routes",
57 "read_routes6",
58 "load_extcap",
59 "SIOCGIFHWADDR",
60]
61
62# BACKWARD COMPATIBILITY
63from scapy.interfaces import (
64 get_if_list,
65 get_working_if,
66)
67
68
69# We build the utils functions BEFORE importing the underlying handlers
70# because they might be themselves imported within the arch/ folder.
71
72def str2mac(s):
73 # Duplicated from scapy/utils.py for import reasons
74 # type: (bytes) -> str
75 return ("%02x:" * 6)[:-1] % tuple(orb(x) for x in s)
76
77
78def get_if_addr(iff):
79 # type: (_GlobInterfaceType) -> str
80 """
81 Returns the IPv4 of an interface or "0.0.0.0" if not available
82 """
83 return inet_ntop(socket.AF_INET, get_if_raw_addr(iff)) # noqa: F405
84
85
86def get_if_hwaddr(iff):
87 # type: (_GlobInterfaceType) -> str
88 """
89 Returns the MAC (hardware) address of an interface
90 """
91 from scapy.arch import get_if_raw_hwaddr
92 addrfamily, mac = get_if_raw_hwaddr(iff) # noqa: F405
93 if addrfamily in [ARPHDR_ETHER, ARPHDR_LOOPBACK, ARPHDR_PPP, ARPHDR_TUN]:
94 return str2mac(mac)
95 else:
96 raise Scapy_Exception("Unsupported address family (%i) for interface [%s]" % (addrfamily, iff)) # noqa: E501
97
98
99def get_if_addr6(niff):
100 # type: (_GlobInterfaceType) -> Optional[str]
101 """
102 Returns the main global unicast address associated with provided
103 interface, in human readable form. If no global address is found,
104 None is returned.
105 """
106 iff = network_name(niff)
107 return next((x[0] for x in in6_getifaddr()
108 if x[2] == iff and x[1] == IPV6_ADDR_GLOBAL), None)
109
110
111def get_if_raw_addr6(iff):
112 # type: (_GlobInterfaceType) -> Optional[bytes]
113 """
114 Returns the main global unicast address associated with provided
115 interface, in network format. If no global address is found, None
116 is returned.
117 """
118 ip6 = get_if_addr6(iff)
119 if ip6 is not None:
120 return inet_pton(socket.AF_INET6, ip6)
121
122 return None
123
124
125# Next step is to import following architecture specific functions:
126# def attach_filter(s, filter, iface)
127# def get_if(iff,cmd)
128# def get_if_raw_addr(iff)
129# def get_if_raw_hwaddr(iff)
130# def in6_getifaddr()
131# def read_nameservers()
132# def read_routes()
133# def read_routes6()
134# def set_promisc(s,iff,val=1)
135
136if LINUX:
137 from scapy.arch.linux import * # noqa F403
138elif BSD:
139 from scapy.arch.unix import ( # noqa F403
140 read_nameservers,
141 read_routes,
142 read_routes6,
143 in6_getifaddr,
144 )
145 from scapy.arch.bpf.core import * # noqa F403
146 if not conf.use_pcap:
147 # Native
148 from scapy.arch.bpf.supersocket import * # noqa F403
149 conf.use_bpf = True
150 SIOCGIFHWADDR = 0 # mypy compat
151elif SOLARIS:
152 from scapy.arch.solaris import * # noqa F403
153elif WINDOWS:
154 from scapy.arch.windows import * # noqa F403
155 from scapy.arch.windows.native import * # noqa F403
156 SIOCGIFHWADDR = 0 # mypy compat
157else:
158 log_loading.critical(
159 "Scapy currently does not support %s! I/O will NOT work!" % sys.platform
160 )
161 SIOCGIFHWADDR = 0 # mypy compat
162
163 # DUMMYS
164 def get_if_raw_addr(iff: Union['NetworkInterface', str]) -> bytes:
165 return b"\0\0\0\0"
166
167 def get_if_raw_hwaddr(iff: Union['NetworkInterface', str]) -> Tuple[int, bytes]:
168 return -1, b""
169
170 def in6_getifaddr() -> List[Tuple[str, int, str]]:
171 return []
172
173 def read_nameservers() -> List[str]:
174 return []
175
176 def read_routes() -> List[str]:
177 return []
178
179 def read_routes6() -> List[str]:
180 return []
181
182if LINUX or BSD:
183 conf.load_layers.append("tuntap")
184
185_set_conf_sockets() # Apply config