Files
linker/linker.tun/LinkerOsxTunDevice.cs
2024-12-09 14:29:54 +08:00

184 lines
5.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using linker.libs;
using linker.libs.extends;
using Microsoft.Win32.SafeHandles;
using System.Net;
namespace linker.tun
{
internal sealed class LinkerOsxTunDevice : ILinkerTunDevice
{
private string name = string.Empty;
public string Name => name;
public bool Running => fs != null;
private FileStream fs = null;
private IPAddress address;
private byte prefixLength = 24;
private SafeFileHandle safeFileHandle;
private string interfaceOsx = string.Empty;
public LinkerOsxTunDevice(string name)
{
this.name = name;
}
public bool Setup(IPAddress address, IPAddress gateway, byte prefixLength, out string error)
{
error = string.Empty;
interfaceOsx = GetOsxInterfaceNum();
this.address = address;
this.prefixLength = prefixLength;
safeFileHandle = File.OpenHandle($"/dev/{Name}", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, FileOptions.Asynchronous);
fs = new FileStream(safeFileHandle, FileAccess.ReadWrite, 1500);
IPAddress network = NetworkHelper.NetworkIP2IP(address, NetworkHelper.PrefixLength2Value(prefixLength));
CommandHelper.Osx(string.Empty, new string[] {
$"route delete -net {network}/{prefixLength} {address}",
$"ifconfig {Name} {address} {address} up",
$"route add -net {network}/{prefixLength} {address}",
});
return true;
}
public void Shutdown()
{
if (fs != null)
{
safeFileHandle?.Dispose();
interfaceOsx = string.Empty;
fs.Close();
fs.Dispose();
fs = null;
}
IPAddress network = NetworkHelper.NetworkIP2IP(address, NetworkHelper.PrefixLength2Value(this.prefixLength));
CommandHelper.Osx(string.Empty, new string[] { $"route delete -net {network}/{prefixLength} {address}" });
}
public void AddRoute(LinkerTunDeviceRouteItem[] ips, IPAddress ip)
{
string[] commands = ips.Select(item =>
{
IPAddress _ip = NetworkHelper.NetworkIP2IP(item.Address, item.PrefixLength);
return $"route add -net {_ip}/{item.PrefixLength} {ip}";
}).ToArray();
if (commands.Length > 0)
{
CommandHelper.Osx(string.Empty, commands.ToArray());
}
}
public void DelRoute(LinkerTunDeviceRouteItem[] ip)
{
string[] commands = ip.Select(item =>
{
IPAddress _ip = NetworkHelper.NetworkIP2IP(item.Address, item.PrefixLength);
return $"route delete -net {_ip}/{item.PrefixLength}";
}).ToArray();
if (commands.Length > 0)
{
CommandHelper.Osx(string.Empty, commands.ToArray());
}
}
public void SetMtu(int value)
{
CommandHelper.Osx(string.Empty, new string[] { $"ifconfig {Name} mtu {value}" });
}
public void SetNat(out string error)
{
error = string.Empty;
/*
# 开启ip转发
sudo sysctl -w net.ipv4.ip_forward=1
# 配置NAT转发规则
# 在/etc/pf.conf文件中添加以下规则,en0是出口网卡10.26.0.0/24是来源网段
nat on en0 from 10.26.0.0/24 to any -> (en0)
# 加载规则
sudo pfctl -f /etc/pf.conf -e
CommandHelper.Osx(string.Empty, new string[] {
"sysctl -w net.ipv4.ip_forward=1",
"nat on en0 from 10.26.0.0/24 to any -> (en0)",
"pfctl -f /etc/pf.conf -e",
});
*/
}
public void RemoveNat(out string error)
{
error = string.Empty;
}
public List<LinkerTunDeviceForwardItem> GetForward()
{
return new List<LinkerTunDeviceForwardItem>();
}
public void AddForward(List<LinkerTunDeviceForwardItem> forwards)
{
}
public void RemoveForward(List<LinkerTunDeviceForwardItem> forwards)
{
}
private byte[] buffer = new byte[2 * 1024];
public ReadOnlyMemory<byte> Read()
{
try
{
int length = fs.Read(buffer.AsSpan(4));
length.ToBytes(buffer);
return buffer.AsMemory(0, length + 4);
}
catch (Exception)
{
}
return Helper.EmptyArray;
}
public bool Write(ReadOnlyMemory<byte> buffer)
{
try
{
fs.Write(buffer.Span);
return true;
}
catch (Exception)
{
}
return false;
}
private string GetOsxInterfaceNum()
{
string output = CommandHelper.Osx(string.Empty, new string[] { "ifconfig" });
var arr = output.Split(Environment.NewLine);
for (int i = 0; i < arr.Length; i++)
{
var item = arr[i];
if (item.Contains("inet "))
{
for (int k = i; k >= 0; k--)
{
var itemk = arr[k];
if (itemk.Contains("flags=") && itemk.StartsWith("en"))
{
return itemk.Split(": ")[0];
}
}
}
}
return string.Empty;
}
public void Clear()
{
}
}
}