Browse Source

System proxy support for Remote Access Service

e.g. Dial-up connection and VPN

- use INTERNET_OPTION_PROXY_SETTINGS_CHANGED instead of INTERNET_OPTION_SETTINGS_CHANGED

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
tags/3.3.4
Syrone Wong 8 years ago
parent
commit
1c1cc62235
6 changed files with 217 additions and 14 deletions
  1. +7
    -1
      shadowsocks-csharp/Util/SystemProxy/INTERNET_OPTION.cs
  2. +1
    -1
      shadowsocks-csharp/Util/SystemProxy/INTERNET_PER_CONN_OPTION_LIST.cs
  3. +1
    -1
      shadowsocks-csharp/Util/SystemProxy/NativeMethods.cs
  4. +151
    -0
      shadowsocks-csharp/Util/SystemProxy/RAS.cs
  5. +56
    -11
      shadowsocks-csharp/Util/SystemProxy/WinINet.cs
  6. +1
    -0
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 7
- 1
shadowsocks-csharp/Util/SystemProxy/INTERNET_OPTION.cs View File

@@ -30,7 +30,13 @@ namespace Shadowsocks.Util.SystemProxy
INTERNET_OPTION_SETTINGS_CHANGED = 39,
// Causes the proxy data to be reread from the registry for a handle.
INTERNET_OPTION_REFRESH = 37
INTERNET_OPTION_REFRESH = 37,
// Alerts the current WinInet instance that proxy settings have changed
// and that they must update with the new settings.
// To alert all available WinInet instances, set the Buffer parameter of
// InternetSetOption to NULL and BufferLength to 0 when passing this option.
INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 95
}
}

+ 1
- 1
shadowsocks-csharp/Util/SystemProxy/INTERNET_PER_CONN_OPTION_LIST.cs View File

@@ -22,7 +22,7 @@ using System.Runtime.InteropServices;
namespace Shadowsocks.Util.SystemProxy
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct INTERNET_PER_CONN_OPTION_LIST : IDisposable
{
public int Size;


+ 1
- 1
shadowsocks-csharp/Util/SystemProxy/NativeMethods.cs View File

@@ -26,7 +26,7 @@ namespace Shadowsocks.Util.SystemProxy
/// <summary>
/// Sets an Internet option.
/// </summary>
[DllImport("wininet.dll", CharSet = CharSet.Ansi, SetLastError = true)]
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool InternetSetOption(
IntPtr hInternet,
INTERNET_OPTION dwOption,


+ 151
- 0
shadowsocks-csharp/Util/SystemProxy/RAS.cs View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Shadowsocks.Util.SystemProxy
{
public static class RAS
{
private enum RasFieldSizeConstants
{
#region original header
//#if (WINVER >= 0x400)
//#define RAS_MaxEntryName 256
//#define RAS_MaxDeviceName 128
//#define RAS_MaxCallbackNumber RAS_MaxPhoneNumber
//#else
//#define RAS_MaxEntryName 20
//#define RAS_MaxDeviceName 32
//#define RAS_MaxCallbackNumber 48
//#endif
#endregion
RAS_MaxEntryName = 256,
RAS_MaxPath = 260
}
private const int ERROR_SUCCESS = 0;
private const int RASBASE = 600;
private const int ERROR_BUFFER_TOO_SMALL = RASBASE + 3;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct RasEntryName
{
#region original header
//#define RASENTRYNAMEW struct tagRASENTRYNAMEW
//RASENTRYNAMEW
//{
// DWORD dwSize;
// WCHAR szEntryName[RAS_MaxEntryName + 1];
//
//#if (WINVER >= 0x500)
// //
// // If this flag is REN_AllUsers then its a
// // system phonebook.
// //
// DWORD dwFlags;
// WCHAR szPhonebookPath[MAX_PATH + 1];
//#endif
//};
//
//#define RASENTRYNAMEA struct tagRASENTRYNAMEA
//RASENTRYNAMEA
//{
// DWORD dwSize;
// CHAR szEntryName[RAS_MaxEntryName + 1];
//
//#if (WINVER >= 0x500)
// DWORD dwFlags;
// CHAR szPhonebookPath[MAX_PATH + 1];
//#endif
//};
#endregion
public int dwSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=(int)RasFieldSizeConstants.RAS_MaxEntryName + 1)]
public string szEntryName;
public int dwFlags;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=(int)RasFieldSizeConstants.RAS_MaxPath + 1)]
public string szPhonebookPath;
}
[DllImport("rasapi32.dll", CharSet = CharSet.Auto)]
private static extern uint RasEnumEntries(
string reserved, // reserved, must be NULL
string lpszPhonebook, // pointer to full path and file name of phone-book file
[In, Out] RasEntryName[] lprasentryname, // buffer to receive phone-book entries
ref int lpcb, // size in bytes of buffer
out int lpcEntries // number of entries written to buffer
);
/// <summary>
/// Get all entries from RAS
/// </summary>
/// <param name="allConns"></param>
/// <returns>
/// 0: success with entries
/// 1: success but no entries found
/// 2: failed
/// </returns>
public static uint GetAllConns(ref string[] allConns)
{
int lpNames = 1;
int entryNameSize = 0;
int lpSize = 0;
uint retval = ERROR_SUCCESS;
RasEntryName[] names = null;
entryNameSize = Marshal.SizeOf(typeof(RasEntryName));
lpSize = lpNames * entryNameSize;
names = new RasEntryName[lpNames];
names[0].dwSize = entryNameSize;
retval = RAS.RasEnumEntries(null, null, names, ref lpSize, out lpNames);
//if we have more than one connection, we need to resize
if (retval == ERROR_BUFFER_TOO_SMALL)
{
names = new RasEntryName[lpNames];
for (int i = 0; i < names.Length; i++)
{
names[i].dwSize = entryNameSize;
}
retval = RAS.RasEnumEntries(null, null, names, ref lpSize, out lpNames);
}
if (retval == ERROR_SUCCESS)
{
if (lpNames == 0)
{
// no entries found.
return 1;
}
allConns = new string[names.Length];
for (int i = 0; i < names.Length; i++)
{
allConns[i] = names[i].szEntryName;
}
return 0;
}
else
{
return 2;
}
}
}
}

+ 56
- 11
shadowsocks-csharp/Util/SystemProxy/WinINet.cs View File

@@ -19,17 +19,19 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Shadowsocks.Controller;
namespace Shadowsocks.Util.SystemProxy
{
public static class WinINet
{
/// <summary>
/// Set IE settings for LAN connection.
/// Set IE settings.
/// </summary>
public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL)
private static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL, string connName)
{
List<INTERNET_PER_CONN_OPTION> _optionlist = new List<INTERNET_PER_CONN_OPTION>();
if (enable)
{
if (global)
@@ -38,17 +40,18 @@ namespace Shadowsocks.Util.SystemProxy
_optionlist.Add(new INTERNET_PER_CONN_OPTION
{
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI,
Value = { dwValue = (int)INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_PROXY }
Value = { dwValue = (int)(INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_PROXY
| INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_DIRECT) }
});
_optionlist.Add(new INTERNET_PER_CONN_OPTION
{
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_SERVER,
Value = { pszValue = Marshal.StringToHGlobalAnsi(proxyServer) }
Value = { pszValue = Marshal.StringToHGlobalAuto(proxyServer) }
});
_optionlist.Add(new INTERNET_PER_CONN_OPTION
{
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_BYPASS,
Value = { pszValue = Marshal.StringToHGlobalAnsi("<local>") }
Value = { pszValue = Marshal.StringToHGlobalAuto("<local>") }
});
}
else
@@ -62,7 +65,7 @@ namespace Shadowsocks.Util.SystemProxy
_optionlist.Add(new INTERNET_PER_CONN_OPTION
{
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_AUTOCONFIG_URL,
Value = { pszValue = Marshal.StringToHGlobalAnsi(pacURL) }
Value = { pszValue = Marshal.StringToHGlobalAuto(pacURL) }
});
}
}
@@ -101,8 +104,9 @@ namespace Shadowsocks.Util.SystemProxy
// Return the unmanaged size of an object in bytes.
optionList.Size = Marshal.SizeOf(optionList);
// IntPtr.Zero means LAN connection.
optionList.Connection = IntPtr.Zero;
optionList.Connection = connName.IsNullOrEmpty()
? IntPtr.Zero // NULL means LAN
: Marshal.StringToHGlobalAuto(connName); // TODO: not working if contains Chinese
optionList.OptionCount = _optionlist.Count;
optionList.OptionError = 0;
@@ -132,15 +136,56 @@ namespace Shadowsocks.Util.SystemProxy
// Notify the system that the registry settings have been changed and cause
// the proxy data to be reread from the registry for a handle.
NativeMethods.InternetSetOption(
// bReturn = NativeMethods.InternetSetOption(
// IntPtr.Zero,
// INTERNET_OPTION.INTERNET_OPTION_SETTINGS_CHANGED,
// IntPtr.Zero, 0);
// if ( ! bReturn )
// {
// Logging.Error("InternetSetOption:INTERNET_OPTION_SETTINGS_CHANGED");
// }
bReturn = NativeMethods.InternetSetOption(
IntPtr.Zero,
INTERNET_OPTION.INTERNET_OPTION_SETTINGS_CHANGED,
INTERNET_OPTION.INTERNET_OPTION_PROXY_SETTINGS_CHANGED,
IntPtr.Zero, 0);
if (!bReturn)
{
Logging.Error("InternetSetOption:INTERNET_OPTION_PROXY_SETTINGS_CHANGED");
}
NativeMethods.InternetSetOption(
bReturn = NativeMethods.InternetSetOption(
IntPtr.Zero,
INTERNET_OPTION.INTERNET_OPTION_REFRESH,
IntPtr.Zero, 0);
if (!bReturn)
{
Logging.Error("InternetSetOption:INTERNET_OPTION_REFRESH");
}
}
public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL)
{
string[] allConnections = null;
var ret = RAS.GetAllConns(ref allConnections);
if (ret == 2)
throw new Exception("Cannot get all connections");
if (ret == 1)
{
// no entries, only set LAN
SetIEProxy(enable, global, proxyServer, pacURL, null);
}
else if (ret == 0)
{
// found entries, set LAN and each connection
SetIEProxy(enable, global, proxyServer, pacURL, null);
foreach (string connName in allConnections)
{
SetIEProxy(enable, global, proxyServer, pacURL, connName);
}
}
}
}
}

+ 1
- 0
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -190,6 +190,7 @@
<Compile Include="Util\SystemProxy\INTERNET_PER_CONN_OPTION.cs" />
<Compile Include="Util\SystemProxy\INTERNET_PER_CONN_OPTION_LIST.cs" />
<Compile Include="Util\SystemProxy\NativeMethods.cs" />
<Compile Include="Util\SystemProxy\RAS.cs" />
<Compile Include="Util\SystemProxy\WinINet.cs" />
<Compile Include="Util\Util.cs" />
<Compile Include="View\ConfigForm.cs">


Loading…
Cancel
Save