v0.6: DHCP tunnel transport with NOP heartbeat protocol
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
// Args: [interface_ip] [interval_ms]
|
||||
// Defaults: auto-detect LAN IP, 50ms
|
||||
|
||||
string localIp = args.Length > 0 ? args[0] : GetLanInterfaceIp() ?? "0.0.0.0";
|
||||
int intervalMs = args.Length > 1 && int.TryParse(args[1], out int iv) ? iv : 50;
|
||||
|
||||
using var sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
sock.EnableBroadcast = true;
|
||||
|
||||
var localEp = new IPEndPoint(IPAddress.Parse(localIp), 68);
|
||||
sock.Bind(localEp);
|
||||
|
||||
Console.WriteLine($"Bound to {localEp} (SO_REUSEADDR)");
|
||||
Console.WriteLine("Sending NOPs + listening. Press Ctrl+C to stop.");
|
||||
Console.WriteLine();
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var recvTask = Task.Run(() => ReceiveLoop(sock, cts.Token));
|
||||
|
||||
var destEp = new IPEndPoint(IPAddress.Broadcast, 67);
|
||||
uint nonce = 0;
|
||||
|
||||
while (!cts.Token.IsCancellationRequested)
|
||||
{
|
||||
nonce++;
|
||||
string msg = $"HKMSTR {nonce}\n";
|
||||
byte[] payload = Encoding.UTF8.GetBytes(msg);
|
||||
|
||||
try
|
||||
{
|
||||
int sent = sock.SendTo(payload, destEp);
|
||||
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] SENT n={nonce} {sent} bytes");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] SEND FAILED: {ex.Message}");
|
||||
}
|
||||
|
||||
try { Thread.Sleep(intervalMs); }
|
||||
catch (OperationCanceledException) { break; }
|
||||
}
|
||||
|
||||
cts.Cancel();
|
||||
await recvTask;
|
||||
|
||||
static string? GetLanInterfaceIp()
|
||||
{
|
||||
foreach (var nic in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
if (nic.OperationalStatus != OperationalStatus.Up)
|
||||
continue;
|
||||
if (nic.NetworkInterfaceType == NetworkInterfaceType.Loopback)
|
||||
continue;
|
||||
if (nic.Description.Contains("WireGuard", StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
foreach (var addr in nic.GetIPProperties().UnicastAddresses)
|
||||
{
|
||||
if (addr.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
var ip = addr.Address.ToString();
|
||||
if (ip.StartsWith("192.168.") || ip.StartsWith("10.") || ip.StartsWith("172."))
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void ReceiveLoop(Socket sock, CancellationToken ct)
|
||||
{
|
||||
byte[] buffer = new byte[4096];
|
||||
EndPoint fromEp = new IPEndPoint(IPAddress.Any, 0);
|
||||
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
int received;
|
||||
try
|
||||
{
|
||||
if (!sock.Poll(500_000, SelectMode.SelectRead))
|
||||
continue;
|
||||
received = sock.ReceiveFrom(buffer, ref fromEp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] RECV ERROR: {ex.Message}");
|
||||
continue;
|
||||
}
|
||||
|
||||
string text = Encoding.UTF8.GetString(buffer, 0, received).TrimEnd('\n', '\r');
|
||||
if (!text.StartsWith("HKMSTR"))
|
||||
{
|
||||
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] RECV {received} bytes from {fromEp} (no magic)");
|
||||
continue;
|
||||
}
|
||||
|
||||
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] RECV {received} bytes from {fromEp}: {text}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user