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 IPV6_ADDR_GLOBAL,
18 IPV6_ADDR_LOOPBACK,
19)
20from scapy.error import log_loading
21from scapy.interfaces import (
22 _GlobInterfaceType,
23 network_name,
24 resolve_iface,
25)
26from scapy.pton_ntop import inet_pton, inet_ntop
27
28from scapy.libs.extcap import load_extcap
29
30# Typing imports
31from typing import (
32 List,
33 Optional,
34 Tuple,
35 Union,
36 TYPE_CHECKING,
37)
38
39if TYPE_CHECKING:
40 from scapy.interfaces import NetworkInterface
41
42# Note: the typing of this file is heavily ignored because MyPy doesn't allow
43# to import the same function from different files.
44
45# This list only includes imports that are common across all platforms.
46__all__ = [ # noqa: F405
47 "get_if_addr",
48 "get_if_addr6",
49 "get_if_hwaddr",
50 "get_if_list",
51 "get_if_raw_addr",
52 "get_if_raw_addr6",
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 return resolve_iface(iff).mac or "00:00:00:00:00:00"
92
93
94def get_if_addr6(niff):
95 # type: (_GlobInterfaceType) -> Optional[str]
96 """
97 Returns the main global unicast address associated with provided
98 interface, in human readable form. If no global address is found,
99 None is returned.
100 """
101 iff = network_name(niff)
102 scope = IPV6_ADDR_GLOBAL
103 if iff == conf.loopback_name:
104 scope = IPV6_ADDR_LOOPBACK
105 return next((x[0] for x in in6_getifaddr()
106 if x[2] == iff and x[1] == scope), None)
107
108
109def get_if_raw_addr6(iff):
110 # type: (_GlobInterfaceType) -> Optional[bytes]
111 """
112 Returns the main global unicast address associated with provided
113 interface, in network format. If no global address is found, None
114 is returned.
115 """
116 ip6 = get_if_addr6(iff)
117 if ip6 is not None:
118 return inet_pton(socket.AF_INET6, ip6)
119
120 return None
121
122
123# Next step is to import following architecture specific functions:
124# def attach_filter(s, filter, iface)
125# def get_if_raw_addr(iff)
126# def in6_getifaddr()
127# def read_nameservers()
128# def read_routes()
129# def read_routes6()
130# def set_promisc(s,iff,val=1)
131
132if LINUX:
133 from scapy.arch.linux import * # noqa F403
134elif BSD:
135 from scapy.arch.bpf.core import * # noqa F403
136 if not conf.use_pcap:
137 # Native
138 from scapy.arch.bpf.supersocket import * # noqa F403
139 conf.use_bpf = True
140 SIOCGIFHWADDR = 0 # mypy compat
141elif SOLARIS:
142 from scapy.arch.solaris import * # noqa F403
143elif WINDOWS:
144 from scapy.arch.windows import * # noqa F403
145 from scapy.arch.windows.native import * # noqa F403
146 SIOCGIFHWADDR = 0 # mypy compat
147else:
148 log_loading.critical(
149 "Scapy currently does not support %s! I/O will NOT work!" % sys.platform
150 )
151 SIOCGIFHWADDR = 0 # mypy compat
152
153 # DUMMYS
154 def get_if_raw_addr(iff: Union['NetworkInterface', str]) -> bytes:
155 return b"\0\0\0\0"
156
157 def in6_getifaddr() -> List[Tuple[str, int, str]]:
158 return []
159
160 def read_nameservers() -> List[str]:
161 return []
162
163 def read_routes() -> List[str]:
164 return []
165
166 def read_routes6() -> List[str]:
167 return []
168
169if LINUX or BSD:
170 conf.load_layers.append("tuntap")
171
172_set_conf_sockets() # Apply config