diff --git a/RageCoop.Client/Menus/Sub/ServersMenu.cs b/RageCoop.Client/Menus/Sub/ServersMenu.cs index 44c66f7..7209c39 100644 --- a/RageCoop.Client/Menus/Sub/ServersMenu.cs +++ b/RageCoop.Client/Menus/Sub/ServersMenu.cs @@ -6,6 +6,7 @@ using System.Drawing; using System.Net; using System.Threading; using RageCoop.Core; +using GTA.UI; namespace RageCoop.Client.Menus { @@ -81,7 +82,15 @@ namespace RageCoop.Client.Menus try { Menu.Visible = false; - + if (server.ZeroTier) + { + address=$"{server.ZeroTierAddress}:{server.Port}"; + Main.QueueAction(() => { Notification.Show($"~y~Joining ZeroTier network... {address}"); }); + if (ZeroTierHelper.Join(server.ZeroTierNetWorkID)==null) + { + throw new Exception("Failed to obtain ZeroTier network IP"); + } + } Networking.ToggleConnection(address); #if !NON_INTERACTIVE CoopMenu.ServerIpItem.AltTitle = address; @@ -93,7 +102,7 @@ namespace RageCoop.Client.Menus } catch (Exception ex) { - GTA.UI.Notification.Show($"~r~{ex.Message}"); + Notification.Show($"~r~{ex.Message}"); } }; Menu.Add(tmpItem); diff --git a/RageCoop.Client/Networking/Networking.cs b/RageCoop.Client/Networking/Networking.cs index d361338..766ce9a 100644 --- a/RageCoop.Client/Networking/Networking.cs +++ b/RageCoop.Client/Networking/Networking.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; - +using GTA.UI; namespace RageCoop.Client { internal static partial class Networking @@ -34,7 +34,7 @@ namespace RageCoop.Client else if (IsConnecting) { _publicKeyReceived.Set(); IsConnecting = false; - GTA.UI.Notification.Show("Connection has been canceled"); + Notification.Show("Connection has been canceled"); } else { @@ -84,10 +84,10 @@ namespace RageCoop.Client try { ProcessMessage(m); } catch (Exception ex) { Main.Logger.Error(ex); } }; - Main.QueueAction(() => { GTA.UI.Notification.Show($"~y~Trying to connect..."); }); + Main.QueueAction(() => { Notification.Show($"~y~Trying to connect..."); }); Menus.CoopMenu._serverConnectItem.Enabled=false; Security.Regen(); - if (!GetServerPublicKey(address)) + if (!GetServerPublicKey(ip[0],int.Parse(ip[1]))) { Menus.CoopMenu._serverConnectItem.Enabled=true; throw new TimeoutException("Failed to retrive server's public key"); @@ -112,7 +112,7 @@ namespace RageCoop.Client catch (Exception ex) { Main.Logger.Error("Cannot connect to server: ", ex); - Main.QueueAction(() => GTA.UI.Notification.Show("Cannot connect to server: "+ex.Message)); + Main.QueueAction(() => Notification.Show("Cannot connect to server: "+ex.Message)); } IsConnecting=false; }); @@ -147,13 +147,12 @@ namespace RageCoop.Client #endregion // -- PLAYER -- #region -- GET -- - private static bool GetServerPublicKey(string address, int timeout = 10000) + private static bool GetServerPublicKey(string host,int port, int timeout = 10000) { Security.ServerRSA=null; var msg = Peer.CreateMessage(); new Packets.PublicKeyRequest().Pack(msg); - var adds = address.Split(':'); - Peer.SendUnconnectedMessage(msg, adds[0], int.Parse(adds[1])); + Peer.SendUnconnectedMessage(msg, host, port); return _publicKeyReceived.WaitOne(timeout) && Security.ServerRSA!=null; } diff --git a/RageCoop.Core/CoreUtils.cs b/RageCoop.Core/CoreUtils.cs index a0e2af6..937a79a 100644 --- a/RageCoop.Core/CoreUtils.cs +++ b/RageCoop.Core/CoreUtils.cs @@ -6,10 +6,12 @@ using System.Threading.Tasks; using GTA.Math; using System.Security.Cryptography; using System.Net; +using System.Net.Http; using System.Net.Sockets; using System.IO; using System.Runtime.CompilerServices; using Lidgren.Network; +using Newtonsoft.Json; [assembly: InternalsVisibleTo("RageCoop.Server")] [assembly: InternalsVisibleTo("RageCoop.Client")] @@ -152,7 +154,7 @@ namespace RageCoop.Core return endPoint.Address; } } - private static IPAddress GetIPfromHost(string p) + public static IPAddress GetIPfromHost(string p) { var hosts = Dns.GetHostAddresses(p); @@ -161,7 +163,34 @@ namespace RageCoop.Core return hosts[0]; } + public static IpInfo GetIPInfo() + { + // TLS only + ServicePointManager.Expect100Continue = true; + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; + var httpClient = new HttpClient(); + HttpResponseMessage response = httpClient.GetAsync("https://ipinfo.io/json").GetAwaiter().GetResult(); + if (response.StatusCode != HttpStatusCode.OK) + { + throw new Exception($"IPv4 request failed! [{(int)response.StatusCode}/{response.ReasonPhrase}]"); + } + + string content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + return JsonConvert.DeserializeObject(content); + } + + + + } + internal struct IpInfo + { + [JsonProperty("ip")] + public string Address { get; set; } + + [JsonProperty("country")] + public string Country { get; set; } } internal static class Extensions { diff --git a/RageCoop.Core/Networking/ServerInfo.cs b/RageCoop.Core/Networking/ServerInfo.cs index fd1996f..f0fd955 100644 --- a/RageCoop.Core/Networking/ServerInfo.cs +++ b/RageCoop.Core/Networking/ServerInfo.cs @@ -12,7 +12,7 @@ namespace RageCoop.Core public string Address { get; set; } [JsonProperty("port")] - public int Port { get; set; } + public string Port { get; set; } [JsonProperty("name")] public string Name { get; set; } @@ -21,10 +21,10 @@ namespace RageCoop.Core public string Version { get; set; } [JsonProperty("players")] - public int Players { get; set; } + public string Players { get; set; } [JsonProperty("maxPlayers")] - public int MaxPlayers { get; set; } + public string MaxPlayers { get; set; } [JsonProperty("country")] public string Country { get; set; } @@ -40,5 +40,19 @@ namespace RageCoop.Core [JsonProperty("language")] public string Language { get; set; } + + + [JsonProperty("useP2P")] + public bool P2P { get; set; } + + [JsonProperty("useZT")] + public bool ZeroTier { get; set; } + + [JsonProperty("ztID")] + public string ZeroTierNetWorkID { get; set; } + + + [JsonProperty("ztAddress")] + public string ZeroTierAddress { get; set; } } } diff --git a/RageCoop.Core/Networking/ZeroTierHelper.cs b/RageCoop.Core/Networking/ZeroTierHelper.cs index 330a9ff..1b49097 100644 --- a/RageCoop.Core/Networking/ZeroTierHelper.cs +++ b/RageCoop.Core/Networking/ZeroTierHelper.cs @@ -54,7 +54,7 @@ namespace RageCoop.Core throw new Exception("ZeroTier not ready: "+status); } } - public static ZeroTierNetwork Join(string networkId, bool waitIpAssign=true) + public static ZeroTierNetwork Join(string networkId, int timeout=10000) { var p = Run("join "+networkId); var o = p.StandardOutput.ReadToEnd(); @@ -62,10 +62,12 @@ namespace RageCoop.Core { throw new Exception(o+p.StandardError.ReadToEnd()); } - if (!waitIpAssign) { return ListNetworks()[networkId]; } - while (true) + if (timeout==0) { return Networks[networkId]; } + int i = 0; + while (i<=timeout) { - if(ListNetworks().TryGetValue(networkId,out var n)) + i+=100; + if(Networks.TryGetValue(networkId,out var n)) { if (n.Addresses.Count!=0 && (!n.Addresses.Where(x=>x=="-").Any())) { @@ -89,22 +91,24 @@ namespace RageCoop.Core throw new Exception(o+p.StandardError.ReadToEnd()); } } - public static Dictionary ListNetworks() + public static Dictionary Networks { - Dictionary networks=new Dictionary(); - var p = Run("listnetworks"); - var lines=Regex.Split(p.StandardOutput.ReadToEnd(),"\n").Skip(1); + get { + 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)) + foreach (var line in lines) { - var n = new ZeroTierNetwork(l); - networks.Add(n.ID,n); + var l = line.Replace("\r", ""); + if (!string.IsNullOrWhiteSpace(l)) + { + var n = new ZeroTierNetwork(l); + networks.Add(n.ID, n); + } } + return networks; } - return networks; } private static Process Run(string args) { @@ -116,6 +120,7 @@ namespace RageCoop.Core UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, + CreateNoWindow=true, }; p.Start(); p.WaitForExit(); diff --git a/RageCoop.Server/Networking/Server.cs b/RageCoop.Server/Networking/Server.cs index 6c3dcbc..c84f948 100644 --- a/RageCoop.Server/Networking/Server.cs +++ b/RageCoop.Server/Networking/Server.cs @@ -20,14 +20,6 @@ using RageCoop.Core.Scripting; namespace RageCoop.Server { - internal struct IpInfo - { - [JsonProperty("ip")] - public string Address { get; set; } - - [JsonProperty("country")] - public string Country { get; set; } - } /// /// The instantiable RageCoop server class @@ -121,18 +113,10 @@ namespace RageCoop.Server ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; HttpClient httpClient = new(); - IpInfo info; try { - HttpResponseMessage response = await httpClient.GetAsync("https://ipinfo.io/json"); - if (response.StatusCode != HttpStatusCode.OK) - { - throw new Exception($"IPv4 request failed! [{(int)response.StatusCode}/{response.ReasonPhrase}]"); - } - - string content = await response.Content.ReadAsStringAsync(); - info = JsonConvert.DeserializeObject(content); + info = CoreUtils.GetIPInfo(); Logger?.Info($"Your public IP is {info.Address}, announcing to master server..."); } catch (Exception ex) @@ -142,24 +126,29 @@ namespace RageCoop.Server } while (!_stopping) { - var serverInfo = new ServerInfo - { - Address = info.Address, - Port=Settings.Port, - Country=info.Country, - Name=Settings.Name, - Version=_compatibleVersion.Replace("_", "."), - Players=MainNetServer.ConnectionsCount, - MaxPlayers=Settings.MaxPlayers, - Description=Settings.Description, - Website=Settings.Website, - GameMode=Settings.GameMode, - Language=Settings.Language, - }; - string msg = JsonConvert.SerializeObject(serverInfo); HttpResponseMessage response = null; try { + var serverInfo = new ServerInfo + { + Address = info.Address, + Port=Settings.Port.ToString(), + Country=info.Country, + Name=Settings.Name, + Version=_compatibleVersion.Replace("_", "."), + Players=MainNetServer.ConnectionsCount.ToString(), + MaxPlayers=Settings.MaxPlayers.ToString(), + Description=Settings.Description, + Website=Settings.Website, + GameMode=Settings.GameMode, + Language=Settings.Language, + P2P=Settings.UseP2P, + ZeroTier=Settings.UseZeroTier, + ZeroTierNetWorkID=Settings.UseZeroTier ? Settings.ZeroTierNetworkID : "", + ZeroTierAddress=Settings.UseZeroTier ? ZeroTierHelper.Networks[Settings.ZeroTierNetworkID].Addresses.Where(x => !x.Contains(":")).First() : "0.0.0.0", + }; + string msg = JsonConvert.SerializeObject(serverInfo); + var realUrl = Util.GetFinalRedirect(Settings.MasterServer); response = await httpClient.PostAsync(realUrl, new StringContent(msg, Encoding.UTF8, "application/json")); } @@ -227,6 +216,19 @@ namespace RageCoop.Server Logger?.Info($"Compatible RAGECOOP versions: {_compatibleVersion.Replace('_', '.')}.x"); Logger?.Info("================"); + if (Settings.UseZeroTier) + { + Logger?.Info($"Joining ZeroTier network: "+Settings.ZeroTierNetworkID); + if (ZeroTierHelper.Join(Settings.ZeroTierNetworkID)==null) + { + throw new Exception("Failed to obtain ZeroTier network IP"); + } + } + else if (Settings.UseP2P) + { + Logger?.Warning("ZeroTier is not enabled, P2P connection may not work as expected."); + } + // 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP NetPeerConfiguration config = new("623c92c287cc392406e7aaaac1c0f3b0") {