using System; using System.Collections; using System.Collections.Generic; using System.Configuration; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using Tor; using Tor.Config; using MarketData; using MarketData.Utils; using Utility=MarketData.Utils.Utility; // Tor Current Version // https://www.torproject.org/download/tor/ // Tor older versions // https://archive.torproject.org/tor-package-archive/torbrowser/ // Tor Command Line Options // https://2019.www.torproject.org/docs/tor-manual.html.en #pragma warning disable 618, 3021, 169 namespace TorWebClient { public class Program { private static readonly int TIMER_INTERVAL_MINUTES=2; static readonly string agentName="Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"; [DllImport("user32.dll")] static extern bool SetProcessDPIAware(); [DllImport("wininet.dll",SetLastError=true,CharSet=CharSet.Auto)] static extern IntPtr InternetOpen(string lpszAgent,int dwAccessType,string lpszProxyName,string lpszProxyBypass,int dwFlags); [DllImport("wininet.dll",SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool InternetCloseHandle(IntPtr hInternet); [DllImport("wininet.dll",CharSet=CharSet.Ansi,SetLastError=true)] static extern bool InternetSetOption(IntPtr hInternet,INTERNET_OPTION dwOption,IntPtr lpBuffer,int lpdwBufferLength); [DllImport("wininet.dll",CharSet=CharSet.Ansi,SetLastError=true)] static extern bool InternetQueryOptionList(IntPtr handle,INTERNET_OPTION optionFlag,ref INTERNET_PER_CONN_OPTION_LIST optionList,ref int size); [DllImport("Kernel32")] public static extern bool SetConsoleCtrlHandler(HandlerRoutine handler,bool add); [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)] struct INTERNET_PER_CONN_OPTION_LIST { public int Size; public IntPtr Connection; public int OptionCount; public int OptionError; public IntPtr pOptions; } enum INTERNET_OPTION { INTERNET_OPTION_PER_CONNECTION_OPTION=75, INTERNET_OPTION_SETTINGS_CHANGED=39, INTERNET_OPTION_REFRESH=37 } enum INTERNET_PER_CONN_OPTIONENUM { INTERNET_PER_CONN_FLAGS=1, INTERNET_PER_CONN_PROXY_SERVER=2, INTERNET_PER_CONN_PROXY_BYPASS=3, INTERNET_PER_CONN_AUTOCONFIG_URL=4, INTERNET_PER_CONN_AUTODISCOVERY_FLAGS=5, INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL=6, INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS=7, INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME=8, INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL=9, INTERNET_PER_CONN_FLAGS_UI=10 } const int INTERNET_OPEN_TYPE_DIRECT=1; const int INTERNET_OPEN_TYPE_PRECONFIG=0; enum INTERNET_OPTION_PER_CONN_FLAGS { PROXY_TYPE_DIRECT=0x00000001, // direct to net PROXY_TYPE_PROXY=0x00000002, // via named proxy PROXY_TYPE_AUTO_PROXY_URL=0x00000004, // autoproxy URL PROXY_TYPE_AUTO_DETECT=0x00000008 // use autoproxy detection } [StructLayout(LayoutKind.Explicit)] struct INTERNET_PER_CONN_OPTION_OPTIONUNION { [FieldOffset(0)] public int dwValue; [FieldOffset(0)] public IntPtr pszValue; [FieldOffset(0)] public FILETIME ftValue; } [StructLayout(LayoutKind.Sequential)] struct INTERNET_PER_CONN_OPTION { public int dwOption; public INTERNET_PER_CONN_OPTION_OPTIONUNION value; } private static Program instance=null; private RouterCollection allRouters; private volatile bool closing; private CircuitCollection circuits; private Client client; private Timer dispatcherTimer; private Program() { closing=false; dispatcherTimer=new Timer(new TimerCallback(OnDispatcherTimerTick),null,0,(TIMER_INTERVAL_MINUTES*60*1000)); // every minute } public ManualResetEvent ResetEvent{get;set;} public static Program GetInstance() { lock(typeof(Program)) { if(null==instance)instance=new Program(); return instance; } } private void OnDispatcherTimerTick(object sender) { lock(this) { if(null==client) return; MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} DispatcherTimerTick : Total Uploaded: {1}, Total Downloaded: {2}",Utility.DateTimeToStringMMSDDSYYYYHHMMSS(DateTime.Now),client.Status.TotalBytesUploaded.ToString(),client.Status.TotalBytesDownloaded.ToString())); } } private void OnClientBandwidthChanged(object sender,BandwidthEventArgs e) { //lock(this) //{ // MDTrace.WriteLine(LogLevel.DEBUG,"OnClientBandwidthChanged"); // if(closing) return; //} } private void OnClientCircuitsChanged(object sender,EventArgs e) { //lock(this) //{ // MDTrace.WriteLine(LogLevel.DEBUG,"OnClientCircuitsChanged"); // circuits=client.Status.Circuits; // if(closing) return; //} } private void OnClientConnectionsChanged(object sender,EventArgs e) { //lock(this) //{ //MDTrace.WriteLine(LogLevel.DEBUG,"OnClientConnectionsChanged"); //if(closing) return; //} } private void OnClientStreamsChanged(object sender,EventArgs e) { //lock(this) //{ // MDTrace.WriteLine(LogLevel.DEBUG,"OnClientStreamsChanged"); // if(closing) return; //} } private void OnClientShutdown(object sender,EventArgs e) { lock(this) { MDTrace.WriteLine(LogLevel.DEBUG,"OnClientShutdown"); if(!closing) { MDTrace.WriteLine(LogLevel.DEBUG,"OnClientShutdown : The tor client has been terminated without warning"); return; } client=null; } } public void Start() { lock(this) { Process[] previous=Process.GetProcessesByName("tor"); if(previous!=null&&previous.Length>0) { MDTrace.WriteLine(LogLevel.DEBUG,"Killing previous tor instances.."); foreach(Process process in previous) process.Kill(); } MDTrace.WriteLine(LogLevel.DEBUG,"Creating the tor client.."); ClientCreateParams createParams=new ClientCreateParams(); createParams.CaptureTorConsoleOutput=Boolean.Parse(ConfigurationManager.AppSettings["captureTorConsoleOuput"]); createParams.ConfigurationFile=ConfigurationManager.AppSettings["torConfigurationFile"]; createParams.ControlPassword=ConfigurationManager.AppSettings["torControlPassword"]; createParams.ControlPort=Convert.ToInt32(ConfigurationManager.AppSettings["torControlPort"]); createParams.DefaultConfigurationFile=ConfigurationManager.AppSettings["torDefaultConfigurationFile"]; createParams.Path=ConfigurationManager.AppSettings["torPath"]; createParams.SetConfig(ConfigurationNames.AvoidDiskWrites,true); createParams.SetConfig(ConfigurationNames.GeoIPFile,ConfigurationManager.AppSettings["geoipfile"]); createParams.SetConfig(ConfigurationNames.GeoIPv6File,ConfigurationManager.AppSettings["geoip6file"]); createParams.SetConfig(ConfigurationNames.ExitNodes,"{US}"); // making the final exit node a U.S. node provides better ligitimacy MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Current Working Directory:{0}",Directory.GetCurrentDirectory())); MDTrace.WriteLine(LogLevel.DEBUG,String.Format("TORPath:{0}",ConfigurationManager.AppSettings["torPath"])); MDTrace.WriteLine(LogLevel.DEBUG,String.Format("TORConfiguration:{0}",ConfigurationManager.AppSettings["torConfigurationFile"])); MDTrace.WriteLine(LogLevel.DEBUG,String.Format("TORControlPort:{0}",ConfigurationManager.AppSettings["torControlPort"])); MDTrace.WriteLine(LogLevel.DEBUG,String.Format("GEOIPFile:{0}",ConfigurationManager.AppSettings["geoipfile"])); MDTrace.WriteLine(LogLevel.DEBUG,String.Format("GEOIPV6File:{0}",ConfigurationManager.AppSettings["geoip6file"])); CreateTorConfig(createParams.ConfigurationFile); MDTrace.WriteLine(LogLevel.DEBUG,String.Format("TOR Arguments:{0}",createParams.ToString())); client=Client.Create(createParams); try{Thread.Sleep(2500);}catch(Exception){;} client.Configuration.Save(); if(!client.IsRunning) { MDTrace.WriteLine(LogLevel.DEBUG,"The tor client could not be created"); return; } if(!client.Proxy.IsRunning) { MDTrace.WriteLine(LogLevel.DEBUG,"The proxy is not running"); return; } client.Status.BandwidthChanged+=OnClientBandwidthChanged; client.Status.CircuitsChanged+=OnClientCircuitsChanged; client.Status.ORConnectionsChanged+=OnClientConnectionsChanged; client.Status.StreamsChanged+=OnClientStreamsChanged; client.Shutdown+=new EventHandler(OnClientShutdown); MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Setting Proxy Configuration: 127.0.0.1:{0}",client.Proxy.Port)); if(!Program.SetConnectionProxy(string.Format("127.0.0.1:{0}",client.Proxy.Port))) { MDTrace.WriteLine(LogLevel.DEBUG,"The application could not set the default connection proxy. The browser control is not using the tor service as a proxy!"); } allRouters=client.Status.GetAllRouters(); if(null!=allRouters) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Got {0} routers",allRouters.Count)); } //DisplayRouters(allRouters); //if(null==allRouters) //{ // MDTrace.WriteLine(LogLevel.DEBUG,"Could not download routers"); //} } } public bool CreateTorConfig(String pathTorConfig) { try { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Creating {0}",pathTorConfig)); String pathBackupTorConfig=pathTorConfig+".bak"; if(File.Exists(pathTorConfig)) { if(File.Exists(pathBackupTorConfig))File.Delete(pathBackupTorConfig); File.Copy(pathTorConfig, pathBackupTorConfig); File.Delete(pathTorConfig); } FileStream outStream = new FileStream(pathTorConfig,FileMode.CreateNew, FileAccess.Write); StreamWriter streamWriter = new StreamWriter(outStream); streamWriter.WriteLine("# Created by TorWebClient"); streamWriter.WriteLine("# If non-zero, try to write to disk less frequently than we would otherwise."); streamWriter.WriteLine("AvoidDiskWrites 1"); streamWriter.Flush(); streamWriter.Close(); streamWriter.Dispose(); outStream.Close(); outStream.Dispose(); return true; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("CreateTorConfig: Exception {0}",exception.ToString())); return false; } } public void Stop() { lock(this) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} Disposing client.",Utility.DateTimeToStringMMSDDSYYYYHHMMSS(DateTime.Now))); client.Dispose(); } } private String[] GetRouterNicknames(List routers) { lock(this) { List nicknames=new List(); foreach(Router router in routers) { nicknames.Add(router.Nickname); } return nicknames.ToArray(); } } public void DisplayRouters(RouterCollection routers) { lock(this) { if(null==routers)return; MDTrace.WriteLine(LogLevel.DEBUG,"Nickname,Identity,IP Address,Digest,Published,Bandwidth,Country,Flags"); foreach(Router router in routers) { string countryCode = client.Status.GetCountryCode(router); StringBuilder sb=new StringBuilder(); sb.Append(router.Nickname).Append(","); sb.Append(router.Identity).Append(","); sb.Append(router.IPAddress).Append(","); sb.Append(router.Digest).Append(","); sb.Append((router.Publication == DateTime.MinValue ? "Unknown" : Convert.ToString(router.Publication))).Append(","); sb.Append(router.Bandwidth).Append(","); sb.Append(countryCode).Append(","); sb.Append(router.Flags); MDTrace.WriteLine(LogLevel.DEBUG,sb.ToString()); } } } public void DisplayRouters(List routers) { lock(this) { MDTrace.WriteLine(LogLevel.DEBUG,"Nickname,Identity,IP Address,Digest,Published,Bandwidth,Country,Flags"); foreach(Router router in routers) { string countryCode=client.Status.GetCountryCode(router); StringBuilder sb=new StringBuilder(); sb.Append(router.Nickname).Append(","); sb.Append(router.Identity).Append(","); sb.Append(router.IPAddress).Append(","); sb.Append(router.Digest).Append(","); sb.Append((router.Publication==DateTime.MinValue?"Unknown":Convert.ToString(router.Publication))).Append(","); sb.Append(router.Bandwidth).Append(","); sb.Append(countryCode).Append(","); sb.Append(router.Flags); MDTrace.WriteLine(LogLevel.DEBUG,sb.ToString()); } } } public static bool SetConnectionProxy(string proxyServer) { IntPtr hInternet=InternetOpen(agentName,INTERNET_OPEN_TYPE_DIRECT,null,null,0); INTERNET_PER_CONN_OPTION[] options=new INTERNET_PER_CONN_OPTION[2]; options[0]=new INTERNET_PER_CONN_OPTION(); options[0].dwOption=(int)INTERNET_PER_CONN_OPTIONENUM.INTERNET_PER_CONN_FLAGS; options[0].value.dwValue=(int)INTERNET_OPTION_PER_CONN_FLAGS.PROXY_TYPE_PROXY; options[1]=new INTERNET_PER_CONN_OPTION(); options[1].dwOption=(int)INTERNET_PER_CONN_OPTIONENUM.INTERNET_PER_CONN_PROXY_SERVER; options[1].value.pszValue=Marshal.StringToHGlobalAnsi(proxyServer); IntPtr buffer=Marshal.AllocCoTaskMem(Marshal.SizeOf(options[0])+Marshal.SizeOf(options[1])); IntPtr current=buffer; for(int i=0;i