From 339f817c7e17a9fe29b51ec378499aefc8100684 Mon Sep 17 00:00:00 2001 From: Sardelka Date: Fri, 12 Aug 2022 18:02:43 +0800 Subject: [PATCH] ZeroTier helper --- RageCoop.Core/CoreUtils.cs | 10 ++ RageCoop.Core/Networking/ZeroTierHelper.cs | 130 ++++++++++++++++++ .../{ServerSettings.cs => Settings.cs} | 14 +- 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 RageCoop.Core/Networking/ZeroTierHelper.cs rename RageCoop.Server/{ServerSettings.cs => Settings.cs} (84%) diff --git a/RageCoop.Core/CoreUtils.cs b/RageCoop.Core/CoreUtils.cs index 2d5c56e..a0e2af6 100644 --- a/RageCoop.Core/CoreUtils.cs +++ b/RageCoop.Core/CoreUtils.cs @@ -425,5 +425,15 @@ namespace RageCoop.Core { return BitConverter.ToString(data).Replace("-", String.Empty); } + + /// + /// Convert a string to IP address + /// + /// + /// + public static IPAddress ToIP(this string ip) + { + return IPAddress.Parse(ip); + } } } diff --git a/RageCoop.Core/Networking/ZeroTierHelper.cs b/RageCoop.Core/Networking/ZeroTierHelper.cs new file mode 100644 index 0000000..330a9ff --- /dev/null +++ b/RageCoop.Core/Networking/ZeroTierHelper.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.IO; +using System.Diagnostics; +using System.Net; +using Newtonsoft.Json; +using System.Text.RegularExpressions; + +namespace RageCoop.Core +{ + internal class ZeroTierNetwork + { + public ZeroTierNetwork(string line) + { + // + var v = Regex.Split(line," ").Skip(2).ToArray(); + ID=v[0]; + Name=v[1]; + Mac=v[2]; + Status=v[3]; + Type=v[4]; + Device=v[5]; + foreach (var i in v[6].Split(',')) + { + Addresses.Add(i.Split('/')[0]); + } + } + public string ID; + public string Name; + public string Mac; + public string Status; + public string Type; + public string Device; + public List Addresses=new List(); + + } + internal static class ZeroTierHelper + { + private static readonly string _path="zerotier-cli"; + private static readonly string _arg = ""; + static ZeroTierHelper() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var batpath= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "ZeroTier", "One", "zerotier-cli.bat"); + _arg=$"/c \"{batpath}\" "; + _path="cmd.exe"; + } + var status = RunCommand("status"); + if (!status.StartsWith("200")) + { + throw new Exception("ZeroTier not ready: "+status); + } + } + public static ZeroTierNetwork Join(string networkId, bool waitIpAssign=true) + { + var p = Run("join "+networkId); + var o = p.StandardOutput.ReadToEnd(); + if (!o.StartsWith("200 join OK")) + { + throw new Exception(o+p.StandardError.ReadToEnd()); + } + if (!waitIpAssign) { return ListNetworks()[networkId]; } + while (true) + { + if(ListNetworks().TryGetValue(networkId,out var n)) + { + if (n.Addresses.Count!=0 && (!n.Addresses.Where(x=>x=="-").Any())) + { + return n; + } + System.Threading.Thread.Sleep(100); + } + else + { + break; + } + } + return null; + } + public static void Leave(string networkId) + { + var p = Run("leave "+networkId); + var o = p.StandardOutput.ReadToEnd(); + if (!o.StartsWith("200 leave OK")) + { + throw new Exception(o+p.StandardError.ReadToEnd()); + } + } + public static Dictionary ListNetworks() + { + Dictionary networks=new Dictionary(); + var p = Run("listnetworks"); + var lines=Regex.Split(p.StandardOutput.ReadToEnd(),"\n").Skip(1); + + foreach (var line in lines) + { + var l=line.Replace("\r",""); + if (!string.IsNullOrWhiteSpace(l)) + { + var n = new ZeroTierNetwork(l); + networks.Add(n.ID,n); + } + } + return networks; + } + private static Process Run(string args) + { + var p = new Process(); + p.StartInfo=new ProcessStartInfo() + { + FileName = _path, + Arguments =_arg+args, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + p.Start(); + p.WaitForExit(); + return p; + } + private static string RunCommand(string command) + { + var p = Run(command); + return p.StandardOutput.ReadToEnd()+p.StandardError.ReadToEnd(); + } + } +} diff --git a/RageCoop.Server/ServerSettings.cs b/RageCoop.Server/Settings.cs similarity index 84% rename from RageCoop.Server/ServerSettings.cs rename to RageCoop.Server/Settings.cs index 059a3e4..ba591cf 100644 --- a/RageCoop.Server/ServerSettings.cs +++ b/RageCoop.Server/Settings.cs @@ -3,7 +3,7 @@ /// /// Settings for RageCoop Server /// - public class ServerSettings + public class Settings { /// /// Port to listen for incoming connections @@ -86,8 +86,18 @@ public string AllowedUsernameChars { get; set; } = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-_"; /// - /// Whether to use direct connection between players to send entity information + /// Whether to use direct connection between players to send entity information, needs to be enabled if on WAN for this feature to function properly. /// public bool UseP2P { get; set; } = false; + + /// + /// Whether to enable zerotier VLAN functionality, allowing you to host a server behind NAT firewall, no port forward required. + /// + public bool UseZeroTier { get; set; } = false; + + /// + /// The zerotier network id to join, default value is zerotier's public Earth network. + /// + public string ZeroTierNetworkID = "8056c2e21c000001"; } }