Wv2hModule.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. using AspNetTools;
  2. using System;
  3. using System.Configuration;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Runtime.InteropServices;
  9. using System.Threading;
  10. using System.Web;
  11. namespace Wv2h
  12. {
  13. public class Wv2hModule : IHttpModule, IDisposable
  14. {
  15. private static object _lock = new object();
  16. private static Process _process;
  17. private static IPEndPoint _listening;
  18. //TODO: Use pid.lock to hold process
  19. private static void Log(string info)
  20. {
  21. File.AppendAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", "logs.log"), DateTime.Now + " " + info + Environment.NewLine);
  22. }
  23. public void Init(HttpApplication context)
  24. {
  25. Log("WsModule Init, OS:" + Environment.OSVersion);
  26. AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
  27. {
  28. Log(args.ExceptionObject?.ToString());
  29. };
  30. //start v2ray exe
  31. //get it's port
  32. var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data");
  33. lock (_lock)
  34. {
  35. if (_process == null || _process?.HasExited == true)
  36. {
  37. if (_process == null)
  38. {
  39. Log("Init process");
  40. }
  41. else if (_process?.HasExited == true)
  42. {
  43. Log("Last Process Exit. Start new process");
  44. }
  45. _process = new Process
  46. {
  47. StartInfo = {
  48. UseShellExecute = false,
  49. WorkingDirectory = dir,
  50. FileName = Path.Combine(dir, ConfigurationManager.AppSettings["exe"]),
  51. Arguments = "-config="+ConfigurationManager.AppSettings["cfg"]
  52. }
  53. };
  54. _process.Start();
  55. var pid = _process.Id;
  56. Log("Process started, Pid:" + pid);
  57. Thread.Sleep(1000);
  58. var connections = ListenScan.GetAllTcpConnections();
  59. var listens = connections.Where(p => p.owningPid == pid).ToArray();
  60. _listening = new IPEndPoint(IPAddress.Loopback, listens.First().LocalPort);
  61. Log("Listening on " + _listening);
  62. }
  63. else
  64. {
  65. Log("Use exist process");
  66. }
  67. }
  68. //forward ws to v2
  69. context.PostMapRequestHandler += delegate
  70. {
  71. var ctx = HttpContext.Current;
  72. var req = ctx.Request;
  73. if(req.Path.StartsWith("/.")) return; //ACME
  74. Log($"{(ctx.IsWebSocketRequest ? "[WS]" : "")} {req.UserHostAddress} {req.HttpMethod} {req.Path} ");
  75. WebSocketForwardModule.ForwardCurrentContext(
  76. ConfigurationManager.AppSettings["key"],
  77. ConfigurationManager.AppSettings["value"],
  78. _listening, 1024 * int.Parse(ConfigurationManager.AppSettings["bsk"]));
  79. };
  80. }
  81. public void Dispose()
  82. {
  83. Log("WsModule Dispose");
  84. lock (_lock)
  85. {
  86. if (_process?.HasExited != true)
  87. {
  88. Log("Killing process " + _process?.Id);
  89. _process?.Kill();
  90. Log("Process Killed " + _process?.Id);
  91. }
  92. }
  93. }
  94. private static class ListenScan
  95. {
  96. public enum TCP_TABLE_CLASS : int
  97. {
  98. TCP_TABLE_BASIC_LISTENER,
  99. TCP_TABLE_BASIC_CONNECTIONS,
  100. TCP_TABLE_BASIC_ALL,
  101. TCP_TABLE_OWNER_PID_LISTENER,
  102. TCP_TABLE_OWNER_PID_CONNECTIONS,
  103. TCP_TABLE_OWNER_PID_ALL,
  104. TCP_TABLE_OWNER_MODULE_LISTENER,
  105. TCP_TABLE_OWNER_MODULE_CONNECTIONS,
  106. TCP_TABLE_OWNER_MODULE_ALL
  107. }
  108. [StructLayout(LayoutKind.Sequential)]
  109. public struct MIB_TCPROW_OWNER_PID
  110. {
  111. public uint state;
  112. public uint localAddr;
  113. public byte localPort1;
  114. public byte localPort2;
  115. public byte localPort3;
  116. public byte localPort4;
  117. public uint remoteAddr;
  118. public byte remotePort1;
  119. public byte remotePort2;
  120. public byte remotePort3;
  121. public byte remotePort4;
  122. public int owningPid;
  123. public ushort LocalPort
  124. {
  125. get
  126. {
  127. return BitConverter.ToUInt16(
  128. new byte[2] { localPort2, localPort1 }, 0);
  129. }
  130. }
  131. public ushort RemotePort
  132. {
  133. get
  134. {
  135. return BitConverter.ToUInt16(
  136. new byte[2] { remotePort2, remotePort1 }, 0);
  137. }
  138. }
  139. }
  140. [StructLayout(LayoutKind.Sequential)]
  141. public struct MIB_TCPTABLE_OWNER_PID
  142. {
  143. public uint dwNumEntries;
  144. private MIB_TCPROW_OWNER_PID table;
  145. }
  146. [DllImport("iphlpapi.dll", SetLastError = true)]
  147. private static extern uint GetExtendedTcpTable(IntPtr pTcpTable,
  148. ref int dwOutBufLen,
  149. bool sort,
  150. int ipVersion,
  151. TCP_TABLE_CLASS tblClass,
  152. int reserved);
  153. public static MIB_TCPROW_OWNER_PID[] GetAllTcpConnections()
  154. {
  155. MIB_TCPROW_OWNER_PID[] tTable;
  156. int AF_INET = 2; // IP_v4
  157. int buffSize = 0;
  158. // how much memory do we need?
  159. uint ret = GetExtendedTcpTable(IntPtr.Zero,
  160. ref buffSize,
  161. true,
  162. AF_INET,
  163. TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL,
  164. 0);
  165. if (ret != 0 && ret != 122) // 122 insufficient buffer size
  166. throw new Exception("bad ret on check " + ret);
  167. IntPtr buffTable = Marshal.AllocHGlobal(buffSize);
  168. try
  169. {
  170. ret = GetExtendedTcpTable(buffTable,
  171. ref buffSize,
  172. true,
  173. AF_INET,
  174. TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL,
  175. 0);
  176. if (ret != 0)
  177. throw new Exception("bad ret " + ret);
  178. // get the number of entries in the table
  179. MIB_TCPTABLE_OWNER_PID tab =
  180. (MIB_TCPTABLE_OWNER_PID)Marshal.PtrToStructure(
  181. buffTable,
  182. typeof(MIB_TCPTABLE_OWNER_PID));
  183. IntPtr rowPtr = (IntPtr)((long)buffTable +
  184. Marshal.SizeOf(tab.dwNumEntries));
  185. tTable = new MIB_TCPROW_OWNER_PID[tab.dwNumEntries];
  186. for (int i = 0; i < tab.dwNumEntries; i++)
  187. {
  188. MIB_TCPROW_OWNER_PID tcpRow = (MIB_TCPROW_OWNER_PID)Marshal
  189. .PtrToStructure(rowPtr, typeof(MIB_TCPROW_OWNER_PID));
  190. tTable[i] = tcpRow;
  191. // next entry
  192. rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(tcpRow));
  193. }
  194. }
  195. finally
  196. {
  197. // Free the Memory
  198. Marshal.FreeHGlobal(buffTable);
  199. }
  200. return tTable;
  201. }
  202. }
  203. }
  204. }