mirror of
https://github.com/snltty/linker.git
synced 2025-12-19 18:06:47 +08:00
fixed
This commit is contained in:
@@ -9,7 +9,7 @@ using System.Text.RegularExpressions;
|
||||
namespace linker.tun.device
|
||||
{
|
||||
/// <summary>
|
||||
/// osx网卡实现,未测试
|
||||
/// macOS network adapter implementation (untested)
|
||||
/// </summary>
|
||||
internal sealed class LinkerOsxTunDevice : ILinkerTunDevice
|
||||
{
|
||||
@@ -17,7 +17,6 @@ namespace linker.tun.device
|
||||
public string Name => name;
|
||||
public bool Running => safeFileHandle != null;
|
||||
|
||||
|
||||
private string interfaceMac = string.Empty;
|
||||
private FileStream fsRead = null;
|
||||
private FileStream fsWrite = null;
|
||||
@@ -26,66 +25,54 @@ namespace linker.tun.device
|
||||
private byte prefixLength = 24;
|
||||
private int tunUnit = -1;
|
||||
|
||||
|
||||
public LinkerOsxTunDevice()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public bool Setup(LinkerTunDeviceSetupInfo info, out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
|
||||
|
||||
this.name = info.Name;
|
||||
this.address = info.Address;
|
||||
this.prefixLength = info.PrefixLength;
|
||||
|
||||
|
||||
if (Running)
|
||||
{
|
||||
error = ($"Adapter already exists");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (OpenUtunDevice(out error) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (ConfigureInterface(out error) == false)
|
||||
{
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
fsRead = new FileStream(safeFileHandle, FileAccess.Read, 65 * 1024, false);
|
||||
fsWrite = new FileStream(safeFileHandle, FileAccess.Write, 65 * 1024, false);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private bool OpenUtunDevice(out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
// macOS'ta utun cihazları otomatik olarak unit numarası ile oluşturulur
|
||||
// -1 kullanarak sistemin otomatik olarak bir unit atamasını sağlıyoruz
|
||||
// On macOS, utun devices are created automatically with unit numbers
|
||||
// Using -1 lets the system assign a free unit
|
||||
IntPtr ifnameBuffer = Marshal.AllocHGlobal(256);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
int fd = MacAPI.open_utun(-1, ifnameBuffer, new UIntPtr(256), out int errno);
|
||||
|
||||
int fd = OsxAPI.open_utun(-1, ifnameBuffer, new UIntPtr(256), out int errno);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
@@ -93,8 +80,7 @@ namespace linker.tun.device
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Interface adını al
|
||||
// Retrieve interface name
|
||||
interfaceMac = Marshal.PtrToStringAnsi(ifnameBuffer);
|
||||
if (string.IsNullOrEmpty(interfaceMac))
|
||||
{
|
||||
@@ -102,19 +88,16 @@ namespace linker.tun.device
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Unit numarasını çıkar (örn: utun5 -> 5)
|
||||
// Extract unit number (e.g. utun5 -> 5)
|
||||
var match = Regex.Match(interfaceMac, @"utun(\d+)");
|
||||
if (match.Success)
|
||||
{
|
||||
tunUnit = int.Parse(match.Groups[1].Value);
|
||||
}
|
||||
|
||||
|
||||
// SafeFileHandle oluştur
|
||||
// Create SafeFileHandle
|
||||
safeFileHandle = new SafeFileHandle(new IntPtr(fd), true);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
@@ -129,63 +112,55 @@ namespace linker.tun.device
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool ConfigureInterface(out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
// macOS'ta TUN interface için gateway IP (genellikle .1)
|
||||
// On macOS, the TUN interface gateway IP (usually .1)
|
||||
byte[] gatewayBytes = address.GetAddressBytes();
|
||||
gatewayBytes[3] = 1; // Son octet'i 1 yap (örn: 10.18.18.1)
|
||||
gatewayBytes[3] = 1; // Set last octet to 1 (e.g., 10.18.18.1)
|
||||
IPAddress gatewayAddr = new IPAddress(gatewayBytes);
|
||||
|
||||
|
||||
IPAddress networkAddr = NetworkHelper.ToNetworkIP(address, NetworkHelper.ToPrefixValue(prefixLength));
|
||||
|
||||
|
||||
string[] commands = new string[]
|
||||
{
|
||||
// Interface'i configure et - destination olarak gateway kullan
|
||||
// Configure interface - use gateway as destination
|
||||
$"sudo ifconfig {interfaceMac} {address} {gatewayAddr} netmask 255.255.255.255 up",
|
||||
$"sudo ifconfig {interfaceMac} mtu 1500",
|
||||
|
||||
// IP forwarding'i aktifleştir
|
||||
// Enable IP forwarding
|
||||
"sudo sysctl -w net.inet.ip.forwarding=1",
|
||||
"sudo sysctl -w net.inet.ip.redirect=0",
|
||||
|
||||
// Eski route'ları temizle
|
||||
// Remove old routes
|
||||
$"sudo route delete -net {networkAddr}/{prefixLength} 2>/dev/null || true",
|
||||
|
||||
// Network route'u ekle - interface üzerinden
|
||||
// Add network route via interface
|
||||
$"sudo route add -net {networkAddr}/{prefixLength} -interface {interfaceMac}",
|
||||
|
||||
// Host route ekle - kendisi için
|
||||
// Add host route for self
|
||||
$"sudo route add -host {address} -interface {interfaceMac}",
|
||||
|
||||
// Gateway route ekle
|
||||
// Add gateway route
|
||||
$"sudo route add -host {gatewayAddr} -interface {interfaceMac}"
|
||||
};
|
||||
|
||||
|
||||
string result = CommandHelper.Osx(string.Empty, commands, out error);
|
||||
|
||||
|
||||
// Route ekleme hatası normal olabilir (zaten varsa)
|
||||
// Ignore non-critical routing errors
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
// Route hatalarını ignore et ama diğer hatalar için kontrol et
|
||||
if (!(!error.Contains("File exists") && !error.Contains("Network is unreachable") && !error.Contains("route: writing to routing socket")))
|
||||
{
|
||||
// Kritik olmayan hatalar için devam et
|
||||
// Continue for non-critical issues
|
||||
error = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Interface'in UP olduğunu kontrol et
|
||||
// Verify interface is UP
|
||||
result = CommandHelper.Osx(string.Empty, new string[] { $"ifconfig {interfaceMac}" });
|
||||
if (!result.Contains("UP"))
|
||||
{
|
||||
@@ -193,14 +168,8 @@ namespace linker.tun.device
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
string routes = CommandHelper.Osx(string.Empty, new string[] { "netstat -rn | grep " + interfaceMac });
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -210,27 +179,23 @@ namespace linker.tun.device
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(interfaceMac))
|
||||
{
|
||||
// Interface'i down yap
|
||||
// Bring interface down
|
||||
CommandHelper.Osx(string.Empty, new string[] { $"sudo ifconfig {interfaceMac} down" });
|
||||
}
|
||||
|
||||
|
||||
safeFileHandle?.Dispose();
|
||||
safeFileHandle = null;
|
||||
|
||||
|
||||
try { fsRead?.Flush(); } catch (Exception) { }
|
||||
try { fsRead?.Close(); fsRead?.Dispose(); } catch (Exception) { }
|
||||
fsRead = null;
|
||||
|
||||
|
||||
try { fsWrite?.Flush(); } catch (Exception) { }
|
||||
try { fsWrite?.Close(); fsWrite?.Dispose(); } catch (Exception) { }
|
||||
fsWrite = null;
|
||||
@@ -239,13 +204,11 @@ namespace linker.tun.device
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
interfaceMac = string.Empty;
|
||||
tunUnit = -1;
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if (safeFileHandle == null) return;
|
||||
@@ -260,7 +223,6 @@ namespace linker.tun.device
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetMtu(int value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(interfaceMac))
|
||||
@@ -269,89 +231,67 @@ namespace linker.tun.device
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string GetDefaultInterface()
|
||||
{
|
||||
return CommandHelper.Osx(string.Empty, new string[] { "route get default | grep interface | awk '{print $2}'" });
|
||||
}
|
||||
|
||||
|
||||
public void SetNat(out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
if (address == null || address.Equals(IPAddress.Any)) return;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
IPAddress network = NetworkHelper.ToNetworkIP(address, NetworkHelper.ToPrefixValue(prefixLength));
|
||||
string defaultInterface = GetDefaultInterface().Trim();
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(defaultInterface))
|
||||
{
|
||||
// Fallback - en0 veya eth0 dene
|
||||
// Fallback - try en0 or eth0
|
||||
defaultInterface = "en0";
|
||||
}
|
||||
|
||||
|
||||
// Önce mevcut pfctl durumunu kontrol et
|
||||
// Check pfctl status
|
||||
string pfStatus = CommandHelper.Osx(string.Empty, new string[] { "sudo pfctl -s info" });
|
||||
|
||||
|
||||
// Basit NAT kuralları
|
||||
string pfRules = $@"# Localtonet VPN NAT Rules
|
||||
// Basic NAT rules
|
||||
string pfRules = $@"# VPN NAT Rules
|
||||
# Enable packet forwarding
|
||||
set skip on lo0
|
||||
|
||||
|
||||
# NAT outgoing traffic from VPN network
|
||||
nat on {defaultInterface} from {network}/{prefixLength} to any -> ({defaultInterface})
|
||||
|
||||
|
||||
# Allow traffic on TUN interface
|
||||
pass on {interfaceMac} all
|
||||
|
||||
|
||||
# Allow forwarding from VPN network
|
||||
pass from {network}/{prefixLength} to any keep state
|
||||
pass from any to {network}/{prefixLength} keep state
|
||||
|
||||
|
||||
# Allow ICMP (for ping)
|
||||
pass inet proto icmp all
|
||||
";
|
||||
|
||||
|
||||
// pfctl konfigürasyonu
|
||||
string tempFile = "/tmp/localtonet_pf_rules";
|
||||
string tempFile = "/tmp/vpn_pf_rules";
|
||||
File.WriteAllText(tempFile, pfRules);
|
||||
|
||||
|
||||
// IP forwarding'i aktifleştir
|
||||
// Enable IP forwarding
|
||||
CommandHelper.Osx(string.Empty, new string[] {
|
||||
"sudo sysctl -w net.inet.ip.forwarding=1"
|
||||
});
|
||||
|
||||
|
||||
// pfctl kurallarını yükle
|
||||
// Load pfctl rules
|
||||
string pfResult = CommandHelper.Osx(string.Empty, new string[] {
|
||||
$"sudo pfctl -f {tempFile}",
|
||||
"sudo pfctl -e"
|
||||
}, out error);
|
||||
|
||||
|
||||
// Geçici dosyayı sil
|
||||
try { File.Delete(tempFile); } catch { }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// pfctl durumunu kontrol et
|
||||
// Verify pfctl state
|
||||
string rules = CommandHelper.Osx(string.Empty, new string[] { "sudo pfctl -s nat" });
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -359,13 +299,12 @@ pass inet proto icmp all
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RemoveNat(out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
try
|
||||
{
|
||||
// pfctl'i disable et
|
||||
// Disable pfctl
|
||||
CommandHelper.Osx(string.Empty, new string[] {
|
||||
"sudo pfctl -d"
|
||||
}, out error);
|
||||
@@ -376,58 +315,48 @@ pass inet proto icmp all
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<LinkerTunDeviceForwardItem> GetForward()
|
||||
{
|
||||
// macOS'ta port forwarding genellikle pfctl ile yapılır
|
||||
// Basit bir implementasyon - gerçek kullanımda daha karmaşık parsing gerekebilir
|
||||
// On macOS, port forwarding is generally handled with pfctl
|
||||
// Simple implementation - real-world parsing may be more complex
|
||||
var forwards = new List<LinkerTunDeviceForwardItem>();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
string result = CommandHelper.Osx(string.Empty, new string[] { "sudo pfctl -s nat" });
|
||||
// pfctl output'unu parse etmek için regex kullan
|
||||
// Bu basit bir örnek - gerçek implementasyon daha karmaşık olabilir
|
||||
// Could parse pfctl output using regex if needed
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
return forwards;
|
||||
}
|
||||
|
||||
|
||||
public void AddForward(List<LinkerTunDeviceForwardItem> forwards)
|
||||
{
|
||||
if (forwards == null || forwards.Count == 0) return;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
string defaultInterface = GetDefaultInterface().Trim();
|
||||
List<string> rules = new List<string>();
|
||||
|
||||
|
||||
foreach (var forward in forwards.Where(f => f != null && f.Enable))
|
||||
{
|
||||
rules.Add($"rdr on {defaultInterface} inet proto tcp from any to any port {forward.ListenPort} -> {forward.ConnectAddr} port {forward.ConnectPort}");
|
||||
}
|
||||
|
||||
|
||||
if (rules.Count > 0)
|
||||
{
|
||||
string tempFile = "/tmp/localtonet_forward_rules";
|
||||
string tempFile = "/tmp/vpn_forward_rules";
|
||||
File.WriteAllText(tempFile, string.Join("\n", rules));
|
||||
|
||||
|
||||
CommandHelper.Osx(string.Empty, new string[] {
|
||||
$"sudo pfctl -f {tempFile}",
|
||||
"sudo pfctl -e"
|
||||
});
|
||||
|
||||
|
||||
try { File.Delete(tempFile); } catch { }
|
||||
}
|
||||
}
|
||||
@@ -436,10 +365,9 @@ pass inet proto icmp all
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RemoveForward(List<LinkerTunDeviceForwardItem> forwards)
|
||||
{
|
||||
// pfctl rules'ları kaldırmak için genellikle tüm konfigürasyon yeniden yüklenir
|
||||
// Removing pfctl rules usually requires reloading configuration
|
||||
try
|
||||
{
|
||||
CommandHelper.Osx(string.Empty, new string[] { "sudo pfctl -F nat" });
|
||||
@@ -449,12 +377,10 @@ pass inet proto icmp all
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void AddRoute(LinkerTunDeviceRouteItem[] routes)
|
||||
{
|
||||
if (routes == null || routes.Length == 0) return;
|
||||
|
||||
|
||||
string[] commands = routes.Select(route =>
|
||||
{
|
||||
uint prefixValue = NetworkHelper.ToPrefixValue(route.PrefixLength);
|
||||
@@ -462,19 +388,16 @@ pass inet proto icmp all
|
||||
return $"sudo route add -net {network}/{route.PrefixLength} -interface {interfaceMac}";
|
||||
}).ToArray();
|
||||
|
||||
|
||||
if (commands.Length > 0)
|
||||
{
|
||||
CommandHelper.Osx(string.Empty, commands);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RemoveRoute(LinkerTunDeviceRouteItem[] routes)
|
||||
{
|
||||
if (routes == null || routes.Length == 0) return;
|
||||
|
||||
|
||||
string[] commands = routes.Select(route =>
|
||||
{
|
||||
uint prefixValue = NetworkHelper.ToPrefixValue(route.PrefixLength);
|
||||
@@ -482,54 +405,43 @@ pass inet proto icmp all
|
||||
return $"sudo route delete -net {network}/{route.PrefixLength}";
|
||||
}).ToArray();
|
||||
|
||||
|
||||
if (commands.Length > 0)
|
||||
{
|
||||
CommandHelper.Osx(string.Empty, commands);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private readonly byte[] buffer = new byte[65 * 1024];
|
||||
private readonly object writeLockObj = new object();
|
||||
|
||||
|
||||
public byte[] Read(out int length)
|
||||
{
|
||||
length = 0;
|
||||
if (safeFileHandle == null || fsRead == null) return Helper.EmptyArray;
|
||||
|
||||
|
||||
// UTUN: tek okuyuşta [AF(4) | IP(...)]
|
||||
// UTUN: [AF(4) | IP(...)]
|
||||
int n = fsRead.Read(buffer, 0, buffer.Length);
|
||||
if (n < 5) return Helper.EmptyArray;
|
||||
|
||||
|
||||
// AF header BIG-ENDIAN
|
||||
uint af = BinaryPrimitives.ReadUInt32BigEndian(buffer.AsSpan(0, 4));
|
||||
if (af != 2u && af != 30u) // AF_INET=2, AF_INET6=30
|
||||
return Helper.EmptyArray;
|
||||
|
||||
|
||||
int payloadLen = n - 4;
|
||||
|
||||
|
||||
// Senin pipeline: [LEN_LE(4) | IP]
|
||||
// Your pipeline format: [LEN_LE(4) | IP]
|
||||
BinaryPrimitives.WriteInt32LittleEndian(buffer.AsSpan(0, 4), payloadLen);
|
||||
Buffer.BlockCopy(buffer, 4, buffer, 4, payloadLen);
|
||||
|
||||
|
||||
length = payloadLen + 4;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public bool Write(ReadOnlyMemory<byte> packet)
|
||||
{
|
||||
if (safeFileHandle == null || fsWrite == null) return false;
|
||||
|
||||
|
||||
lock (writeLockObj)
|
||||
{
|
||||
try
|
||||
@@ -537,25 +449,21 @@ pass inet proto icmp all
|
||||
var span = packet.Span;
|
||||
if (span.Length < 1) return false;
|
||||
|
||||
|
||||
ReadOnlySpan<byte> ipSpan;
|
||||
|
||||
|
||||
// 1) UTUN çerçevesi mi? (AF header big-endian: 0x00000002 veya 0x0000001E)
|
||||
// 1) UTUN frame? (AF header big-endian: 0x00000002 or 0x0000001E)
|
||||
if (span.Length >= 5)
|
||||
{
|
||||
uint afBe = BinaryPrimitives.ReadUInt32BigEndian(span.Slice(0, 4));
|
||||
if (afBe == 2u || afBe == 30u)
|
||||
{
|
||||
// Zaten [AF_BE][IP] -> direkt yaz
|
||||
// Already [AF_BE][IP] -> write directly
|
||||
fsWrite.Write(span);
|
||||
// fsWrite.Flush(); // genelde gerek yok
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 2) Ham IP mi? (ilk nibble 4 ya da 6)
|
||||
// 2) Raw IP packet (first nibble 4 or 6)
|
||||
byte v = (byte)(span[0] >> 4);
|
||||
if (v == 4 || v == 6)
|
||||
{
|
||||
@@ -563,50 +471,42 @@ pass inet proto icmp all
|
||||
}
|
||||
else
|
||||
{
|
||||
// 3) [LEN_LE][IP] çerçevesi
|
||||
// 3) [LEN_LE][IP] frame
|
||||
if (span.Length < 5) return false;
|
||||
int payloadLen = BinaryPrimitives.ReadInt32LittleEndian(span.Slice(0, 4));
|
||||
// Mantık kontrolü
|
||||
if (payloadLen <= 0 || payloadLen > span.Length - 4) return false;
|
||||
|
||||
|
||||
ipSpan = span.Slice(4, payloadLen);
|
||||
|
||||
|
||||
// Güvenlik: gerçekten IP mi?
|
||||
// Safety check
|
||||
byte v2 = (byte)(ipSpan[0] >> 4);
|
||||
if (v2 != 4 && v2 != 6) return false;
|
||||
v = v2;
|
||||
}
|
||||
|
||||
|
||||
uint af = (v == 6) ? 30u : 2u; // AF_INET6 / AF_INET
|
||||
|
||||
|
||||
// UTUN paketi oluştur: [AF_BE(4)] + [IP]
|
||||
// Create UTUN frame: [AF_BE(4)] + [IP]
|
||||
byte[] outBuf = new byte[4 + ipSpan.Length];
|
||||
BinaryPrimitives.WriteUInt32BigEndian(outBuf.AsSpan(0, 4), af);
|
||||
ipSpan.CopyTo(outBuf.AsSpan(4));
|
||||
|
||||
|
||||
fsWrite.Write(outBuf, 0, outBuf.Length);
|
||||
fsWrite.Flush(); // çoğu zaman gerekmez
|
||||
fsWrite.Flush();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> CheckAvailable(bool order = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(interfaceMac))
|
||||
return await Task.FromResult(false);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
string output = CommandHelper.Osx(string.Empty, new string[] { $"ifconfig {interfaceMac}" });
|
||||
@@ -619,13 +519,5 @@ pass inet proto icmp all
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Mac API için gerekli P/Invoke tanımları
|
||||
internal static class MacAPI
|
||||
{
|
||||
[DllImport("libutunshim.dylib", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int open_utun(int unit, IntPtr ifnameBuf, UIntPtr ifnameLen, out int out_errno);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,18 +5,8 @@ namespace linker.tun.device
|
||||
{
|
||||
internal static class OsxAPI
|
||||
{
|
||||
|
||||
// 定义 macOS 的 ioctl 命令(来自 <net/if_utun.h>)
|
||||
private const uint UTUN_CONTROL = 0x80000000; // 'u' << 24
|
||||
private const uint UTUN_CTRL_SET_IFNAME = UTUN_CONTROL | 1;
|
||||
|
||||
// P/Invoke 声明
|
||||
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
|
||||
private static extern int Ioctl(SafeFileHandle fd, uint request, nint arg);
|
||||
|
||||
public static int Ioctl(SafeFileHandle fd, nint arg)
|
||||
{
|
||||
return Ioctl(fd, UTUN_CTRL_SET_IFNAME, arg);
|
||||
}
|
||||
// Required P/Invoke for macOS UTUN API
|
||||
[DllImport("libutunshim.dylib", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int open_utun(int unit, IntPtr ifnameBuf, UIntPtr ifnameLen, out int out_errno);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user