Skip to content

Commit

Permalink
Refine ProxiFyre's Configuration and Introduce Service Capabilities
Browse files Browse the repository at this point in the history
- Integrated Topshelf to enable ProxiFyre to run as a Windows Service, while retaining its functionality as a standalone application with Control-C termination. Resolves: #12
- Revamped configuration to support selective protocols (TCP, UDP, or both) for individual proxy instances. See: #11
- Adopted NLog for enhanced logging, with output directed to `/logs` in the application directory. Addresses: #13

This enhancement empowers users with versatile proxy management, seamless service operation, and streamlined log tracking.
  • Loading branch information
wiresock committed Aug 31, 2023
1 parent 40d1730 commit 75c0d8a
Show file tree
Hide file tree
Showing 12 changed files with 309 additions and 117 deletions.
13 changes: 13 additions & 0 deletions ProxiFyre/NLog.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<targets>
<target name="file" xsi:type="File" fileName="${basedir}/logs/logfile_${date:format=yyyy-MM-dd}.txt" />
</targets>

<rules>
<logger name="*" minlevel="Info" writeTo="file" />
</rules>
</nlog>
184 changes: 121 additions & 63 deletions ProxiFyre/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,106 +2,164 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using NLog;
using NLog.Config;
using Socksifier;
using Topshelf;
using LogLevel = Socksifier.LogLevel;

namespace ProxiFyre
{
// Main class for the SOCKS proxy application
internal class Program
public class ProxiFyreService
{
//[
//{
// "appNames": ["chrome", "chrome_canary"],
// "socks5ProxyEndpoint": "158.101.205.51:1080",
// "username": "username1",
// "password": "password1"
//},
//{
// "appNames": ["firefox", "firefox_dev"],
// "socks5ProxyEndpoint": "159.101.205.52:1080",
// "username": "username2",
// "password": "password2"
//}
//]
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
private Socksifier.Socksifier _socksify;

private class AppSettings
public void Start()
{
public List<string> AppNames { get; set; }
public string Socks5ProxyEndpoint { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
// Get the current executable path
var executablePath = Assembly.GetExecutingAssembly().Location;
var directoryPath = Path.GetDirectoryName(executablePath);

// Entry point of the application
private static void Main(string[] args)
{
LogLevel logLevel;
// Form the path to app-config.json
var configFilePath = Path.Combine(directoryPath ?? string.Empty, "app-config.json");

// Parse the log level from the command line arguments
if (args.Length > 0 && Enum.TryParse<LogLevel>(args[0], true, out var parsedLogLevel))
{
logLevel = parsedLogLevel;
}
else
{
// If no valid log level provided, default to LogLevel.None
logLevel = LogLevel.None;
}
// Form the path to app-config.json
var logConfigFilePath = Path.Combine(directoryPath ?? string.Empty, "NLog.config");

// Load the configuration from JSON
var appSettingsList = JsonConvert.DeserializeObject<List<AppSettings>>(File.ReadAllText("app-config.json"));
var serviceSettings = JsonConvert.DeserializeObject<ProxiFyreSettings>(File.ReadAllText(configFilePath));

LogManager.Configuration = new XmlLoggingConfiguration(logConfigFilePath);

// Handle the global log level from the configuration
var logLevel = Enum.TryParse<LogLevel>(serviceSettings.LogLevel, true, out var globalLogLevel)
? globalLogLevel
: LogLevel.None;

// Get an instance of the Socksifier
var wiresock = Socksifier.Socksifier.GetInstance(logLevel);
_socksify = Socksifier.Socksifier.GetInstance(logLevel);

// Attach the LogPrinter method to the LogEvent event
wiresock.LogEvent += LogPrinter;
_socksify.LogEvent += LogPrinter;

// Set the limit for logging and the interval between logs
wiresock.LogLimit = 100;
wiresock.LogEventInterval = 1000;
_socksify.LogLimit = 100;
_socksify.LogEventInterval = 1000;

foreach (var appSettings in appSettingsList)
foreach (var appSettings in serviceSettings.Proxies)
{
// Add the defined SOCKS5 proxies
var oracle = wiresock.AddSocks5Proxy(appSettings.Socks5ProxyEndpoint, appSettings.Username,
appSettings.Password, true);
var proxy = _socksify.AddSocks5Proxy(appSettings.Socks5ProxyEndpoint, appSettings.Username,
appSettings.Password, appSettings.SupportedProtocolsParse,
true); // Assuming the AddSocks5Proxy method supports a list of protocols

foreach (var appName in appSettings.AppNames)
// Associate the defined application names to the proxies
if (oracle.ToInt64() != -1 && wiresock.AssociateProcessNameToProxy(appName, oracle))
Console.WriteLine(
$"Successfully associated {appName} to {appSettings.Socks5ProxyEndpoint} SOCKS5 proxy!");
if (proxy.ToInt64() != -1 && _socksify.AssociateProcessNameToProxy(appName, proxy))
_logger.Info(
$"Successfully associated {appName} to {appSettings.Socks5ProxyEndpoint} SOCKS5 proxy with protocols {string.Join(", ", appSettings.SupportedProtocols)}!");
}

// Start the Socksifier, if it fails, dispose and exit
if (!wiresock.Start())
{
Console.WriteLine("Failed to start SOCKS PROXY!");
wiresock.Dispose();
return;
}
_socksify.Start();

// Inform user that the application is running and how to stop it
Console.WriteLine("Press any key to stop");

// Wait for a key press before disposing and exiting
Console.ReadKey();
_logger.Info("ProxiFyre Service is running...");
}

public void Stop()
{
// Dispose of the Socksifier before exiting
wiresock.Dispose();
_socksify.Dispose();
_logger.Info("ProxiFyre Service has stopped.");
LogManager.Shutdown();
}


// Method to handle logging events
private static void LogPrinter(object sender, LogEventArgs e)
{
// Loop through each log entry and print it to the console
// Loop through each log entry and log it using NLog
foreach (var entry in e.Log.Where(entry => entry != null))
Console.WriteLine(
// ReSharper disable once PossibleLossOfFraction
$"{new DateTime(1970, 1, 1).AddSeconds(entry.TimeStamp / 1000)}::{entry.Event}::{entry.Description}::{entry.Data}");
{
var logMessage =
$"{new DateTime(1970, 1, 1).AddSeconds(entry.TimeStamp / 1000)}::{entry.Event}::{entry.Description}::{entry.Data}";
_logger.Info(logMessage);
}
}

//{
// "logLevel": "Warning",
// "proxies": [
// {
// "appNames": ["chrome", "chrome_canary"],
// "socks5ProxyEndpoint": "158.101.205.51:1080",
// "username": "username1",
// "password": "password1",
// "supportedProtocols": ["TCP", "UDP"]
// },
// {
// "appNames": ["firefox", "firefox_dev"],
// "socks5ProxyEndpoint": "159.101.205.52:1080",
// "username": "username2",
// "password": "password2",
// "supportedProtocols": ["TCP"]
// }
// ]
//}

private class ProxiFyreSettings
{
public string LogLevel { get; set; }
public List<AppSettings> Proxies { get; set; }
}

private class AppSettings
{
public List<string> AppNames { get; set; }
public string Socks5ProxyEndpoint { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public List<string> SupportedProtocols { get; set; } // Keep the original list for parsing

public SupportedProtocolsEnum SupportedProtocolsParse // New property for the enum
{
get
{
if (SupportedProtocols.Count == 0 ||
(SupportedProtocols.Contains("TCP") && SupportedProtocols.Contains("UDP")))
return SupportedProtocolsEnum.BOTH;
if (SupportedProtocols.Contains("TCP"))
return SupportedProtocolsEnum.TCP;
return SupportedProtocols.Contains("UDP")
? SupportedProtocolsEnum.UDP
: SupportedProtocolsEnum.BOTH;
}
}
}
}

internal class Program
{
private static void Main()
{
HostFactory.Run(x =>
{
x.Service<ProxiFyreService>(s =>
{
s.ConstructUsing(name => new ProxiFyreService());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
x.RunAsLocalSystem();
x.SetDescription("ProxiFyre - SOCKS5 Proxifier Service");
x.SetDisplayName("ProxiFyre Service");
x.SetServiceName("ProxiFyreService");
});
}
}
}
1 change: 0 additions & 1 deletion ProxiFyre/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
Expand Down
18 changes: 18 additions & 0 deletions ProxiFyre/ProxiFyre.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,39 @@
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.2.3\lib\net46\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="Topshelf, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b800c4cfcdeea87b, processorArchitecture=MSIL">
<HintPath>..\packages\Topshelf.4.3.0\lib\net452\Topshelf.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="NLog.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions ProxiFyre/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@

<packages>
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net472" />
<package id="NLog" version="5.2.3" targetFramework="net472" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net472" />
<package id="Topshelf" version="4.3.0" targetFramework="net472" />
</packages>
65 changes: 49 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
# ProxiFyre: SOCKS5 Proxifier for Windows

This project is an advanced version of the Windows Packet Filter [socksify](https://github.com/wiresock/ndisapi/tree/master/examples/cpp/socksify) demo. It enhances the base version with added support for UDP and multiple proxy instances. Additionally, it now reads its configuration from an `app-config.json` file.
ProxiFyre elevates the foundational capabilities of the Windows Packet Filter's [socksify](https://github.com/wiresock/ndisapi/tree/master/examples/cpp/socksify) demo, introducing robust enhancements. Not only does it seamlessly integrate support for UDP, but it also empowers users with the flexibility of managing multiple proxy instances. Streamlining its configuration process, ProxiFyre now dynamically sources its settings from an `app-config.json` file, ensuring a more intuitive and user-friendly experience. Furthermore, with its adaptability in mind, ProxiFyre can be effortlessly configured to run as a Windows Service, providing continuous operation without the need for manual intervention.

## Configuration

The application now uses a configuration file named `app-config.json`. This JSON file should contain an array of configurations for different applications. Each configuration object should have the following properties:
The application uses a configuration file named `app-config.json`. This JSON file should contain configurations for different applications. Each configuration object should have the following properties:

- `appNames`: An array of strings representing the names of applications this configuration applies to.
- `socks5ProxyEndpoint`: A string that specifies the SOCKS5 proxy endpoint.
- `username`: A string that specifies the username for the proxy.
- `password`: A string that specifies the password for the proxy.
- `supportedProtocols`: An array of strings specifying the supported protocols (e.g., "TCP", "UDP").

Here is an example configuration:

```json
[
{
"appNames": ["chrome", "chrome_canary"],
"socks5ProxyEndpoint": "158.101.205.51:1080",
"username": "username1",
"password": "password1"
},
{
"appNames": ["firefox", "firefox_dev"],
"socks5ProxyEndpoint": "159.101.205.52:1080",
"username": "username2",
"password": "password2"
}
]
{
"logLevel": "None",
"proxies": [
{
"appNames": ["chrome", "chrome_canary"],
"socks5ProxyEndpoint": "158.101.205.51:1080",
"username": "username1",
"password": "password1",
"supportedProtocols": ["TCP", "UDP"]
},
{
"appNames": ["firefox", "firefox_dev"],
"socks5ProxyEndpoint": "159.101.205.52:1080",
"username": "username2",
"password": "password2",
"supportedProtocols": ["TCP"]
}
]
}
```

## Quick Start Guide
Expand All @@ -50,6 +56,33 @@ This guide provides step-by-step instructions on how to set up and run the Proxi

5. **Run the Application**: Navigate to the directory where you extracted the software. Find the main application executable (`.exe` file) and run it. It's recommended to run the application as an administrator to ensure all functionalities work as expected.

### Running as a Service

ProxiFyre can be installed and run as a Windows service. Follow these steps:

1. Open a command prompt as an administrator.
2. Navigate to the directory containing `ProxiFyre.exe`.
3. Use the following command to install the service:
```
ProxiFyre.exe install
```
4. Start the service with:
```
ProxiFyre.exe start
```
5. To stop the service, use:
```
ProxiFyre.exe stop
```
6. If you wish to uninstall the service, use:
```
ProxiFyre.exe uninstall
```

### Logging

Logs are saved in the application folder under the `/logs` directory. The details and verbosity of the logs depend on the configuration set in the `app-config.json` file.

## Build Prerequisites

Before starting the build process, ensure the following requirements are met:
Expand Down
Loading

0 comments on commit 75c0d8a

Please sign in to comment.