1010These allow Scapy to act as the remote side of a virtual network interface.
1111"""
1212
13-
1413import socket
1514import time
1615from fcntl import ioctl
1716
18- from scapy .compat import raw , bytes_encode
17+ from scapy .compat import bytes_encode , raw
1918from scapy .config import conf
20- from scapy .consts import BIG_ENDIAN , BSD , LINUX
19+ from scapy .consts import BIG_ENDIAN , BSD , DARWIN , LINUX
2120from scapy .data import ETHER_TYPES , MTU
22- from scapy .error import warning , log_runtime
23- from scapy .fields import Field , FlagsField , StrFixedLenField , XShortEnumField
21+ from scapy .error import log_runtime , warning
22+ from scapy .fields import (
23+ BitField ,
24+ Field ,
25+ FlagsField ,
26+ IntField ,
27+ StrFixedLenField ,
28+ XShortEnumField ,
29+ )
2430from scapy .interfaces import network_name
2531from scapy .layers .inet import IP
26- from scapy .layers .inet6 import IPv46 , IPv6
32+ from scapy .layers .inet6 import IPv6 , IPv46
2733from scapy .layers .l2 import Ether
28- from scapy .packet import Packet
34+ from scapy .packet import Packet , bind_layers
2935from scapy .supersocket import SimpleSocket
3036
31-
3237# Linux-specific defines (/usr/include/linux/if_tun.h)
3338LINUX_TUNSETIFF = 0x400454ca
3439LINUX_IFF_TUN = 0x0001
3540LINUX_IFF_TAP = 0x0002
3641LINUX_IFF_NO_PI = 0x1000
3742LINUX_IFNAMSIZ = 16
3843
44+ # Darwin-specific defines (net/if_utun.h and sys/kern_control.h)
45+ DARWIN_CTLIOCGINFO = 0xc0644e03
46+ DARWIN_UTUN_CONTROL_NAME = b"com.apple.net.utun_control"
47+ DARWIN_MAX_KCTL_NAME = 96
48+
3949
4050class NativeShortField (Field ):
4151 def __init__ (self , name , default ):
@@ -61,6 +71,18 @@ class LinuxTunIfReq(Packet):
6171 ]
6272
6373
74+ class DarwinUtunIfReq (Packet ):
75+ """
76+ Structure for issuing Darwin ioctl commands (``struct ctl_info``).
77+
78+ See net/if_utun.h and sys/kern_control.h for reference.
79+ """
80+ fields_desc = [
81+ BitField ("ctl_id" , 0 , - 32 ),
82+ StrFixedLenField ("ctl_name" , DARWIN_UTUN_CONTROL_NAME , DARWIN_MAX_KCTL_NAME )
83+ ]
84+
85+
6486class LinuxTunPacketInfo (TunPacketInfo ):
6587 """
6688 Base for TUN packets.
@@ -78,6 +100,12 @@ class LinuxTunPacketInfo(TunPacketInfo):
78100 ]
79101
80102
103+ class DarwinUtunPacketInfo (Packet ):
104+ fields_desc = [
105+ IntField ("addr_family" , socket .AF_INET )
106+ ]
107+
108+
81109class TunTapInterface (SimpleSocket ):
82110 """
83111 A socket to act as the host's peer of a tun / tap interface.
@@ -116,7 +144,7 @@ def __init__(self, iface=None, mode_tun=None, default_read_size=MTU,
116144
117145 self .mode_tun = mode_tun
118146 if self .mode_tun is None :
119- if self .iface .startswith (b"tun" ):
147+ if self .iface .startswith (b"tun" ) or self . iface . startswith ( b"utun" ) :
120148 self .mode_tun = True
121149 elif self .iface .startswith (b"tap" ):
122150 self .mode_tun = False
@@ -152,23 +180,38 @@ def __init__(self, iface=None, mode_tun=None, default_read_size=MTU,
152180 warning ("Linux interface names are limited to %d bytes, "
153181 "truncating!" % (LINUX_IFNAMSIZ ,))
154182 self .iface = self .iface [:LINUX_IFNAMSIZ ]
155-
183+ sock = open ( devname , "r+b" , buffering = 0 )
156184 elif BSD : # also DARWIN
157- if not (self .iface .startswith (b"tap" ) or
158- self .iface .startswith (b"tun" )):
185+ if self .iface .startswith (b"utun" ): # allowed for Darwin
186+ if not DARWIN :
187+ raise ValueError ('`utun` iface prefix is only allowed for Darwin' )
188+ self .kernel_packet_class = DarwinUtunPacketInfo
189+ self .mtu_overhead = 4
190+ interface_num = int (self .iface [4 :])
191+
192+ utun_socket = socket .socket (
193+ socket .PF_SYSTEM , socket .SOCK_DGRAM , socket .SYSPROTO_CONTROL )
194+ ctl_info = ioctl (utun_socket , DARWIN_CTLIOCGINFO ,
195+ raw (DarwinUtunIfReq ()))
196+ utun_socket .connect (
197+ (DarwinUtunIfReq (ctl_info ).getfieldval ("ctl_id" ), interface_num + 1 )
198+ )
199+
200+ sock = utun_socket .makefile (mode = "rwb" , buffering = 0 )
201+ elif self .iface .startswith (b"tap" ) or self .iface .startswith (b"tun" ):
202+ devname = b"/dev/" + self .iface
203+ if not self .strip_packet_info :
204+ warning ("tun/tap devices on BSD and Darwin never include "
205+ "packet info!" )
206+ self .strip_packet_info = True
207+ sock = open (devname , "r+b" , buffering = 0 )
208+ else :
159209 raise ValueError ("Interface names must start with `tun` or "
160- "`tap` on BSD and Darwin" )
161- devname = b"/dev/" + self .iface
162- if not self .strip_packet_info :
163- warning ("tun/tap devices on BSD and Darwin never include "
164- "packet info!" )
165- self .strip_packet_info = True
210+ "`tap` on BSD and Darwin or `utun` on Darwin" )
166211 else :
167212 raise NotImplementedError ("TunTapInterface is not supported on "
168213 "this platform!" )
169214
170- sock = open (devname , "r+b" , buffering = 0 )
171-
172215 if LINUX :
173216 if self .mode_tun :
174217 flags = LINUX_IFF_TUN
@@ -241,3 +284,8 @@ def send(self, x):
241284 except socket .error :
242285 log_runtime .error ("%s send" ,
243286 self .__class__ .__name__ , exc_info = True )
287+
288+
289+ # Bindings #
290+ bind_layers (DarwinUtunPacketInfo , IP , addr_family = socket .AF_INET )
291+ bind_layers (DarwinUtunPacketInfo , IPv6 , addr_family = socket .AF_INET6 )
0 commit comments