mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84b412bc8c | ||
|
|
7fef3dfe5c | ||
|
|
c139a82bdf | ||
|
|
97f6d601fb | ||
|
|
1ea0bb4096 | ||
|
|
7265bd2922 | ||
|
|
f316e13ada | ||
|
|
370794646d | ||
|
|
677ac07d9a | ||
|
|
cba6e6b668 | ||
|
|
64260b18cc | ||
|
|
74e1635e26 | ||
|
|
b6e4e5effa | ||
|
|
c1644ec52f | ||
|
|
e5a968f581 | ||
|
|
dc7c537eef | ||
|
|
1fc211acde | ||
|
|
0ce8bbf712 | ||
|
|
1003521d01 | ||
|
|
026eb75eb1 | ||
|
|
e42b98cf03 | ||
|
|
93eeaf8c75 | ||
|
|
e99772ad11 | ||
|
|
0714a7bc12 | ||
|
|
f3515974f8 | ||
|
|
50678fba42 | ||
|
|
29532e9353 | ||
|
|
66e219f8a6 | ||
|
|
8789b04953 | ||
|
|
3fd8100aa5 | ||
|
|
e03fe9fec9 | ||
|
|
eab0797fb2 | ||
|
|
046079639e | ||
|
|
a5147e147e | ||
|
|
f9503d61d3 | ||
|
|
389c385d18 | ||
|
|
3f6744205a | ||
|
|
5e168d9e50 | ||
|
|
ad660fb598 | ||
|
|
dfe5a4528b | ||
|
|
5225a98581 | ||
|
|
74aa072d9b | ||
|
|
dd5dee02c5 | ||
|
|
6d4e12a6f2 | ||
|
|
790abce3c8 | ||
|
|
e0ca3a5ee4 | ||
|
|
fde71e922f | ||
|
|
140912bd2f | ||
|
|
677be9ba53 | ||
|
|
146f2013ee | ||
|
|
7ad89e7803 | ||
|
|
e9246bb300 | ||
|
|
2e81e41ae3 | ||
|
|
c3e2314bcd | ||
|
|
bcbb7928c3 | ||
|
|
7ea525a8ea | ||
|
|
758a4ca57e | ||
|
|
f752c883ca | ||
|
|
ba646e43e3 | ||
|
|
210bafb33f | ||
|
|
67fb8f449b | ||
|
|
fa57761013 | ||
|
|
96dd2e7bf2 | ||
|
|
890ebeb592 | ||
|
|
eb88be81e2 | ||
|
|
cb18816e64 | ||
|
|
244f32e9f4 |
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@@ -23,3 +23,13 @@ updates:
|
||||
labels:
|
||||
- "Automatic"
|
||||
open-pull-requests-limit: 99
|
||||
- package-ecosystem: "gitsubmodule"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "07:15"
|
||||
timezone: "Asia/Shanghai"
|
||||
labels:
|
||||
- "Automatic"
|
||||
open-pull-requests-limit: 99
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/.vs
|
||||
/packages
|
||||
.idea/
|
||||
/*.user
|
||||
@@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SearchComboBox", "SearchComboBox\SearchComboBox.csproj", "{A8715AF4-ACC6-43F9-9381-4294C5360623}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{53397641-35CA-4336-8E22-2CE12EF476AC}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "UnitTest\UnitTest.csproj", "{53397641-35CA-4336-8E22-2CE12EF476AC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -14,34 +15,33 @@ namespace nfapinet
|
||||
|
||||
public enum NF_DIRECTION
|
||||
{
|
||||
NF_D_IN = 1, // Incoming TCP connection or UDP packet
|
||||
NF_D_OUT = 2, // Outgoing TCP connection or UDP packet
|
||||
NF_D_BOTH = 3 // Any direction
|
||||
NF_D_IN = 1, // Incoming TCP connection or UDP packet
|
||||
NF_D_OUT = 2, // Outgoing TCP connection or UDP packet
|
||||
NF_D_BOTH = 3 // Any direction
|
||||
};
|
||||
|
||||
public enum NF_FILTERING_FLAG
|
||||
{
|
||||
NF_ALLOW = 0, // Allow the activity without filtering transmitted packets
|
||||
NF_BLOCK = 1, // Block the activity
|
||||
NF_FILTER = 2, // Filter the transmitted packets
|
||||
NF_SUSPENDED = 4, // Suspend receives from server and sends from client
|
||||
NF_OFFLINE = 8, // Emulate establishing a TCP connection with remote server
|
||||
NF_INDICATE_CONNECT_REQUESTS = 16, // Indicate outgoing connect requests to API
|
||||
NF_ALLOW = 0, // Allow the activity without filtering transmitted packets
|
||||
NF_BLOCK = 1, // Block the activity
|
||||
NF_FILTER = 2, // Filter the transmitted packets
|
||||
NF_SUSPENDED = 4, // Suspend receives from server and sends from client
|
||||
NF_OFFLINE = 8, // Emulate establishing a TCP connection with remote server
|
||||
NF_INDICATE_CONNECT_REQUESTS = 16, // Indicate outgoing connect requests to API
|
||||
NF_DISABLE_REDIRECT_PROTECTION = 32, // Disable blocking indicating connect requests for outgoing connections of local proxies
|
||||
NF_PEND_CONNECT_REQUEST = 64, // Pend outgoing connect request to complete it later using nf_complete(TCP|UDP)ConnectRequest
|
||||
NF_FILTER_AS_IP_PACKETS = 128, // Indicate the traffic as IP packets via ipSend/ipReceive
|
||||
NF_READONLY = 256, // Don't block the IP packets and indicate them to ipSend/ipReceive only for monitoring
|
||||
NF_CONTROL_FLOW = 512, // Use the flow limit rules even without NF_FILTER flag
|
||||
NF_PEND_CONNECT_REQUEST = 64, // Pend outgoing connect request to complete it later using nf_complete(TCP|UDP)ConnectRequest
|
||||
NF_FILTER_AS_IP_PACKETS = 128, // Indicate the traffic as IP packets via ipSend/ipReceive
|
||||
NF_READONLY = 256, // Don't block the IP packets and indicate them to ipSend/ipReceive only for monitoring
|
||||
NF_CONTROL_FLOW = 512, // Use the flow limit rules even without NF_FILTER flag
|
||||
};
|
||||
|
||||
public enum NF_FLAGS
|
||||
{
|
||||
NFF_NONE = 0,
|
||||
NFF_DONT_DISABLE_TEREDO = 1, // Don't disable Teredo
|
||||
NFF_DONT_DISABLE_TEREDO = 1, // Don't disable Teredo
|
||||
NFF_DONT_DISABLE_TCP_OFFLOADING = 2 // Don't disable TCP offloading
|
||||
};
|
||||
|
||||
|
||||
public enum NF_CONSTS
|
||||
{
|
||||
NF_MAX_ADDRESS_LENGTH = 28,
|
||||
@@ -61,30 +61,30 @@ namespace nfapinet
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct NF_RULE
|
||||
{
|
||||
public int protocol; // IPPROTO_TCP or IPPROTO_UDP
|
||||
public UInt32 processId; // Process identifier
|
||||
public Byte direction; // See NF_DIRECTION
|
||||
public ushort localPort; // Local port
|
||||
public ushort remotePort; // Remote port
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
public int protocol; // IPPROTO_TCP or IPPROTO_UDP
|
||||
public UInt32 processId; // Process identifier
|
||||
public Byte direction; // See NF_DIRECTION
|
||||
public ushort localPort; // Local port
|
||||
public ushort remotePort; // Remote port
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
|
||||
// Local IP (or network if localIpAddressMask is not zero)
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] localIpAddress;
|
||||
|
||||
// Local IP mask
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] localIpAddressMask;
|
||||
|
||||
// Remote IP (or network if remoteIpAddressMask is not zero)
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] remoteIpAddress;
|
||||
|
||||
// Remote IP mask
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] remoteIpAddressMask;
|
||||
|
||||
public UInt32 filteringFlag; // See NF_FILTERING_FLAG
|
||||
public UInt32 filteringFlag; // See NF_FILTERING_FLAG
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -93,30 +93,30 @@ namespace nfapinet
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)]
|
||||
public struct NF_RULE_EX
|
||||
{
|
||||
public int protocol; // IPPROTO_TCP or IPPROTO_UDP
|
||||
public UInt32 processId; // Process identifier
|
||||
public Byte direction; // See NF_DIRECTION
|
||||
public ushort localPort; // Local port
|
||||
public ushort remotePort; // Remote port
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
public int protocol; // IPPROTO_TCP or IPPROTO_UDP
|
||||
public UInt32 processId; // Process identifier
|
||||
public Byte direction; // See NF_DIRECTION
|
||||
public ushort localPort; // Local port
|
||||
public ushort remotePort; // Remote port
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
|
||||
// Local IP (or network if localIpAddressMask is not zero)
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] localIpAddress;
|
||||
|
||||
// Local IP mask
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] localIpAddressMask;
|
||||
|
||||
// Remote IP (or network if remoteIpAddressMask is not zero)
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] remoteIpAddress;
|
||||
|
||||
// Remote IP mask
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] remoteIpAddressMask;
|
||||
|
||||
public UInt32 filteringFlag; // See NF_FILTERING_FLAG
|
||||
public UInt32 filteringFlag; // See NF_FILTERING_FLAG
|
||||
|
||||
// Tail part of the process path mask
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
|
||||
@@ -129,17 +129,17 @@ namespace nfapinet
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct NF_TCP_CONN_INFO
|
||||
{
|
||||
public UInt32 filteringFlag; // See NF_FILTERING_FLAG
|
||||
public UInt32 processId; // Process identifier
|
||||
public Byte direction; // See NF_DIRECTION
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
public UInt32 filteringFlag; // See NF_FILTERING_FLAG
|
||||
public UInt32 processId; // Process identifier
|
||||
public Byte direction; // See NF_DIRECTION
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
|
||||
// Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
public byte[] localAddress;
|
||||
|
||||
// Remote address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
public byte[] remoteAddress;
|
||||
};
|
||||
|
||||
@@ -149,11 +149,11 @@ namespace nfapinet
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct NF_UDP_CONN_INFO
|
||||
{
|
||||
public UInt32 processId; // Process identifier
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
public UInt32 processId; // Process identifier
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
|
||||
// Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
public byte[] localAddress;
|
||||
};
|
||||
|
||||
@@ -175,35 +175,35 @@ namespace nfapinet
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct NF_UDP_CONN_REQUEST
|
||||
{
|
||||
public UInt32 filteringFlag; // See NF_FILTERING_FLAG
|
||||
public UInt32 processId; // Process identifier
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
public UInt32 filteringFlag; // See NF_FILTERING_FLAG
|
||||
public UInt32 processId; // Process identifier
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
|
||||
// Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
public byte[] localAddress;
|
||||
|
||||
// Remote address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_ADDRESS_LENGTH)]
|
||||
public byte[] remoteAddress;
|
||||
};
|
||||
|
||||
public enum NF_IP_FLAG
|
||||
{
|
||||
NFIF_NONE = 0, // No flags
|
||||
NFIF_READONLY = 1, // The packet was not blocked and indicated only for monitoring in read-only mode
|
||||
// (see NF_READ_ONLY flags from NF_FILTERING_FLAG).
|
||||
NFIF_NONE = 0, // No flags
|
||||
NFIF_READONLY = 1, // The packet was not blocked and indicated only for monitoring in read-only mode
|
||||
// (see NF_READ_ONLY flags from NF_FILTERING_FLAG).
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct NF_IP_PACKET_OPTIONS
|
||||
{
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
public UInt32 ipHeaderSize; // Size in bytes of IP header
|
||||
public UInt32 compartmentId; // Network routing compartment identifier (can be zero)
|
||||
public UInt32 interfaceIndex; // Index of the interface on which the original packet data was received (irrelevant to outgoing packets)
|
||||
public UInt32 subInterfaceIndex; // Index of the subinterface on which the original packet data was received (irrelevant to outgoing packets)
|
||||
public UInt32 flags; // Can be a combination of flags from NF_IP_FLAG enumeration
|
||||
public ushort ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6
|
||||
public UInt32 ipHeaderSize; // Size in bytes of IP header
|
||||
public UInt32 compartmentId; // Network routing compartment identifier (can be zero)
|
||||
public UInt32 interfaceIndex; // Index of the interface on which the original packet data was received (irrelevant to outgoing packets)
|
||||
public UInt32 subInterfaceIndex; // Index of the subinterface on which the original packet data was received (irrelevant to outgoing packets)
|
||||
public UInt32 flags; // Can be a combination of flags from NF_IP_FLAG enumeration
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
@@ -257,15 +257,15 @@ namespace nfapinet
|
||||
public ushort ip_family;
|
||||
|
||||
// Local IP (or network if localIpAddressMask is not zero)
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] localIpAddress;
|
||||
|
||||
// Local IP mask
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] localIpAddressMask;
|
||||
|
||||
// Redirect bind request to this IP
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)]
|
||||
public byte[] newLocalIpAddress;
|
||||
|
||||
// Redirect bind request to this port, if it is not zero
|
||||
@@ -277,38 +277,55 @@ namespace nfapinet
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_threadStart();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_threadEnd();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_tcpConnectRequest(ulong id, ref NF_TCP_CONN_INFO pConnInfo);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_tcpConnected(ulong id, ref NF_TCP_CONN_INFO pConnInfo);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_tcpClosed(ulong id, ref NF_TCP_CONN_INFO pConnInfo);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_tcpReceive(ulong id, IntPtr buf, int len);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_tcpSend(ulong id, IntPtr buf, int len);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_tcpCanReceive(ulong id);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_tcpCanSend(ulong id);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_udpCreated(ulong id, ref NF_UDP_CONN_INFO pConnInfo);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_udpConnectRequest(ulong id, ref NF_UDP_CONN_REQUEST pConnReq);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_udpClosed(ulong id, ref NF_UDP_CONN_INFO pConnInfo);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_udpReceive(ulong id, IntPtr remoteAddress, IntPtr buf, int len, IntPtr options);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_udpSend(ulong id, IntPtr remoteAddress, IntPtr buf, int len, IntPtr options);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_udpCanReceive(ulong id);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_udpCanSend(ulong id);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_ipReceive(IntPtr buf, int len, ref NF_IP_PACKET_OPTIONS ipOptions);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void cbd_ipSend(IntPtr buf, int len, ref NF_IP_PACKET_OPTIONS ipOptions);
|
||||
|
||||
@@ -355,80 +372,95 @@ namespace nfapinet
|
||||
{
|
||||
m_pEventHandler.threadStart();
|
||||
}
|
||||
|
||||
public static void threadEnd()
|
||||
{
|
||||
m_pEventHandler.threadEnd();
|
||||
}
|
||||
|
||||
public static void tcpConnectRequest(ulong id, ref NF_TCP_CONN_INFO pConnInfo)
|
||||
{
|
||||
m_pEventHandler.tcpConnectRequest(id, ref pConnInfo);
|
||||
}
|
||||
|
||||
public static void tcpConnected(ulong id, ref NF_TCP_CONN_INFO pConnInfo)
|
||||
{
|
||||
m_pEventHandler.tcpConnected(id, pConnInfo);
|
||||
}
|
||||
|
||||
public static void tcpClosed(ulong id, ref NF_TCP_CONN_INFO pConnInfo)
|
||||
{
|
||||
m_pEventHandler.tcpClosed(id, pConnInfo);
|
||||
}
|
||||
|
||||
public static void tcpReceive(ulong id, IntPtr buf, int len)
|
||||
{
|
||||
m_pEventHandler.tcpReceive(id, buf, len);
|
||||
}
|
||||
|
||||
public static void tcpSend(ulong id, IntPtr buf, int len)
|
||||
{
|
||||
m_pEventHandler.tcpSend(id, buf, len);
|
||||
}
|
||||
|
||||
public static void tcpCanReceive(ulong id)
|
||||
{
|
||||
m_pEventHandler.tcpCanReceive(id);
|
||||
}
|
||||
|
||||
public static void tcpCanSend(ulong id)
|
||||
{
|
||||
m_pEventHandler.tcpCanSend(id);
|
||||
}
|
||||
|
||||
public static void udpCreated(ulong id, ref NF_UDP_CONN_INFO pConnInfo)
|
||||
{
|
||||
m_pEventHandler.udpCreated(id, pConnInfo);
|
||||
}
|
||||
|
||||
public static void udpConnectRequest(ulong id, ref NF_UDP_CONN_REQUEST pConnReq)
|
||||
{
|
||||
m_pEventHandler.udpConnectRequest(id, ref pConnReq);
|
||||
}
|
||||
|
||||
public static void udpClosed(ulong id, ref NF_UDP_CONN_INFO pConnInfo)
|
||||
{
|
||||
m_pEventHandler.udpClosed(id, pConnInfo);
|
||||
}
|
||||
|
||||
public static void udpReceive(ulong id, IntPtr remoteAddress, IntPtr buf, int len, IntPtr options)
|
||||
{
|
||||
if (options.ToInt64() != 0)
|
||||
{
|
||||
NF_UDP_OPTIONS optionsCopy = (NF_UDP_OPTIONS)Marshal.PtrToStructure((IntPtr)options, typeof(NF_UDP_OPTIONS));
|
||||
NF_UDP_OPTIONS optionsCopy = (NF_UDP_OPTIONS) Marshal.PtrToStructure((IntPtr) options, typeof(NF_UDP_OPTIONS));
|
||||
int optionsLen = 8 + optionsCopy.optionsLength;
|
||||
m_pEventHandler.udpReceive(id, remoteAddress, buf, len, options, optionsLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pEventHandler.udpReceive(id, remoteAddress, buf, len, (IntPtr)null, 0);
|
||||
m_pEventHandler.udpReceive(id, remoteAddress, buf, len, (IntPtr) null, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void udpSend(ulong id, IntPtr remoteAddress, IntPtr buf, int len, IntPtr options)
|
||||
{
|
||||
if (options.ToInt64() != 0)
|
||||
{
|
||||
NF_UDP_OPTIONS optionsCopy = (NF_UDP_OPTIONS)Marshal.PtrToStructure((IntPtr)options, typeof(NF_UDP_OPTIONS));
|
||||
NF_UDP_OPTIONS optionsCopy = (NF_UDP_OPTIONS) Marshal.PtrToStructure((IntPtr) options, typeof(NF_UDP_OPTIONS));
|
||||
int optionsLen = 8 + optionsCopy.optionsLength;
|
||||
m_pEventHandler.udpSend(id, remoteAddress, buf, len, options, optionsLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pEventHandler.udpSend(id, remoteAddress, buf, len, (IntPtr)null, 0);
|
||||
m_pEventHandler.udpSend(id, remoteAddress, buf, len, (IntPtr) null, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void udpCanReceive(ulong id)
|
||||
{
|
||||
m_pEventHandler.udpCanReceive(id);
|
||||
}
|
||||
|
||||
public static void udpCanSend(ulong id)
|
||||
{
|
||||
m_pEventHandler.udpCanSend(id);
|
||||
@@ -446,6 +478,7 @@ namespace nfapinet
|
||||
{
|
||||
m_pEventHandler.ipReceive(buf, len, ref ipOptions);
|
||||
}
|
||||
|
||||
public static void ipSend(IntPtr buf, int len, ref NF_IP_PACKET_OPTIONS ipOptions)
|
||||
{
|
||||
m_pEventHandler.ipSend(buf, len, ref ipOptions);
|
||||
@@ -489,9 +522,9 @@ namespace nfapinet
|
||||
// Managed wrapper over API
|
||||
public class NFAPI
|
||||
{
|
||||
private static IntPtr m_pEventHandlerRaw = (IntPtr)null;
|
||||
private static IntPtr m_pEventHandlerRaw = (IntPtr) null;
|
||||
private static NF_EventHandlerInternal m_pEventHandler;
|
||||
private static IntPtr m_pIPEventHandlerRaw = (IntPtr)null;
|
||||
private static IntPtr m_pIPEventHandlerRaw = (IntPtr) null;
|
||||
private static NF_IPEventHandlerInternal m_pIPEventHandler;
|
||||
|
||||
/**
|
||||
@@ -554,7 +587,6 @@ namespace nfapinet
|
||||
[DllImport("bin\\nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS nf_unRegisterDriver(String driverName);
|
||||
|
||||
|
||||
//
|
||||
// TCP control routines
|
||||
//
|
||||
@@ -612,10 +644,7 @@ namespace nfapinet
|
||||
* @param len Buffer length
|
||||
**/
|
||||
[DllImport("bin\\nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS nf_udpPostSend(ulong id,
|
||||
IntPtr remoteAddress,
|
||||
IntPtr buf, int len,
|
||||
IntPtr options);
|
||||
public static extern NF_STATUS nf_udpPostSend(ulong id, IntPtr remoteAddress, IntPtr buf, int len, IntPtr options);
|
||||
|
||||
/**
|
||||
* Indicates the buffer to local process via specified socket.
|
||||
@@ -625,10 +654,7 @@ namespace nfapinet
|
||||
* @param len Buffer length
|
||||
**/
|
||||
[DllImport("bin\\nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS nf_udpPostReceive(ulong id,
|
||||
IntPtr remoteAddress,
|
||||
IntPtr buf, int len,
|
||||
IntPtr options);
|
||||
public static extern NF_STATUS nf_udpPostReceive(ulong id, IntPtr remoteAddress, IntPtr buf, int len, IntPtr options);
|
||||
|
||||
/**
|
||||
* Indicates a packet to TCP/IP stack
|
||||
@@ -637,9 +663,7 @@ namespace nfapinet
|
||||
* @param options IP options
|
||||
**/
|
||||
[DllImport("bin\\nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS nf_ipPostReceive(
|
||||
IntPtr buf, int len,
|
||||
ref NF_IP_PACKET_OPTIONS options);
|
||||
public static extern NF_STATUS nf_ipPostReceive(IntPtr buf, int len, ref NF_IP_PACKET_OPTIONS options);
|
||||
|
||||
/**
|
||||
* Sends a packet to remote IP
|
||||
@@ -648,9 +672,7 @@ namespace nfapinet
|
||||
* @param options IP options
|
||||
**/
|
||||
[DllImport("bin\\nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS nf_ipPostSend(
|
||||
IntPtr buf, int len,
|
||||
ref NF_IP_PACKET_OPTIONS options);
|
||||
public static extern NF_STATUS nf_ipPostSend(IntPtr buf, int len, ref NF_IP_PACKET_OPTIONS options);
|
||||
|
||||
//
|
||||
// Filtering rules
|
||||
@@ -668,13 +690,13 @@ namespace nfapinet
|
||||
{
|
||||
if (buf == null)
|
||||
{
|
||||
buf = new byte[(int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH];
|
||||
buf = new byte[(int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buf.Length < (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)
|
||||
if (buf.Length < (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH)
|
||||
{
|
||||
Array.Resize(ref buf, (int)NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH);
|
||||
Array.Resize(ref buf, (int) NF_CONSTS.NF_MAX_IP_ADDRESS_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -853,9 +875,9 @@ namespace nfapinet
|
||||
|
||||
fixed (char* p = buf)
|
||||
{
|
||||
if (nf_getProcessNameFromKernel(processId, (IntPtr)p, buf.Length))
|
||||
if (nf_getProcessNameFromKernel(processId, (IntPtr) p, buf.Length))
|
||||
{
|
||||
return Marshal.PtrToStringUni((IntPtr)p);
|
||||
return Marshal.PtrToStringUni((IntPtr) p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -871,9 +893,9 @@ namespace nfapinet
|
||||
|
||||
fixed (char* p = buf)
|
||||
{
|
||||
if (nf_getProcessNameW(processId, (IntPtr)p, buf.Length))
|
||||
if (nf_getProcessNameW(processId, (IntPtr) p, buf.Length))
|
||||
{
|
||||
return Marshal.PtrToStringUni((IntPtr)p);
|
||||
return Marshal.PtrToStringUni((IntPtr) p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -983,11 +1005,9 @@ namespace nfapinet
|
||||
* Add binding rule to driver
|
||||
*/
|
||||
[DllImport("bin\\nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern NF_STATUS
|
||||
nf_addBindingRule(ref NF_BINDING_RULE pRule, int toHead);
|
||||
private static extern NF_STATUS nf_addBindingRule(ref NF_BINDING_RULE pRule, int toHead);
|
||||
|
||||
public static NF_STATUS
|
||||
nf_addBindingRule(NF_BINDING_RULE pRule, int toHead)
|
||||
public static NF_STATUS nf_addBindingRule(NF_BINDING_RULE pRule, int toHead)
|
||||
{
|
||||
updateAddressLength(ref pRule.localIpAddress);
|
||||
updateAddressLength(ref pRule.localIpAddressMask);
|
||||
@@ -1000,15 +1020,12 @@ namespace nfapinet
|
||||
* Delete all binding rules from driver
|
||||
*/
|
||||
[DllImport("bin\\nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS
|
||||
nf_deleteBindingRules();
|
||||
public static extern NF_STATUS nf_deleteBindingRules();
|
||||
|
||||
/**
|
||||
* Returns the type of attached driver (DT_WFP, DT_TDI or DT_UNKNOWN)
|
||||
*/
|
||||
[DllImport("bin\\nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UInt32
|
||||
nf_getDriverType();
|
||||
public static extern UInt32 nf_getDriverType();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ namespace Netch.Controllers
|
||||
#region NativeMethods
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_dial(int name, byte[] value);
|
||||
public static extern bool aiodns_dial(int name, byte[]? value);
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_init();
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Timer = System.Timers.Timer;
|
||||
@@ -14,31 +15,34 @@ namespace Netch.Controllers
|
||||
{
|
||||
public abstract class Guard
|
||||
{
|
||||
private static readonly Timer SaveBufferTimer = new(300) {AutoReset = true};
|
||||
private readonly Timer _flushFileStreamTimer = new(300) {AutoReset = true};
|
||||
|
||||
private readonly StringBuilder _logBuffer = new();
|
||||
private FileStream? _logFileStream;
|
||||
|
||||
private StreamWriter? _logStreamWriter;
|
||||
private bool _redirectToFile = true;
|
||||
|
||||
/// <summary>
|
||||
/// 日志文件(重定向输出文件)
|
||||
/// </summary>
|
||||
private string _logPath;
|
||||
protected string LogPath => Path.Combine(Global.NetchDir, $"logging\\{Name}.log");
|
||||
|
||||
/// <summary>
|
||||
/// 成功启动关键词
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<string> StartedKeywords { get; } = null;
|
||||
protected virtual IEnumerable<string> StartedKeywords { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 启动失败关键词
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<string> StoppedKeywords { get; } = null;
|
||||
protected virtual IEnumerable<string> StoppedKeywords { get; } = new List<string>();
|
||||
|
||||
public virtual string Name { get; }
|
||||
public abstract string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 主程序名
|
||||
/// </summary>
|
||||
public virtual string MainFile { get; protected set; }
|
||||
public abstract string MainFile { get; protected set; }
|
||||
|
||||
protected State State { get; set; } = State.Waiting;
|
||||
|
||||
@@ -47,16 +51,21 @@ namespace Netch.Controllers
|
||||
/// </summary>
|
||||
protected bool RedirectStd { get; set; } = true;
|
||||
|
||||
protected bool RedirectToFile
|
||||
{
|
||||
get => RedirectStd && _redirectToFile;
|
||||
set => _redirectToFile = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance { get; private set; }
|
||||
public Process? Instance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序输出的编码,
|
||||
/// 调用于基类的 <see cref="OnOutputDataReceived" />
|
||||
/// </summary>
|
||||
protected Encoding InstanceOutputEncoding { get; set; } = Encoding.GetEncoding("gbk");
|
||||
protected virtual Encoding? InstanceOutputEncoding { get; } = null;
|
||||
|
||||
public abstract void Stop();
|
||||
|
||||
@@ -105,6 +114,9 @@ namespace Netch.Controllers
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
}
|
||||
};
|
||||
|
||||
if (!File.Exists(Instance.StartInfo.FileName))
|
||||
throw new MessageException(i18N.Translate($"bin\\{MainFile} file not found!"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -118,36 +130,28 @@ namespace Netch.Controllers
|
||||
State = State.Starting;
|
||||
// 初始化程序
|
||||
InitInstance(argument);
|
||||
Instance.EnableRaisingEvents = true;
|
||||
if (RedirectStd)
|
||||
{
|
||||
// 清理日志
|
||||
_logPath ??= Path.Combine(Global.NetchDir, $"logging\\{Name}.log");
|
||||
if (File.Exists(_logPath))
|
||||
File.Delete(_logPath);
|
||||
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
}
|
||||
|
||||
Instance.Exited += OnExited;
|
||||
if (RedirectToFile)
|
||||
OpenLogFile();
|
||||
|
||||
// 启动程序
|
||||
Instance.Start();
|
||||
Instance!.Start();
|
||||
if (priority != ProcessPriorityClass.Normal)
|
||||
Instance.PriorityClass = priority;
|
||||
|
||||
if (!RedirectStd)
|
||||
return;
|
||||
|
||||
// 启动日志重定向
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
SaveBufferTimer.Elapsed += SaveBufferTimerEvent;
|
||||
SaveBufferTimer.Enabled = true;
|
||||
if (!(StartedKeywords?.Any() ?? false))
|
||||
if (RedirectStd)
|
||||
{
|
||||
Task.Run(() => ReadOutput(Instance.StandardOutput));
|
||||
Task.Run(() => ReadOutput(Instance.StandardError));
|
||||
|
||||
if (!StartedKeywords.Any())
|
||||
{
|
||||
State = State.Started;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
State = State.Started;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -158,48 +162,97 @@ namespace Netch.Controllers
|
||||
switch (State)
|
||||
{
|
||||
case State.Started:
|
||||
Task.Run(OnKeywordStarted);
|
||||
return;
|
||||
case State.Stopped:
|
||||
Stop();
|
||||
Utils.Utils.Open(_logPath);
|
||||
throw new Exception($"{Name} 控制器启动失败");
|
||||
CloseLogFile();
|
||||
OnKeywordStopped();
|
||||
throw new MessageException($"{Name} 控制器启动失败");
|
||||
}
|
||||
}
|
||||
|
||||
Stop();
|
||||
throw new Exception($"{Name} 控制器启动超时");
|
||||
OnKeywordTimeout();
|
||||
throw new MessageException($"{Name} 控制器启动超时");
|
||||
}
|
||||
|
||||
private void OnExited(object sender, EventArgs e)
|
||||
#region FileStream
|
||||
|
||||
private void OpenLogFile()
|
||||
{
|
||||
if (RedirectStd)
|
||||
SaveBufferTimer.Enabled = false;
|
||||
|
||||
SaveBufferTimerEvent(null, null);
|
||||
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接收输出数据
|
||||
/// </summary>
|
||||
/// <param name="sender">发送者</param>
|
||||
/// <param name="e">数据</param>
|
||||
protected void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
// 程序结束, 接收到 null
|
||||
if (e.Data == null)
|
||||
if (!RedirectToFile)
|
||||
return;
|
||||
|
||||
Write(e.Data);
|
||||
// 检查启动
|
||||
if (State == State.Starting)
|
||||
_logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
|
||||
_logStreamWriter = new StreamWriter(_logFileStream);
|
||||
|
||||
_flushFileStreamTimer.Elapsed += FlushFileStreamTimerEvent;
|
||||
_flushFileStreamTimer.Enabled = true;
|
||||
}
|
||||
|
||||
private void WriteLog(string line)
|
||||
{
|
||||
if (!RedirectToFile)
|
||||
return;
|
||||
|
||||
_logStreamWriter!.WriteLine(line);
|
||||
}
|
||||
|
||||
private void CloseLogFile()
|
||||
{
|
||||
if (!RedirectToFile)
|
||||
return;
|
||||
|
||||
_flushFileStreamTimer.Enabled = false;
|
||||
_logStreamWriter?.Close();
|
||||
_logFileStream?.Close();
|
||||
_logStreamWriter = _logStreamWriter = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region virtual
|
||||
|
||||
protected virtual void OnReadNewLine(string line)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnKeywordStarted()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnKeywordStopped()
|
||||
{
|
||||
Utils.Utils.Open(LogPath);
|
||||
}
|
||||
|
||||
protected virtual void OnKeywordTimeout()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected void ReadOutput(TextReader reader)
|
||||
{
|
||||
string? line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (StartedKeywords.Any(s => e.Data.Contains(s)))
|
||||
State = State.Started;
|
||||
else if (StoppedKeywords.Any(s => e.Data.Contains(s)))
|
||||
State = State.Stopped;
|
||||
WriteLog(line);
|
||||
OnReadNewLine(line);
|
||||
|
||||
// State == State.Started if !StartedKeywords.Any()
|
||||
if (State == State.Starting)
|
||||
{
|
||||
if (StartedKeywords.Any(s => line.Contains(s)))
|
||||
State = State.Started;
|
||||
else if (StoppedKeywords.Any(s => line.Contains(s)))
|
||||
State = State.Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
CloseLogFile();
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -207,30 +260,16 @@ namespace Netch.Controllers
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void SaveBufferTimerEvent(object sender, EventArgs e)
|
||||
private void FlushFileStreamTimerEvent(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_logPath != null && _logBuffer != null)
|
||||
{
|
||||
File.AppendAllText(_logPath, _logBuffer.ToString());
|
||||
_logBuffer.Clear();
|
||||
}
|
||||
_logStreamWriter!.Flush();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logging.Warning($"写入 {Name} 日志错误:\n" + exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志文件缓冲
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <returns>转码后的字符串</returns>
|
||||
private void Write(string info)
|
||||
{
|
||||
_logBuffer.Append(info + Global.EOF);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using WindowsProxy;
|
||||
using Microsoft.Win32;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Servers.Trojan;
|
||||
@@ -12,10 +10,9 @@ namespace Netch.Controllers
|
||||
{
|
||||
public class HTTPController : IModeController
|
||||
{
|
||||
public PrivoxyController pPrivoxyController = new();
|
||||
public readonly PrivoxyController PrivoxyController = new();
|
||||
|
||||
private string prevBypass, prevHTTP, prevPAC;
|
||||
private bool prevEnabled;
|
||||
private ProxyStatus? _oldState;
|
||||
|
||||
public string Name { get; } = "HTTP";
|
||||
|
||||
@@ -26,25 +23,38 @@ namespace Netch.Controllers
|
||||
/// <returns>是否启动成功</returns>
|
||||
public void Start(in Mode mode)
|
||||
{
|
||||
RecordPrevious();
|
||||
PrivoxyController.Start(MainController.Server!);
|
||||
Global.Job.AddProcess(PrivoxyController.Instance!);
|
||||
string? pacUrl = null;
|
||||
|
||||
pPrivoxyController.Start(MainController.Server);
|
||||
Global.Job.AddProcess(pPrivoxyController.Instance);
|
||||
|
||||
if (mode.Type == 3)
|
||||
if (MainController.Server is Socks5 or Trojan && mode.BypassChina || (Global.Settings.AlwaysStartPACServer ?? false))
|
||||
{
|
||||
if (MainController.Server is Socks5 or Trojan && mode.BypassChina)
|
||||
try
|
||||
{
|
||||
//启动PAC服务器
|
||||
PACServerHandle.InitPACServer("127.0.0.1");
|
||||
PortHelper.CheckPort(Global.Settings.Pac_Port);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Global.Settings.Pac_Port = PortHelper.GetAvailablePort();
|
||||
}
|
||||
|
||||
pacUrl = PACServerHandle.InitPACServer("127.0.0.1");
|
||||
}
|
||||
|
||||
if (mode.Type is 3)
|
||||
{
|
||||
using var service = new ProxyService();
|
||||
_oldState = service.Query();
|
||||
|
||||
if (pacUrl != null)
|
||||
{
|
||||
service.AutoConfigUrl = pacUrl;
|
||||
service.Pac();
|
||||
}
|
||||
else
|
||||
{
|
||||
using var service = new ProxyService
|
||||
{
|
||||
Server = $"127.0.0.1:{Global.Settings.HTTPLocalPort}",
|
||||
Bypass = string.Join(";", ProxyService.LanIp)
|
||||
};
|
||||
service.Server = $"127.0.0.1:{Global.Settings.HTTPLocalPort}";
|
||||
service.Bypass = string.Join(";", ProxyService.LanIp);
|
||||
|
||||
service.Global();
|
||||
}
|
||||
@@ -58,70 +68,20 @@ namespace Netch.Controllers
|
||||
{
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Run(pPrivoxyController.Stop),
|
||||
Task.Run(PrivoxyController.Stop),
|
||||
Task.Run(() =>
|
||||
{
|
||||
using var service = new ProxyService();
|
||||
try
|
||||
{
|
||||
PACServerHandle.Stop();
|
||||
if (prevEnabled)
|
||||
{
|
||||
if (prevHTTP != "")
|
||||
{
|
||||
service.Server = prevHTTP;
|
||||
service.Bypass = prevBypass;
|
||||
service.Global();
|
||||
}
|
||||
PACServerHandle.Stop();
|
||||
|
||||
if (prevPAC != "")
|
||||
{
|
||||
service.AutoConfigUrl = prevPAC;
|
||||
service.Pac();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
service.Direct();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
if (_oldState != null)
|
||||
{
|
||||
Logging.Error($"{Name} 控制器出错:\n" + e);
|
||||
using var service = new ProxyService();
|
||||
service.Set(_oldState!);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
private void RecordPrevious()
|
||||
{
|
||||
try
|
||||
{
|
||||
var registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
|
||||
if (registry == null)
|
||||
throw new Exception();
|
||||
|
||||
prevPAC = registry.GetValue("AutoConfigURL")?.ToString() ?? "";
|
||||
prevHTTP = registry.GetValue("ProxyServer")?.ToString() ?? "";
|
||||
prevBypass = registry.GetValue("ProxyOverride")?.ToString() ?? "";
|
||||
prevEnabled = registry.GetValue("ProxyEnable")?.Equals(1) ?? false; // HTTP Proxy Enabled
|
||||
|
||||
if (prevHTTP == $"127.0.0.1:{Global.Settings.HTTPLocalPort}")
|
||||
{
|
||||
prevEnabled = false;
|
||||
prevHTTP = "";
|
||||
}
|
||||
|
||||
if (prevPAC != "")
|
||||
prevEnabled = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
prevEnabled = false;
|
||||
prevPAC = prevHTTP = prevBypass = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
@@ -12,36 +11,36 @@ namespace Netch.Controllers
|
||||
{
|
||||
public static class MainController
|
||||
{
|
||||
public static Mode Mode;
|
||||
public static Mode? Mode;
|
||||
|
||||
/// TCP or Both Server
|
||||
public static Server Server;
|
||||
public static Server? Server;
|
||||
|
||||
private static Server _udpServer;
|
||||
private static Server? _udpServer;
|
||||
|
||||
public static readonly NTTController NTTController = new();
|
||||
private static IServerController _serverController;
|
||||
private static IServerController _udpServerController;
|
||||
private static IServerController? _serverController;
|
||||
private static IServerController? _udpServerController;
|
||||
|
||||
public static IServerController ServerController
|
||||
public static IServerController? ServerController
|
||||
{
|
||||
get => _serverController;
|
||||
private set => _serverController = value;
|
||||
}
|
||||
|
||||
public static IServerController UdpServerController
|
||||
public static IServerController? UdpServerController
|
||||
{
|
||||
get => _udpServerController ?? _serverController;
|
||||
set => _udpServerController = value;
|
||||
}
|
||||
|
||||
public static Server UdpServer
|
||||
public static Server? UdpServer
|
||||
{
|
||||
get => _udpServer ?? Server;
|
||||
set => _udpServer = value;
|
||||
}
|
||||
|
||||
public static IModeController ModeController { get; private set; }
|
||||
public static IModeController? ModeController { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
@@ -62,20 +61,11 @@ namespace Netch.Controllers
|
||||
// 刷新DNS缓存
|
||||
NativeMethods.FlushDNSResolverCache();
|
||||
|
||||
try
|
||||
{
|
||||
WebUtil.BestLocalEndPoint(new IPEndPoint(0x72727272, 53));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new MessageException(i18N.Translate("No internet connection"));
|
||||
}
|
||||
|
||||
if (Global.Settings.ResolveServerHostname && DNS.Lookup(server.Hostname) == null)
|
||||
if (DnsUtils.Lookup(server.Hostname) == null)
|
||||
throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
|
||||
|
||||
// 添加Netch到防火墙
|
||||
_ = Task.Run(Firewall.AddNetchFwRules);
|
||||
Firewall.AddNetchFwRules();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -130,7 +120,7 @@ namespace Netch.Controllers
|
||||
Task.Run(() =>
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
Global.Job.AddProcess(guard.Instance);
|
||||
Global.Job.AddProcess(guard.Instance!);
|
||||
});
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
@@ -149,7 +139,7 @@ namespace Netch.Controllers
|
||||
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName, out var portType);
|
||||
|
||||
if (ModeController == null)
|
||||
throw new MessageException("未知模式类型");
|
||||
return;
|
||||
|
||||
if (port != null)
|
||||
PortCheck((ushort) port, portName, portType);
|
||||
@@ -158,7 +148,7 @@ namespace Netch.Controllers
|
||||
|
||||
ModeController.Start(mode);
|
||||
if (ModeController is Guard {Instance: { }} guard)
|
||||
Global.Job.AddProcess(guard.Instance);
|
||||
Global.Job.AddProcess(guard.Instance!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -166,6 +156,9 @@ namespace Netch.Controllers
|
||||
/// </summary>
|
||||
public static async Task Stop()
|
||||
{
|
||||
if (_serverController == null && ModeController == null)
|
||||
return;
|
||||
|
||||
StatusPortInfoText.Reset();
|
||||
|
||||
_ = Task.Run(() => NTTController.Stop());
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ServiceProcess;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
@@ -18,9 +17,11 @@ namespace Netch.Controllers
|
||||
{
|
||||
private static readonly ServiceController NFService = new("netfilter2");
|
||||
|
||||
private static readonly string BinDriver = string.Empty;
|
||||
private static readonly string BinDriver;
|
||||
private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
|
||||
private static string _sysDns;
|
||||
|
||||
private static string? _sysDns;
|
||||
private OutboundAdapter? _outbound;
|
||||
|
||||
static NFController()
|
||||
{
|
||||
@@ -39,8 +40,7 @@ namespace Netch.Controllers
|
||||
fileName = "Win-7.sys";
|
||||
break;
|
||||
default:
|
||||
Logging.Error($"不支持的系统版本:{Environment.OSVersion.Version}");
|
||||
return;
|
||||
throw new MessageException($"不支持的系统版本:{Environment.OSVersion.Version}");
|
||||
}
|
||||
|
||||
BinDriver = "bin\\" + fileName;
|
||||
@@ -57,32 +57,9 @@ namespace Netch.Controllers
|
||||
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
|
||||
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
|
||||
|
||||
if (Global.Settings.ProcessNoProxyForUdp && Global.Settings.ProcessNoProxyForTcp)
|
||||
MessageBoxX.Show("?");
|
||||
|
||||
//UDP
|
||||
if (Global.Settings.ProcessNoProxyForUdp)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_FILTERUDP, "false");
|
||||
SetServer(PortType.TCP);
|
||||
}
|
||||
else
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_FILTERUDP, "true");
|
||||
SetServer(PortType.Both);
|
||||
}
|
||||
|
||||
//TCP
|
||||
if (Global.Settings.ProcessNoProxyForTcp)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_FILTERTCP, "false");
|
||||
SetServer(PortType.UDP);
|
||||
}
|
||||
else
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_FILTERTCP, "true");
|
||||
SetServer(PortType.Both);
|
||||
}
|
||||
aio_dial((int) NameList.TYPE_FILTERUDP, (Global.Settings.ProcessProxyProtocol != PortType.TCP).ToString().ToLower());
|
||||
aio_dial((int) NameList.TYPE_FILTERTCP, (Global.Settings.ProcessProxyProtocol != PortType.UDP).ToString().ToLower());
|
||||
SetServer(Global.Settings.ProcessProxyProtocol);
|
||||
|
||||
if (!CheckRule(mode.FullRule, out var list))
|
||||
throw new MessageException($"\"{string.Join("", list.Select(s => s + "\n"))}\" does not conform to C++ regular expression syntax");
|
||||
@@ -93,12 +70,13 @@ namespace Netch.Controllers
|
||||
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
{
|
||||
_outbound = new OutboundAdapter();
|
||||
// 备份并替换系统 DNS
|
||||
_sysDns = DNS.OutboundDNS;
|
||||
_sysDns = _outbound.DNS;
|
||||
if (string.IsNullOrWhiteSpace(Global.Settings.ModifiedDNS))
|
||||
Global.Settings.ModifiedDNS = "1.1.1.1,8.8.8.8";
|
||||
|
||||
DNS.OutboundDNS = Global.Settings.ModifiedDNS;
|
||||
_outbound.DNS = Global.Settings.ModifiedDNS;
|
||||
}
|
||||
|
||||
if (!aio_init())
|
||||
@@ -111,7 +89,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
//恢复系统DNS
|
||||
DNS.OutboundDNS = _sysDns;
|
||||
_outbound!.DNS = _sysDns!;
|
||||
});
|
||||
|
||||
aio_free();
|
||||
@@ -204,14 +182,14 @@ namespace Netch.Controllers
|
||||
if (portType == PortType.UDP)
|
||||
{
|
||||
offset = UdpNameListOffset;
|
||||
server = MainController.UdpServer;
|
||||
controller = MainController.UdpServerController;
|
||||
server = MainController.UdpServer!;
|
||||
controller = MainController.UdpServerController!;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0;
|
||||
server = MainController.Server;
|
||||
controller = MainController.ServerController;
|
||||
server = MainController.Server!;
|
||||
controller = MainController.ServerController!;
|
||||
}
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
@@ -20,32 +21,38 @@ namespace Netch.Controllers
|
||||
/// 启动 NatTypeTester
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public (string, string, string) Start()
|
||||
public async Task<(string?, string?, string?)> Start()
|
||||
{
|
||||
string localEnd = null;
|
||||
string publicEnd = null;
|
||||
string result = null;
|
||||
string bindingTest = null;
|
||||
string? localEnd = null, publicEnd = null, result = null, bindingTest = null;
|
||||
|
||||
try
|
||||
{
|
||||
InitInstance($" {Global.Settings.STUN_Server} {Global.Settings.STUN_Server_Port}");
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
Instance.Start();
|
||||
var output = Instance.StandardOutput.ReadToEnd();
|
||||
Instance!.Start();
|
||||
|
||||
var output = await Instance.StandardOutput.ReadToEndAsync();
|
||||
var error = await Instance.StandardError.ReadToEndAsync();
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(Path.Combine(Global.NetchDir, $"logging\\{Name}.log"), output);
|
||||
File.WriteAllText(Path.Combine(Global.NetchDir, $"logging\\{Name}.log"), $"{output}\r\n{error}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Warning($"写入 {Name} 日志错误:\n" + e.Message);
|
||||
}
|
||||
|
||||
if (output.IsNullOrWhiteSpace())
|
||||
if (!error.IsNullOrWhiteSpace())
|
||||
{
|
||||
error = error.Trim();
|
||||
var errorFirst = error.Substring(0, error.IndexOf('\n')).Trim();
|
||||
return (errorFirst.SplitTrimEntries(':').Last(), null, null);
|
||||
}
|
||||
|
||||
foreach (var line in output.Split('\n'))
|
||||
{
|
||||
var str = line.Split(':').Select(s => s.Trim()).ToArray();
|
||||
var str = line.SplitTrimEntries(':');
|
||||
if (str.Length < 2)
|
||||
continue;
|
||||
|
||||
@@ -69,14 +76,11 @@ namespace Netch.Controllers
|
||||
case "result":
|
||||
result = value;
|
||||
break;
|
||||
default:
|
||||
result = str.Last();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bindingTest == "Fail")
|
||||
result = "UdpBlocked";
|
||||
result = "Fail";
|
||||
|
||||
return (result, localEnd, publicEnd);
|
||||
}
|
||||
|
||||
81
Netch/Controllers/PcapController.cs
Normal file
81
Netch/Controllers/PcapController.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class PcapController : Guard, IModeController
|
||||
{
|
||||
public override string Name { get; } = "pcap2socks";
|
||||
|
||||
public override string MainFile { get; protected set; } = "pcap2socks.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; } = new[] {"└"};
|
||||
|
||||
private readonly OutboundAdapter _outbound = new();
|
||||
|
||||
protected override Encoding? InstanceOutputEncoding { get; } = Encoding.UTF8;
|
||||
|
||||
private LogForm? _form;
|
||||
|
||||
public void Start(in Mode mode)
|
||||
{
|
||||
var server = MainController.Server!;
|
||||
|
||||
_form = new LogForm(Global.MainForm);
|
||||
_form.CreateControl();
|
||||
|
||||
var argument = new StringBuilder($@"-i \Device\NPF_{_outbound.NetworkInterface.Id}");
|
||||
if (server is Socks5 socks5 && !socks5.Auth())
|
||||
argument.Append($" --destination {server.AutoResolveHostname()}:{server.Port}");
|
||||
else
|
||||
argument.Append($" --destination 127.0.0.1:{Global.Settings.Socks5LocalPort}");
|
||||
|
||||
argument.Append($" {mode.FullRule.FirstOrDefault() ?? "-P n"}");
|
||||
StartInstanceAuto(argument.ToString());
|
||||
}
|
||||
|
||||
protected override void OnReadNewLine(string line)
|
||||
{
|
||||
Global.MainForm.BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (!_form!.IsDisposed)
|
||||
_form!.richTextBox1.AppendText(line + "\n");
|
||||
}));
|
||||
}
|
||||
|
||||
protected override void OnKeywordStarted()
|
||||
{
|
||||
Global.MainForm.BeginInvoke(new Action(() => { _form!.Show(); }));
|
||||
}
|
||||
|
||||
protected override void OnKeywordStopped()
|
||||
{
|
||||
if (File.ReadAllText(LogPath).Length == 0)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
Utils.Utils.Open("https://github.com/zhxie/pcap2socks#dependencies");
|
||||
});
|
||||
|
||||
throw new MessageException("Pleases install pcap2socks's dependency");
|
||||
}
|
||||
|
||||
Utils.Utils.Open(LogPath);
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
_form!.Close();
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
@@ -21,7 +19,7 @@ namespace Netch.Controllers
|
||||
/// <summary>
|
||||
/// 服务器 IP 地址
|
||||
/// </summary>
|
||||
private IPAddress _serverAddresses;
|
||||
private IPAddress _serverAddresses = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 本地 DNS 服务控制器
|
||||
@@ -34,49 +32,39 @@ namespace Netch.Controllers
|
||||
|
||||
public override string MainFile { get; protected set; } = "tun2socks.exe";
|
||||
|
||||
protected override Encoding InstanceOutputEncoding { get; } = Encoding.UTF8;
|
||||
|
||||
public override string Name { get; } = "tun2socks";
|
||||
|
||||
private readonly OutboundAdapter _outbound = new();
|
||||
private TapAdapter _tap = null!;
|
||||
|
||||
public void Start(in Mode mode)
|
||||
{
|
||||
var server = MainController.Server;
|
||||
// 查询服务器 IP 地址
|
||||
_serverAddresses = DNS.Lookup(server.Hostname);
|
||||
var server = MainController.Server!;
|
||||
_serverAddresses = DnsUtils.Lookup(server.Hostname)!; // server address have been cached when MainController.Start
|
||||
|
||||
// 查找出口适配器
|
||||
Utils.Utils.SearchOutboundAdapter();
|
||||
if (TUNTAP.GetComponentID() == null)
|
||||
TUNTAP.AddTap();
|
||||
|
||||
// 查找并安装 TAP 适配器
|
||||
if (string.IsNullOrEmpty(TUNTAP.GetComponentID()))
|
||||
AddTap();
|
||||
_tap = new TapAdapter();
|
||||
|
||||
SearchTapAdapter();
|
||||
|
||||
SetupRouteTable(mode);
|
||||
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", Name));
|
||||
|
||||
string dns;
|
||||
List<string> dns;
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
{
|
||||
if (Global.Settings.TUNTAP.DNS.Any())
|
||||
{
|
||||
dns = DNS.Join(Global.Settings.TUNTAP.DNS);
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.Settings.TUNTAP.DNS.Add("1.1.1.1");
|
||||
dns = "1.1.1.1";
|
||||
}
|
||||
dns = Global.Settings.TUNTAP.DNS.Any() ? Global.Settings.TUNTAP.DNS : Global.Settings.TUNTAP.DNS = new List<string> {"1.1.1.1"};
|
||||
}
|
||||
else
|
||||
{
|
||||
MainController.PortCheck(53, "DNS");
|
||||
|
||||
DNSController.Start();
|
||||
|
||||
dns = "127.0.0.1";
|
||||
dns = new List<string> {"127.0.0.1"};
|
||||
}
|
||||
|
||||
SetupRouteTable(mode);
|
||||
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", Name));
|
||||
|
||||
var argument = new StringBuilder();
|
||||
if (server is Socks5 socks5 && !socks5.Auth())
|
||||
argument.Append($"-proxyServer {server.AutoResolveHostname()}:{server.Port} ");
|
||||
@@ -84,7 +72,7 @@ namespace Netch.Controllers
|
||||
argument.Append($"-proxyServer 127.0.0.1:{Global.Settings.Socks5LocalPort} ");
|
||||
|
||||
argument.Append(
|
||||
$"-tunAddr {Global.Settings.TUNTAP.Address} -tunMask {Global.Settings.TUNTAP.Netmask} -tunGw {Global.Settings.TUNTAP.Gateway} -tunDns {dns} -tunName \"{TUNTAP.GetName(Global.TUNTAP.ComponentID)}\" ");
|
||||
$"-tunAddr {Global.Settings.TUNTAP.Address} -tunMask {Global.Settings.TUNTAP.Netmask} -tunGw {Global.Settings.TUNTAP.Gateway} -tunDns {DnsUtils.Join(dns)} -tunName \"{TUNTAP.GetName(_tap.ComponentID)}\" ");
|
||||
|
||||
if (Global.Settings.TUNTAP.UseFakeDNS && Global.Flags.SupportFakeDns)
|
||||
argument.Append("-fakeDns ");
|
||||
@@ -121,48 +109,28 @@ namespace Netch.Controllers
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 1:
|
||||
// 代理规则
|
||||
// 代理规则 IP
|
||||
Logging.Info("代理 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
|
||||
|
||||
//处理 NAT 类型检测,由于协议的原因,无法仅通过域名确定需要代理的 IP,自己记录解析了返回的 IP,仅支持默认检测服务器
|
||||
if (Global.Settings.STUN_Server == "stun.stunprotocol.org")
|
||||
try
|
||||
{
|
||||
Logging.Info("代理 → STUN 服务器 IP");
|
||||
RouteAction(Action.Create,
|
||||
new[]
|
||||
{
|
||||
Dns.GetHostAddresses(Global.Settings.STUN_Server)[0],
|
||||
Dns.GetHostAddresses("stunresponse.coldthunder11.com")[0]
|
||||
}.Select(ip => $"{ip}/32"),
|
||||
RouteType.TUNTAP);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logging.Info("NAT 类型测试域名解析失败,将不会被添加到代理列表");
|
||||
}
|
||||
|
||||
if (Global.Settings.TUNTAP.ProxyDNS)
|
||||
{
|
||||
Logging.Info("代理 → 自定义 DNS");
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
RouteAction(Action.Create, Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"), RouteType.TUNTAP);
|
||||
else
|
||||
RouteAction(Action.Create,
|
||||
new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip => $"{ip}/32"),
|
||||
RouteType.TUNTAP);
|
||||
RouteAction(Action.Create, $"{Global.Settings.AioDNS.OtherDNS}/32", RouteType.TUNTAP);
|
||||
}
|
||||
|
||||
break;
|
||||
case 2:
|
||||
// 绕过规则
|
||||
// 绕过规则 IP
|
||||
|
||||
// 将 TUN/TAP 网卡权重放到最高
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "netsh",
|
||||
Arguments = $"interface ip set interface {Global.TUNTAP.Index} metric=0",
|
||||
Arguments = $"interface ip set interface {_tap.Index} metric=0",
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true
|
||||
@@ -184,7 +152,6 @@ namespace Netch.Controllers
|
||||
|
||||
if (mode.Type == 2)
|
||||
{
|
||||
// 绕过规则
|
||||
Logging.Info("代理 → 全局");
|
||||
RouteAction(Action.Create, "0.0.0.0/0", RouteType.TUNTAP);
|
||||
}
|
||||
@@ -207,7 +174,7 @@ namespace Netch.Controllers
|
||||
try
|
||||
{
|
||||
InitInstance("-h");
|
||||
Instance.Start();
|
||||
Instance!.Start();
|
||||
return Instance.StandardError.ReadToEnd().Contains("-fakeDns");
|
||||
}
|
||||
catch
|
||||
@@ -216,45 +183,6 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索出口和TUNTAP适配器
|
||||
/// </summary>
|
||||
public static void SearchTapAdapter()
|
||||
{
|
||||
Global.TUNTAP.Adapter = null;
|
||||
Global.TUNTAP.Index = -1;
|
||||
Global.TUNTAP.ComponentID = TUNTAP.GetComponentID();
|
||||
|
||||
// 搜索 TUN/TAP 适配器的索引
|
||||
if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID))
|
||||
{
|
||||
const string s = "TAP 适配器未安装";
|
||||
Logging.Info(s);
|
||||
throw new Exception(s);
|
||||
}
|
||||
|
||||
// 根据 ComponentID 寻找 Tap适配器
|
||||
var adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ => _.Id == Global.TUNTAP.ComponentID);
|
||||
Global.TUNTAP.Adapter = adapter;
|
||||
Global.TUNTAP.Index = adapter.GetIPProperties().GetIPv4Properties().Index;
|
||||
Logging.Info($"TAP 适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {Global.TUNTAP.Index}");
|
||||
}
|
||||
|
||||
private static bool AddTap()
|
||||
{
|
||||
TUNTAP.addtap();
|
||||
// 给点时间,不然立马安装完毕就查找适配器可能会导致找不到适配器ID
|
||||
Thread.Sleep(1000);
|
||||
if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID = TUNTAP.GetComponentID()))
|
||||
{
|
||||
const string s = "TAP 驱动安装失败,找不到 ComponentID 注册表项";
|
||||
Logging.Error(s);
|
||||
throw new Exception(s);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType, int metric = 0)
|
||||
{
|
||||
foreach (var address in ipNetworks)
|
||||
@@ -263,54 +191,42 @@ namespace Netch.Controllers
|
||||
|
||||
private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0)
|
||||
{
|
||||
string gateway;
|
||||
int index;
|
||||
switch (routeType)
|
||||
{
|
||||
case RouteType.Outbound:
|
||||
gateway = Global.Outbound.Gateway.ToString();
|
||||
index = Global.Outbound.Index;
|
||||
break;
|
||||
case RouteType.TUNTAP:
|
||||
gateway = Global.Settings.TUNTAP.Gateway;
|
||||
index = Global.TUNTAP.Index;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null);
|
||||
}
|
||||
|
||||
string network;
|
||||
ushort cidr;
|
||||
try
|
||||
{
|
||||
var s = ipNetwork.Split('/');
|
||||
network = s[0];
|
||||
cidr = ushort.Parse(s[1]);
|
||||
}
|
||||
catch
|
||||
var s = ipNetwork.Split('/');
|
||||
if (s.Length != 2)
|
||||
{
|
||||
Logging.Warning($"Failed to parse rule {ipNetwork}");
|
||||
return false;
|
||||
}
|
||||
|
||||
IAdapter adapter;
|
||||
List<string> ipList;
|
||||
|
||||
switch (routeType)
|
||||
{
|
||||
case RouteType.TUNTAP:
|
||||
adapter = _tap;
|
||||
ipList = _proxyIPs;
|
||||
break;
|
||||
case RouteType.Outbound:
|
||||
adapter = _outbound;
|
||||
ipList = _directIPs;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null);
|
||||
}
|
||||
|
||||
string network = s[0];
|
||||
var cidr = ushort.Parse(s[1]);
|
||||
string gateway = adapter.Gateway.ToString();
|
||||
var index = adapter.Index;
|
||||
|
||||
bool result;
|
||||
switch (action)
|
||||
{
|
||||
case Action.Create:
|
||||
{
|
||||
result = NativeMethods.CreateRoute(network, cidr, gateway, index, metric);
|
||||
switch (routeType)
|
||||
{
|
||||
case RouteType.Outbound:
|
||||
_directIPs.Add(ipNetwork);
|
||||
break;
|
||||
case RouteType.TUNTAP:
|
||||
_proxyIPs.Add(ipNetwork);
|
||||
break;
|
||||
}
|
||||
|
||||
ipList.Add(ipNetwork);
|
||||
break;
|
||||
}
|
||||
case Action.Delete:
|
||||
result = NativeMethods.DeleteRoute(network, cidr, gateway, index, metric);
|
||||
break;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models.GitHubRelease;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using static Netch.Updater.Updater;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -19,22 +18,24 @@ namespace Netch.Controllers
|
||||
public const string Name = @"Netch";
|
||||
public const string Copyright = @"Copyright © 2019 - 2021";
|
||||
|
||||
public const string AssemblyVersion = @"1.7.6";
|
||||
public const string AssemblyVersion = @"1.8.1";
|
||||
private const string Suffix = @"";
|
||||
|
||||
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
|
||||
|
||||
public static string LatestVersionNumber;
|
||||
public static string LatestVersionUrl;
|
||||
public static Release LatestRelease;
|
||||
public static Release LatestRelease = null!;
|
||||
|
||||
public static event EventHandler NewVersionFound;
|
||||
public static string LatestVersionNumber => LatestRelease.tag_name;
|
||||
|
||||
public static event EventHandler NewVersionFoundFailed;
|
||||
public static string LatestVersionUrl => LatestRelease.html_url;
|
||||
|
||||
public static event EventHandler NewVersionNotFound;
|
||||
public static event EventHandler? NewVersionFound;
|
||||
|
||||
public static async void Check(bool isPreRelease)
|
||||
public static event EventHandler? NewVersionFoundFailed;
|
||||
|
||||
public static event EventHandler? NewVersionNotFound;
|
||||
|
||||
public static async Task Check(bool isPreRelease)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -43,10 +44,8 @@ namespace Netch.Controllers
|
||||
|
||||
var json = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
|
||||
|
||||
var releases = JsonConvert.DeserializeObject<List<Release>>(json);
|
||||
var releases = JsonSerializer.Deserialize<List<Release>>(json)!;
|
||||
LatestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
|
||||
LatestVersionNumber = LatestRelease.tag_name;
|
||||
LatestVersionUrl = LatestRelease.html_url;
|
||||
Logging.Info($"Github 最新发布版本: {LatestRelease.tag_name}");
|
||||
if (VersionUtil.CompareVersion(LatestRelease.tag_name, Version) > 0)
|
||||
{
|
||||
@@ -70,47 +69,31 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task DownloadUpdate(DownloadProgressChangedEventHandler onDownloadProgressChanged)
|
||||
public static bool GetFileNameAndHashFromMarkdownForm(in string text, out string fileName, out string sha256, string? keyword = null)
|
||||
{
|
||||
using WebClient client = new();
|
||||
|
||||
var latestVersionDownloadUrl = LatestRelease.assets[0].browser_download_url;
|
||||
var tagPage = await client.DownloadStringTaskAsync(LatestVersionUrl);
|
||||
var match = Regex.Match(tagPage, @"<td .*>(?<sha256>.*)</td>", RegexOptions.Singleline);
|
||||
|
||||
// TODO Replace with regex get basename and sha256
|
||||
var fileName = Path.GetFileName(new Uri(latestVersionDownloadUrl).LocalPath);
|
||||
fileName = fileName.Insert(fileName.LastIndexOf('.'), LatestVersionNumber);
|
||||
var fileFullPath = Path.Combine(Global.NetchDir, "data", fileName);
|
||||
|
||||
var sha256 = match.Groups["sha256"].Value;
|
||||
|
||||
if (File.Exists(fileFullPath))
|
||||
{
|
||||
if (Utils.Utils.SHA256CheckSum(fileFullPath) == sha256)
|
||||
{
|
||||
UpdateNetch(fileFullPath);
|
||||
return;
|
||||
}
|
||||
|
||||
File.Delete(fileFullPath);
|
||||
}
|
||||
|
||||
IEnumerable<Match> matches;
|
||||
try
|
||||
{
|
||||
client.DownloadProgressChanged += onDownloadProgressChanged;
|
||||
await client.DownloadFileTaskAsync(new Uri(latestVersionDownloadUrl), fileFullPath);
|
||||
client.DownloadProgressChanged -= onDownloadProgressChanged;
|
||||
matches = Regex.Matches(text, @"^\| (?<filename>.*) \| (?<sha256>.*) \|\r?$", RegexOptions.Multiline).Cast<Match>().Skip(2);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(i18N.Translate("Download Update Failed", ": ") + e.Message);
|
||||
Logging.Error(e.ToString());
|
||||
throw new Exception(i18N.Translate("Find update filename and hash failed"));
|
||||
}
|
||||
|
||||
if (Utils.Utils.SHA256CheckSum(fileFullPath) != sha256)
|
||||
throw new Exception(i18N.Translate("The downloaded file has the wrong hash"));
|
||||
Match match = keyword == null ? matches.First() : matches.First(m => m.Groups["filename"].Value.Contains(keyword));
|
||||
|
||||
UpdateNetch(fileFullPath);
|
||||
if (match != null)
|
||||
{
|
||||
fileName = match.Groups["filename"].Value;
|
||||
sha256 = match.Groups["sha256"].Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
fileName = string.Empty;
|
||||
sha256 = string.Empty;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
1
Netch/Forms/AboutForm.Designer.cs
generated
1
Netch/Forms/AboutForm.Designer.cs
generated
@@ -93,7 +93,6 @@
|
||||
this.Controls.Add(this.NetchPictureBox);
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "AboutForm";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
@@ -10,6 +11,7 @@ namespace Netch.Forms
|
||||
public AboutForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
Icon = Resources.icon;
|
||||
}
|
||||
|
||||
private void AboutForm_Load(object sender, EventArgs e)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1
Netch/Forms/GlobalBypassIPForm.Designer.cs
generated
1
Netch/Forms/GlobalBypassIPForm.Designer.cs
generated
@@ -119,7 +119,6 @@
|
||||
this.Controls.Add(this.IPGroupBox);
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "GlobalBypassIPForm";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
@@ -10,6 +11,7 @@ namespace Netch.Forms
|
||||
public GlobalBypassIPForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
Icon = Resources.icon;
|
||||
}
|
||||
|
||||
private void GlobalBypassIPForm_Load(object sender, EventArgs e)
|
||||
@@ -51,7 +53,7 @@ namespace Netch.Forms
|
||||
{
|
||||
Global.Settings.BypassIPs.Clear();
|
||||
foreach (var ip in IPListBox.Items)
|
||||
Global.Settings.BypassIPs.Add(ip as string);
|
||||
Global.Settings.BypassIPs.Add((string) ip);
|
||||
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
88
Netch/Forms/LogForm.Designer.cs
generated
Normal file
88
Netch/Forms/LogForm.Designer.cs
generated
Normal file
@@ -0,0 +1,88 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
partial class LogForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||
this.checkBox1 = new System.Windows.Forms.CheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// richTextBox1
|
||||
//
|
||||
this.richTextBox1.BackColor = System.Drawing.SystemColors.Control;
|
||||
this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.richTextBox1.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.ReadOnly = true;
|
||||
this.richTextBox1.Size = new System.Drawing.Size(454, 288);
|
||||
this.richTextBox1.TabIndex = 0;
|
||||
this.richTextBox1.Text = "";
|
||||
this.richTextBox1.TextChanged += new System.EventHandler(this.richTextBox1_TextChanged);
|
||||
//
|
||||
// checkBox1
|
||||
//
|
||||
this.checkBox1.AutoSize = true;
|
||||
this.checkBox1.Location = new System.Drawing.Point(12, 297);
|
||||
this.checkBox1.Name = "checkBox1";
|
||||
this.checkBox1.Size = new System.Drawing.Size(102, 16);
|
||||
this.checkBox1.TabIndex = 1;
|
||||
this.checkBox1.Text = "Scroll to End";
|
||||
this.checkBox1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// LogForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(454, 318);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.checkBox1);
|
||||
this.Controls.Add(this.richTextBox1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "LogForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.Text = "LogForm";
|
||||
this.Load += new System.EventHandler(this.Notifycation_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.CheckBox checkBox1;
|
||||
public System.Windows.Forms.RichTextBox richTextBox1;
|
||||
}
|
||||
}
|
||||
78
Netch/Forms/LogForm.cs
Normal file
78
Netch/Forms/LogForm.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using Vanara.PInvoke;
|
||||
using static Vanara.PInvoke.User32;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class LogForm : Form
|
||||
{
|
||||
private readonly Form _parent;
|
||||
|
||||
public LogForm(Form parent)
|
||||
{
|
||||
InitializeComponent();
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
Parent_Move(null!, null!);
|
||||
}
|
||||
|
||||
private void Parent_Move(object sender, EventArgs e)
|
||||
{
|
||||
var cl = Location;
|
||||
var fl = _parent.Location;
|
||||
|
||||
cl.X = fl.X + _parent.Width;
|
||||
cl.Y = fl.Y;
|
||||
Location = cl;
|
||||
}
|
||||
|
||||
private void Parent_Activated(object sender, EventArgs e)
|
||||
{
|
||||
SetWindowPos(Handle,
|
||||
HWND.HWND_TOPMOST,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_SHOWWINDOW);
|
||||
|
||||
SetWindowPos(Handle,
|
||||
HWND.HWND_NOTOPMOST,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_SHOWWINDOW);
|
||||
}
|
||||
|
||||
private void richTextBox1_TextChanged(object sender, System.EventArgs e)
|
||||
{
|
||||
if (!checkBox1.Checked)
|
||||
return;
|
||||
|
||||
richTextBox1.SelectionStart = richTextBox1.Text.Length;
|
||||
richTextBox1.ScrollToCaret();
|
||||
}
|
||||
|
||||
private void Notifycation_Load(object sender, EventArgs e)
|
||||
{
|
||||
_parent.LocationChanged += Parent_Move;
|
||||
_parent.SizeChanged += Parent_Move;
|
||||
_parent.Activated += Parent_Activated;
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
_parent.Activated -= Parent_Activated;
|
||||
_parent.LocationChanged -= Parent_Move;
|
||||
_parent.SizeChanged -= Parent_Move;
|
||||
base.OnClosing(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Netch/Forms/MainForm.Designer.cs
generated
38
Netch/Forms/MainForm.Designer.cs
generated
@@ -35,6 +35,7 @@
|
||||
this.ImportServersFromClipboardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CreateProcessModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CreateRouteTableRuleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ReloadModesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SubscribeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ManageSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -48,6 +49,7 @@
|
||||
this.updatePACToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UninstallTapDriverToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeNetchFirewallRulesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.HelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CheckForUpdatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.fAQToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -89,7 +91,6 @@
|
||||
this.ProfileTable = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.ButtomControlContainerControl = new System.Windows.Forms.ContainerControl();
|
||||
this.removeNetchFirewallRulesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MenuStrip.SuspendLayout();
|
||||
this.ConfigurationGroupBox.SuspendLayout();
|
||||
this.configLayoutPanel.SuspendLayout();
|
||||
@@ -142,10 +143,7 @@
|
||||
//
|
||||
// ModeToolStripMenuItem
|
||||
//
|
||||
this.ModeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[]
|
||||
{
|
||||
this.CreateProcessModeToolStripMenuItem, this.ReloadModesToolStripMenuItem
|
||||
});
|
||||
this.ModeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {this.CreateProcessModeToolStripMenuItem, this.CreateRouteTableRuleToolStripMenuItem, this.ReloadModesToolStripMenuItem});
|
||||
this.ModeToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.ModeToolStripMenuItem.Name = "ModeToolStripMenuItem";
|
||||
this.ModeToolStripMenuItem.Size = new System.Drawing.Size(55, 21);
|
||||
@@ -154,14 +152,21 @@
|
||||
// CreateProcessModeToolStripMenuItem
|
||||
//
|
||||
this.CreateProcessModeToolStripMenuItem.Name = "CreateProcessModeToolStripMenuItem";
|
||||
this.CreateProcessModeToolStripMenuItem.Size = new System.Drawing.Size(202, 22);
|
||||
this.CreateProcessModeToolStripMenuItem.Size = new System.Drawing.Size(217, 22);
|
||||
this.CreateProcessModeToolStripMenuItem.Text = "Create Process Mode";
|
||||
this.CreateProcessModeToolStripMenuItem.Click += new System.EventHandler(this.CreateProcessModeToolStripButton_Click);
|
||||
//
|
||||
// CreateRouteTableRuleToolStripMenuItem
|
||||
//
|
||||
this.CreateRouteTableRuleToolStripMenuItem.Name = "CreateRouteTableRuleToolStripMenuItem";
|
||||
this.CreateRouteTableRuleToolStripMenuItem.Size = new System.Drawing.Size(217, 22);
|
||||
this.CreateRouteTableRuleToolStripMenuItem.Text = "Create Route Table Rule";
|
||||
this.CreateRouteTableRuleToolStripMenuItem.Click += new System.EventHandler(this.createRouteTableModeToolStripMenuItem_Click);
|
||||
//
|
||||
// ReloadModesToolStripMenuItem
|
||||
//
|
||||
this.ReloadModesToolStripMenuItem.Name = "ReloadModesToolStripMenuItem";
|
||||
this.ReloadModesToolStripMenuItem.Size = new System.Drawing.Size(202, 22);
|
||||
this.ReloadModesToolStripMenuItem.Size = new System.Drawing.Size(217, 22);
|
||||
this.ReloadModesToolStripMenuItem.Text = "Reload Modes";
|
||||
this.ReloadModesToolStripMenuItem.Click += new System.EventHandler(this.ReloadModesToolStripMenuItem_Click);
|
||||
//
|
||||
@@ -257,6 +262,13 @@
|
||||
this.UninstallTapDriverToolStripMenuItem.Text = "Uninstall TUN/TAP driver";
|
||||
this.UninstallTapDriverToolStripMenuItem.Click += new System.EventHandler(this.UninstallTapDriverToolStripMenuItem_Click);
|
||||
//
|
||||
// removeNetchFirewallRulesToolStripMenuItem
|
||||
//
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Name = "removeNetchFirewallRulesToolStripMenuItem";
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Text = "Remove Netch Firewall Rules";
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Click += new System.EventHandler(this.RemoveNetchFirewallRulesToolStripMenuItem_Click);
|
||||
//
|
||||
// HelpToolStripMenuItem
|
||||
//
|
||||
this.HelpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[]
|
||||
@@ -616,7 +628,6 @@
|
||||
// NotifyIcon
|
||||
//
|
||||
this.NotifyIcon.ContextMenuStrip = this.NotifyMenu;
|
||||
this.NotifyIcon.Icon = ((System.Drawing.Icon) (resources.GetObject("NotifyIcon.Icon")));
|
||||
this.NotifyIcon.Text = "Netch";
|
||||
this.NotifyIcon.Visible = true;
|
||||
this.NotifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.NotifyIcon_MouseDoubleClick);
|
||||
@@ -707,13 +718,6 @@
|
||||
this.ButtomControlContainerControl.TabStop = false;
|
||||
this.ButtomControlContainerControl.Text = "groupBox1";
|
||||
//
|
||||
// removeNetchFirewallRulesToolStripMenuItem
|
||||
//
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Name = "removeNetchFirewallRulesToolStripMenuItem";
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Text = "Remove Netch Firewall Rules";
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Click += new System.EventHandler(this.RemoveNetchFirewallRulesToolStripMenuItem_Click);
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
@@ -726,7 +730,6 @@
|
||||
this.Controls.Add(this.flowLayoutPanel1);
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte) (134)));
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = ((System.Drawing.Icon) (resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "MainForm";
|
||||
@@ -758,6 +761,9 @@
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
private System.Windows.Forms.ToolStripMenuItem CreateRouteTableRuleToolStripMenuItem;
|
||||
|
||||
private System.Windows.Forms.ToolStripMenuItem removeNetchFirewallRulesToolStripMenuItem;
|
||||
|
||||
private System.Windows.Forms.ToolStripButton AboutToolStripButton;
|
||||
|
||||
@@ -12,12 +12,20 @@ using Microsoft.Win32;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms.Mode;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
private void createRouteTableModeToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Hide();
|
||||
new Route().ShowDialog();
|
||||
Show();
|
||||
}
|
||||
|
||||
#region Start
|
||||
|
||||
private readonly Dictionary<string, object> _mainFormText = new();
|
||||
@@ -28,6 +36,7 @@ namespace Netch.Forms
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
NotifyIcon.Icon = Icon = Resources.icon;
|
||||
|
||||
AddAddServerToolStripMenuItems();
|
||||
|
||||
@@ -41,7 +50,7 @@ namespace Netch.Forms
|
||||
// 监听电源事件
|
||||
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
|
||||
|
||||
ModeComboBox.KeyUp += (sender, args) =>
|
||||
ModeComboBox.KeyUp += (_, args) =>
|
||||
{
|
||||
switch (args.KeyData)
|
||||
{
|
||||
@@ -140,8 +149,8 @@ namespace Netch.Forms
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case TextBoxBase _:
|
||||
case ListControl _:
|
||||
case TextBoxBase:
|
||||
case ListControl:
|
||||
break;
|
||||
case Control c:
|
||||
_mainFormText.Add(c.Name, c.Text);
|
||||
@@ -170,8 +179,8 @@ namespace Netch.Forms
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case TextBoxBase _:
|
||||
case ListControl _:
|
||||
case TextBoxBase:
|
||||
case ListControl:
|
||||
break;
|
||||
case Control c:
|
||||
if (_mainFormText.ContainsKey(c.Name))
|
||||
@@ -192,7 +201,7 @@ namespace Netch.Forms
|
||||
return string.Empty;
|
||||
|
||||
if (value is object[] values)
|
||||
return i18N.TranslateFormat(values.First() as string, values.Skip(1).ToArray());
|
||||
return i18N.TranslateFormat((string) values.First(), values.Skip(1).ToArray());
|
||||
|
||||
return i18N.Translate(value);
|
||||
}
|
||||
@@ -307,10 +316,14 @@ namespace Netch.Forms
|
||||
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ProfileGroupBox.Enabled = ControlButton.Enabled = v;
|
||||
}
|
||||
|
||||
if (useProxy && ServerComboBox.SelectedIndex == -1)
|
||||
var server = ServerComboBox.SelectedItem as Server;
|
||||
if (useProxy)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
if (server == null)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.Settings.SubscribeLink.Count <= 0)
|
||||
@@ -323,7 +336,7 @@ namespace Netch.Forms
|
||||
DisableItems(false);
|
||||
try
|
||||
{
|
||||
string proxyServer = null;
|
||||
string? proxyServer = null;
|
||||
if (useProxy)
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
@@ -332,7 +345,7 @@ namespace Netch.Forms
|
||||
Type = 5
|
||||
};
|
||||
|
||||
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
|
||||
await MainController.Start(server!, mode);
|
||||
proxyServer = $"http://127.0.0.1:{Global.Settings.HTTPLocalPort}";
|
||||
}
|
||||
|
||||
@@ -401,7 +414,7 @@ namespace Netch.Forms
|
||||
await Task.Run(() =>
|
||||
{
|
||||
NativeMethods.FlushDNSResolverCache();
|
||||
DNS.Cache.Clear();
|
||||
DnsUtils.ClearCache();
|
||||
});
|
||||
|
||||
NotifyTip(i18N.Translate("DNS cache cleanup succeeded"));
|
||||
@@ -428,25 +441,27 @@ namespace Netch.Forms
|
||||
|
||||
private async void UpdateACL(bool useProxy)
|
||||
{
|
||||
if (useProxy && ServerComboBox.SelectedIndex == -1)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
Enabled = false;
|
||||
StatusText(i18N.TranslateFormat("Updating {0}", "ACL"));
|
||||
try
|
||||
{
|
||||
if (useProxy)
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
if (!(ServerComboBox.SelectedItem is Server server))
|
||||
{
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
{
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
|
||||
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
|
||||
await MainController.Start(server, mode);
|
||||
}
|
||||
}
|
||||
|
||||
var req = WebUtil.CreateRequest(Global.Settings.ACL);
|
||||
@@ -573,7 +588,7 @@ namespace Netch.Forms
|
||||
|
||||
#region ControlButton
|
||||
|
||||
private async void ControlButton_Click(object sender, EventArgs e)
|
||||
private async void ControlButton_Click(object? sender, EventArgs? e)
|
||||
{
|
||||
if (!IsWaiting())
|
||||
{
|
||||
@@ -714,14 +729,16 @@ namespace Netch.Forms
|
||||
private void EditServerPictureBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 当前ServerComboBox中至少有一项
|
||||
if (ServerComboBox.SelectedIndex == -1)
|
||||
if (!(ServerComboBox.SelectedItem is Server server))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server.Valid())
|
||||
return;
|
||||
|
||||
Hide();
|
||||
var server = Global.Settings.Server[ServerComboBox.SelectedIndex];
|
||||
ServerHelper.GetUtilByTypeName(server.Type).Edit(server);
|
||||
LoadServers();
|
||||
Configuration.Save();
|
||||
@@ -733,7 +750,14 @@ namespace Netch.Forms
|
||||
Enabled = false;
|
||||
StatusText(i18N.Translate("Testing"));
|
||||
|
||||
if (IsWaiting())
|
||||
if (!IsWaiting() || ModifierKeys == Keys.Control)
|
||||
{
|
||||
(ServerComboBox.SelectedItem as Server)?.Test();
|
||||
ServerComboBox.Refresh();
|
||||
Enabled = true;
|
||||
StatusText();
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerHelper.DelayTestHelper.TestDelayFinished += OnTestDelayFinished;
|
||||
_ = Task.Run(ServerHelper.DelayTestHelper.TestAllDelay);
|
||||
@@ -747,28 +771,23 @@ namespace Netch.Forms
|
||||
StatusText();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(ServerComboBox.SelectedItem as Server)?.Test();
|
||||
ServerComboBox.Refresh();
|
||||
Enabled = true;
|
||||
StatusText();
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyLinkPictureBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 当前ServerComboBox中至少有一项
|
||||
if (ServerComboBox.SelectedIndex == -1)
|
||||
if (!(ServerComboBox.SelectedItem is Server server))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server.Valid())
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
//听说巨硬BUG经常会炸,所以Catch一下 :D
|
||||
var server = (Server) ServerComboBox.SelectedItem;
|
||||
string text;
|
||||
if (ModifierKeys == Keys.Control)
|
||||
text = ShareLink.GetNetchLink(server);
|
||||
@@ -786,13 +805,13 @@ namespace Netch.Forms
|
||||
private void DeleteServerPictureBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 当前 ServerComboBox 中至少有一项
|
||||
if (ServerComboBox.SelectedIndex == -1)
|
||||
if (!(ServerComboBox.SelectedItem is Server server))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
Global.Settings.Server.Remove(ServerComboBox.SelectedItem as Server);
|
||||
Global.Settings.Server.Remove(server);
|
||||
LoadServers();
|
||||
}
|
||||
|
||||
@@ -851,7 +870,7 @@ namespace Netch.Forms
|
||||
var mode = (Models.Mode) ModeComboBox.SelectedItem;
|
||||
if (ModifierKeys == Keys.Control)
|
||||
{
|
||||
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath));
|
||||
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath!));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -862,8 +881,14 @@ namespace Netch.Forms
|
||||
new Process(mode).ShowDialog();
|
||||
Show();
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
Hide();
|
||||
new Route(mode).ShowDialog();
|
||||
Show();
|
||||
break;
|
||||
default:
|
||||
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath));
|
||||
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath!));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -974,7 +999,7 @@ namespace Netch.Forms
|
||||
var mode = (Models.Mode) ModeComboBox.SelectedItem;
|
||||
var name = ProfileNameText.Text;
|
||||
|
||||
Profile profile;
|
||||
Profile? profile;
|
||||
if ((profile = Global.Settings.Profiles.SingleOrDefault(p => p.Index == index)) != null)
|
||||
Global.Settings.Profiles.Remove(profile);
|
||||
|
||||
@@ -986,7 +1011,7 @@ namespace Netch.Forms
|
||||
private async void ProfileButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var profileButton = (Button) sender;
|
||||
var profile = (Profile) profileButton.Tag;
|
||||
var profile = (Profile?) profileButton.Tag;
|
||||
var index = ProfileTable.Controls.IndexOf(profileButton);
|
||||
|
||||
switch (ModifierKeys)
|
||||
@@ -1141,7 +1166,7 @@ namespace Netch.Forms
|
||||
/// 更新状态栏文本
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void StatusText(string text = null)
|
||||
public void StatusText(string? text = null)
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
@@ -1169,7 +1194,7 @@ namespace Netch.Forms
|
||||
UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = state;
|
||||
}
|
||||
|
||||
public void NatTypeStatusText(string text = "", string country = "")
|
||||
public void NatTypeStatusText(string? text = null, string? country = null)
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
@@ -1186,7 +1211,7 @@ namespace Netch.Forms
|
||||
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} {(country != string.Empty ? $"[{country}]" : "")}";
|
||||
NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} {(!country.IsNullOrEmpty() ? $"[{country}]" : "")}";
|
||||
|
||||
UpdateNatTypeLight(int.TryParse(text, out var natType) ? natType : -1);
|
||||
}
|
||||
@@ -1207,25 +1232,14 @@ namespace Netch.Forms
|
||||
if (natType > 0 && natType < 5)
|
||||
{
|
||||
NatTypeStatusLightLabel.Visible = Global.Flags.IsWindows10Upper;
|
||||
Color c;
|
||||
switch (natType)
|
||||
{
|
||||
case 1:
|
||||
c = Color.LimeGreen;
|
||||
break;
|
||||
case 2:
|
||||
c = Color.Yellow;
|
||||
break;
|
||||
case 3:
|
||||
c = Color.Red;
|
||||
break;
|
||||
case 4:
|
||||
c = Color.Black;
|
||||
break;
|
||||
default:
|
||||
c = Color.Black;
|
||||
break;
|
||||
}
|
||||
var c = natType switch
|
||||
{
|
||||
1 => Color.LimeGreen,
|
||||
2 => Color.Yellow,
|
||||
3 => Color.Red,
|
||||
4 => Color.Black,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(natType), natType, null)
|
||||
};
|
||||
|
||||
NatTypeStatusLightLabel.ForeColor = c;
|
||||
}
|
||||
@@ -1248,19 +1262,19 @@ namespace Netch.Forms
|
||||
/// </summary>
|
||||
public void NatTest()
|
||||
{
|
||||
if (!MainController.Mode.TestNatRequired())
|
||||
if (!MainController.Mode!.TestNatRequired())
|
||||
return;
|
||||
|
||||
NttTested = false;
|
||||
Task.Run(() =>
|
||||
{
|
||||
NatTypeStatusText(i18N.Translate("Starting NatTester"));
|
||||
// Thread.Sleep(1000);
|
||||
var (result, localEnd, publicEnd) = MainController.NTTController.Start();
|
||||
|
||||
var (result, localEnd, publicEnd) = MainController.NTTController.Start().Result;
|
||||
|
||||
if (!string.IsNullOrEmpty(publicEnd))
|
||||
{
|
||||
var country = Utils.Utils.GetCityCode(publicEnd);
|
||||
var country = Utils.Utils.GetCityCode(publicEnd!);
|
||||
NatTypeStatusText(result, country);
|
||||
}
|
||||
else
|
||||
@@ -1324,7 +1338,7 @@ namespace Netch.Forms
|
||||
Hide();
|
||||
}
|
||||
|
||||
public async void Exit(bool forceExit = false)
|
||||
public async void Exit(bool forceExit = false, bool saveConfiguration = true)
|
||||
{
|
||||
if (!IsWaiting() && !Global.Settings.StopWhenExited && !forceExit)
|
||||
{
|
||||
@@ -1337,7 +1351,11 @@ namespace Netch.Forms
|
||||
State = State.Terminating;
|
||||
NotifyIcon.Visible = false;
|
||||
Hide();
|
||||
Configuration.Save();
|
||||
|
||||
if (saveConfiguration)
|
||||
{
|
||||
Configuration.Save();
|
||||
}
|
||||
|
||||
foreach (var file in new[] {"data\\last.json", "data\\privoxy.conf"})
|
||||
if (File.Exists(file))
|
||||
@@ -1397,14 +1415,14 @@ namespace Netch.Forms
|
||||
NewVersionLabel.Visible = true;
|
||||
};
|
||||
|
||||
UpdateChecker.Check(Global.Settings.CheckBetaUpdate);
|
||||
UpdateChecker.Check(Global.Settings.CheckBetaUpdate).Wait();
|
||||
}
|
||||
|
||||
private async void NewVersionLabel_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!UpdateChecker.LatestRelease.assets.Any())
|
||||
if (ModifierKeys == Keys.Control || !UpdateChecker.LatestRelease!.assets.Any())
|
||||
{
|
||||
Utils.Utils.Open(UpdateChecker.LatestVersionUrl);
|
||||
Utils.Utils.Open(UpdateChecker.LatestVersionUrl!);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1422,7 +1440,7 @@ namespace Netch.Forms
|
||||
BeginInvoke(new Action(() => { NewVersionLabel.Text = $"{args.ProgressPercentage}%"; }));
|
||||
}
|
||||
|
||||
await UpdateChecker.DownloadUpdate(OnDownloadProgressChanged);
|
||||
await Updater.Updater.DownloadAndUpdate(Path.Combine(Global.NetchDir, "data"), Global.NetchDir, OnDownloadProgressChanged);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -1493,7 +1511,7 @@ namespace Netch.Forms
|
||||
Exit();
|
||||
}
|
||||
|
||||
private void NotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
|
||||
private void NotifyIcon_MouseDoubleClick(object? sender, MouseEventArgs? e)
|
||||
{
|
||||
if (WindowState == FormWindowState.Minimized)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ namespace Netch.Forms
|
||||
LogLevel level = LogLevel.INFO,
|
||||
string title = "",
|
||||
bool confirm = false,
|
||||
IWin32Window owner = null)
|
||||
IWin32Window? owner = null)
|
||||
{
|
||||
MessageBoxIcon msgIcon;
|
||||
if (string.IsNullOrWhiteSpace(title))
|
||||
|
||||
17
Netch/Forms/Mode/ModeEditorUtils.cs
Normal file
17
Netch/Forms/Mode/ModeEditorUtils.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
{
|
||||
public static class ModeEditorUtils
|
||||
{
|
||||
public static string ToSafeFileName(string text)
|
||||
{
|
||||
var fileName = new StringBuilder(text);
|
||||
foreach (var c in Path.GetInvalidFileNameChars())
|
||||
fileName.Replace(c, '_');
|
||||
|
||||
return fileName.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Netch/Forms/Mode/Process.Designer.cs
generated
3
Netch/Forms/Mode/Process.Designer.cs
generated
@@ -80,7 +80,6 @@ namespace Netch.Forms.Mode
|
||||
this.UseCustomFilenameBox.TabIndex = 9;
|
||||
this.UseCustomFilenameBox.Text = "Use Custom Filename";
|
||||
this.UseCustomFilenameBox.UseVisualStyleBackColor = true;
|
||||
this.UseCustomFilenameBox.CheckedChanged += new System.EventHandler(this.UseCustomFilenameBox_CheckedChanged);
|
||||
//
|
||||
// FilenameLabel
|
||||
//
|
||||
@@ -97,6 +96,7 @@ namespace Netch.Forms.Mode
|
||||
this.FilenameTextBox.Name = "FilenameTextBox";
|
||||
this.FilenameTextBox.Size = new System.Drawing.Size(250, 23);
|
||||
this.FilenameTextBox.TabIndex = 5;
|
||||
this.FilenameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.UseCustomFilenameBox, "Checked", true));;
|
||||
//
|
||||
// ScanButton
|
||||
//
|
||||
@@ -205,7 +205,6 @@ namespace Netch.Forms.Mode
|
||||
this.Controls.Add(this.ConfigurationGroupBox);
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte) (134)));
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = ((System.Drawing.Icon) (resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "Process";
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using Netch.Controllers;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
@@ -15,41 +15,33 @@ namespace Netch.Forms.Mode
|
||||
/// <summary>
|
||||
/// 被编辑的模式
|
||||
/// </summary>
|
||||
private readonly Models.Mode _mode;
|
||||
private readonly Models.Mode? _mode;
|
||||
|
||||
/// <summary>
|
||||
/// 编辑模式
|
||||
/// </summary>
|
||||
/// <param name="mode">模式</param>
|
||||
public Process(Models.Mode mode)
|
||||
public Process(Models.Mode? mode = null)
|
||||
{
|
||||
if (mode.Type != 0)
|
||||
throw new Exception("请传入进程模式");
|
||||
if (mode != null && mode.Type is not 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
InitializeComponent();
|
||||
Icon = Resources.icon;
|
||||
CheckForIllegalCrossThreadCalls = false;
|
||||
|
||||
Text = "Edit Process Mode";
|
||||
_mode = mode;
|
||||
RuleListBox.Items.AddRange(mode.Rule.ToArray());
|
||||
if (mode != null)
|
||||
{
|
||||
Text = "Edit Process Mode";
|
||||
|
||||
#region 禁用文件名更改
|
||||
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
|
||||
FilenameTextBox.Enabled = UseCustomFilenameBox.Enabled = false;
|
||||
|
||||
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
|
||||
FilenameTextBox.Enabled = UseCustomFilenameBox.Enabled = false;
|
||||
|
||||
#endregion
|
||||
|
||||
FilenameTextBox.Text = mode.RelativePath;
|
||||
RemarkTextBox.Text = mode.Remark;
|
||||
}
|
||||
|
||||
public Process()
|
||||
{
|
||||
InitializeComponent();
|
||||
CheckForIllegalCrossThreadCalls = false;
|
||||
|
||||
FilenameTextBox.Enabled = false;
|
||||
RemarkTextBox.Text = mode.Remark;
|
||||
FilenameTextBox.Text = mode.RelativePath;
|
||||
RuleListBox.Items.AddRange(mode.Rule.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -142,7 +134,7 @@ namespace Netch.Forms.Mode
|
||||
NavigateToShortcut = true
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog(Win32Native.GetForegroundWindow()) == CommonFileDialogResult.Ok)
|
||||
if (dialog.ShowDialog(Handle) == CommonFileDialogResult.Ok)
|
||||
{
|
||||
ScanDirectory(dialog.FileName);
|
||||
MessageBoxX.Show(i18N.Translate("Scan completed"));
|
||||
@@ -213,19 +205,9 @@ namespace Netch.Forms.Mode
|
||||
{
|
||||
if (!UseCustomFilenameBox.Checked)
|
||||
{
|
||||
var invalidFileChars = Path.GetInvalidFileNameChars();
|
||||
var fileName = new StringBuilder(RemarkTextBox.Text);
|
||||
foreach (var c in invalidFileChars)
|
||||
fileName.Replace(c, '_');
|
||||
|
||||
FilenameTextBox.Text = fileName.ToString();
|
||||
FilenameTextBox.Text = ModeEditorUtils.ToSafeFileName(RemarkTextBox.Text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void UseCustomFilenameBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
FilenameTextBox.Enabled = UseCustomFilenameBox.Checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
208
Netch/Forms/Mode/Route.Designer.cs
generated
Normal file
208
Netch/Forms/Mode/Route.Designer.cs
generated
Normal file
@@ -0,0 +1,208 @@
|
||||
using System.ComponentModel;
|
||||
using Netch.Properties;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
{
|
||||
partial class Route
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.comboBox1 = new System.Windows.Forms.ComboBox();
|
||||
this.UseCustomFilenameBox = new System.Windows.Forms.CheckBox();
|
||||
this.FilenameLabel = new System.Windows.Forms.Label();
|
||||
this.FilenameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ActionLabel = new System.Windows.Forms.Label();
|
||||
this.RemarkTextBox = new System.Windows.Forms.TextBox();
|
||||
this.RemarkLabel = new System.Windows.Forms.Label();
|
||||
this.containerControl1 = new System.Windows.Forms.ContainerControl();
|
||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||
this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ControlButton = new System.Windows.Forms.Button();
|
||||
this.ConfigurationGroupBox.SuspendLayout();
|
||||
this.containerControl1.SuspendLayout();
|
||||
this.contextMenuStrip.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// ConfigurationGroupBox
|
||||
//
|
||||
this.ConfigurationGroupBox.Controls.Add(this.comboBox1);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.UseCustomFilenameBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.FilenameLabel);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.FilenameTextBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.ActionLabel);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.RemarkTextBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.RemarkLabel);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.containerControl1);
|
||||
this.ConfigurationGroupBox.Location = new System.Drawing.Point(8, 12);
|
||||
this.ConfigurationGroupBox.Name = "ConfigurationGroupBox";
|
||||
this.ConfigurationGroupBox.Size = new System.Drawing.Size(340, 355);
|
||||
this.ConfigurationGroupBox.TabIndex = 2;
|
||||
this.ConfigurationGroupBox.TabStop = false;
|
||||
this.ConfigurationGroupBox.Text = "Configuration";
|
||||
//
|
||||
// comboBox1
|
||||
//
|
||||
this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboBox1.FormattingEnabled = true;
|
||||
this.comboBox1.Location = new System.Drawing.Point(84, 49);
|
||||
this.comboBox1.Name = "comboBox1";
|
||||
this.comboBox1.Size = new System.Drawing.Size(138, 20);
|
||||
this.comboBox1.TabIndex = 11;
|
||||
//
|
||||
// UseCustomFilenameBox
|
||||
//
|
||||
this.UseCustomFilenameBox.AutoSize = true;
|
||||
this.UseCustomFilenameBox.Location = new System.Drawing.Point(84, 100);
|
||||
this.UseCustomFilenameBox.Name = "UseCustomFilenameBox";
|
||||
this.UseCustomFilenameBox.Size = new System.Drawing.Size(138, 16);
|
||||
this.UseCustomFilenameBox.TabIndex = 9;
|
||||
this.UseCustomFilenameBox.Text = "Use Custom Filename";
|
||||
this.UseCustomFilenameBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// FilenameLabel
|
||||
//
|
||||
this.FilenameLabel.AutoSize = true;
|
||||
this.FilenameLabel.Location = new System.Drawing.Point(12, 79);
|
||||
this.FilenameLabel.Name = "FilenameLabel";
|
||||
this.FilenameLabel.Size = new System.Drawing.Size(53, 12);
|
||||
this.FilenameLabel.TabIndex = 6;
|
||||
this.FilenameLabel.Text = "Filename";
|
||||
//
|
||||
// FilenameTextBox
|
||||
//
|
||||
this.FilenameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.UseCustomFilenameBox, "Checked", true));
|
||||
this.FilenameTextBox.Location = new System.Drawing.Point(84, 76);
|
||||
this.FilenameTextBox.Name = "FilenameTextBox";
|
||||
this.FilenameTextBox.Size = new System.Drawing.Size(250, 21);
|
||||
this.FilenameTextBox.TabIndex = 5;
|
||||
//
|
||||
// ActionLabel
|
||||
//
|
||||
this.ActionLabel.AutoSize = true;
|
||||
this.ActionLabel.Location = new System.Drawing.Point(12, 52);
|
||||
this.ActionLabel.Name = "ActionLabel";
|
||||
this.ActionLabel.Size = new System.Drawing.Size(41, 12);
|
||||
this.ActionLabel.TabIndex = 0;
|
||||
this.ActionLabel.Text = "Action";
|
||||
//
|
||||
// RemarkTextBox
|
||||
//
|
||||
this.RemarkTextBox.Location = new System.Drawing.Point(84, 22);
|
||||
this.RemarkTextBox.Name = "RemarkTextBox";
|
||||
this.RemarkTextBox.Size = new System.Drawing.Size(250, 21);
|
||||
this.RemarkTextBox.TabIndex = 1;
|
||||
this.RemarkTextBox.TextChanged += new System.EventHandler(this.RemarkTextBox_TextChanged);
|
||||
//
|
||||
// RemarkLabel
|
||||
//
|
||||
this.RemarkLabel.AutoSize = true;
|
||||
this.RemarkLabel.Location = new System.Drawing.Point(12, 25);
|
||||
this.RemarkLabel.Name = "RemarkLabel";
|
||||
this.RemarkLabel.Size = new System.Drawing.Size(41, 12);
|
||||
this.RemarkLabel.TabIndex = 0;
|
||||
this.RemarkLabel.Text = "Remark";
|
||||
//
|
||||
// containerControl1
|
||||
//
|
||||
this.containerControl1.Controls.Add(this.richTextBox1);
|
||||
this.containerControl1.Location = new System.Drawing.Point(6, 125);
|
||||
this.containerControl1.Name = "containerControl1";
|
||||
this.containerControl1.Size = new System.Drawing.Size(328, 224);
|
||||
this.containerControl1.TabIndex = 10;
|
||||
this.containerControl1.Text = "containerControl1";
|
||||
//
|
||||
// richTextBox1
|
||||
//
|
||||
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.Size = new System.Drawing.Size(328, 224);
|
||||
this.richTextBox1.TabIndex = 0;
|
||||
this.richTextBox1.Text = "";
|
||||
//
|
||||
// contextMenuStrip
|
||||
//
|
||||
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.DeleteToolStripMenuItem});
|
||||
this.contextMenuStrip.Name = "contextMenuStrip";
|
||||
this.contextMenuStrip.Size = new System.Drawing.Size(114, 26);
|
||||
//
|
||||
// DeleteToolStripMenuItem
|
||||
//
|
||||
this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem";
|
||||
this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(113, 22);
|
||||
this.DeleteToolStripMenuItem.Text = "Delete";
|
||||
//
|
||||
// ControlButton
|
||||
//
|
||||
this.ControlButton.Location = new System.Drawing.Point(273, 373);
|
||||
this.ControlButton.Name = "ControlButton";
|
||||
this.ControlButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ControlButton.TabIndex = 3;
|
||||
this.ControlButton.Text = "Save";
|
||||
this.ControlButton.UseVisualStyleBackColor = true;
|
||||
this.ControlButton.Click += new System.EventHandler(this.ControlButton_Click);
|
||||
//
|
||||
// Route
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(356, 419);
|
||||
this.Controls.Add(this.ConfigurationGroupBox);
|
||||
this.Controls.Add(this.ControlButton);
|
||||
this.Name = "Route";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Create Route Table Rule";
|
||||
this.Load += new System.EventHandler(this.Route_Load);
|
||||
this.ConfigurationGroupBox.ResumeLayout(false);
|
||||
this.ConfigurationGroupBox.PerformLayout();
|
||||
this.containerControl1.ResumeLayout(false);
|
||||
this.contextMenuStrip.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
}
|
||||
|
||||
public System.Windows.Forms.GroupBox ConfigurationGroupBox;
|
||||
private System.Windows.Forms.ContainerControl containerControl1;
|
||||
private System.Windows.Forms.ContextMenuStrip contextMenuStrip;
|
||||
public System.Windows.Forms.Button ControlButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem DeleteToolStripMenuItem;
|
||||
private System.Windows.Forms.Label FilenameLabel;
|
||||
private System.Windows.Forms.TextBox FilenameTextBox;
|
||||
private System.Windows.Forms.Label RemarkLabel;
|
||||
private System.Windows.Forms.TextBox RemarkTextBox;
|
||||
private System.Windows.Forms.RichTextBox richTextBox1;
|
||||
private System.Windows.Forms.CheckBox UseCustomFilenameBox;
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ComboBox comboBox1;
|
||||
private System.Windows.Forms.Label ActionLabel;
|
||||
}
|
||||
}
|
||||
129
Netch/Forms/Mode/Route.cs
Normal file
129
Netch/Forms/Mode/Route.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
{
|
||||
public partial class Route : Form
|
||||
{
|
||||
class Item
|
||||
{
|
||||
private string _text;
|
||||
|
||||
public Item(int value, string text)
|
||||
{
|
||||
_text = text;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => i18N.Translate(_text);
|
||||
set => _text = value;
|
||||
}
|
||||
|
||||
public int Value { get; set; }
|
||||
}
|
||||
|
||||
private readonly Item[] _items = {new(1, "Proxy Rule IPs"), new(2, "Bypass Rule IPs")};
|
||||
|
||||
private readonly Models.Mode? _mode;
|
||||
|
||||
public Route(Models.Mode? mode = null)
|
||||
{
|
||||
if (mode != null && mode.Type is not (1 or 2))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
_mode = mode;
|
||||
|
||||
InitializeComponent();
|
||||
Icon = Resources.icon;
|
||||
comboBox1.DataSource = _items;
|
||||
comboBox1.ValueMember = "Value";
|
||||
comboBox1.DisplayMember = "Text";
|
||||
|
||||
i18N.TranslateForm(this);
|
||||
}
|
||||
|
||||
private void Route_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (_mode != null)
|
||||
{
|
||||
Text = "Edit Route Table Rule";
|
||||
|
||||
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
|
||||
FilenameTextBox.Enabled = UseCustomFilenameBox.Enabled = false;
|
||||
|
||||
RemarkTextBox.Text = _mode.Remark;
|
||||
comboBox1.SelectedValue = _mode.Type; // ComboBox SelectedValue worked after ctor
|
||||
FilenameTextBox.Text = _mode.RelativePath;
|
||||
richTextBox1.Lines = _mode.Rule.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(RemarkTextBox.Text))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please enter a mode remark"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(FilenameTextBox.Text))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please enter a mode filename"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_mode != null)
|
||||
{
|
||||
_mode.Remark = RemarkTextBox.Text;
|
||||
_mode.Rule.Clear();
|
||||
_mode.Rule.AddRange(richTextBox1.Lines);
|
||||
_mode.Type = (int) comboBox1.SelectedValue;
|
||||
|
||||
_mode.WriteFile();
|
||||
Global.MainForm.LoadModes();
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
}
|
||||
else
|
||||
{
|
||||
var relativePath = $"Custom\\{FilenameTextBox.Text}.txt";
|
||||
var fullName = ModeHelper.GetFullPath(relativePath);
|
||||
if (File.Exists(fullName))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("File already exists.\n Please Change the filename"));
|
||||
return;
|
||||
}
|
||||
|
||||
var mode = new Models.Mode(fullName)
|
||||
{
|
||||
Type = (int) comboBox1.SelectedValue,
|
||||
Remark = RemarkTextBox.Text
|
||||
};
|
||||
|
||||
mode.Rule.AddRange(richTextBox1.Lines);
|
||||
|
||||
mode.WriteFile();
|
||||
ModeHelper.Add(mode);
|
||||
MessageBoxX.Show(i18N.Translate("Mode added successfully"));
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
private async void RemarkTextBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (!UseCustomFilenameBox.Checked)
|
||||
{
|
||||
FilenameTextBox.Text = ModeEditorUtils.ToSafeFileName(RemarkTextBox.Text);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
|
||||
82
Netch/Forms/SettingForm.Designer.cs
generated
82
Netch/Forms/SettingForm.Designer.cs
generated
@@ -31,7 +31,6 @@ namespace Netch.Forms
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingForm));
|
||||
this.TabControl = new System.Windows.Forms.TabControl();
|
||||
this.GeneralTabPage = new System.Windows.Forms.TabPage();
|
||||
this.ServerPingTypeLabel = new System.Windows.Forms.Label();
|
||||
@@ -60,9 +59,9 @@ namespace Netch.Forms
|
||||
this.LanguageLabel = new System.Windows.Forms.Label();
|
||||
this.LanguageComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.NFTabPage = new System.Windows.Forms.TabPage();
|
||||
this.NoProxyForTcpCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.NoProxyForUdpCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ProcessProxyProtocolComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.ModifySystemDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ProcessProxyProtocolLabel = new System.Windows.Forms.Label();
|
||||
this.ModifiedDNSLabel = new System.Windows.Forms.Label();
|
||||
this.ModifiedDNSTextBox = new System.Windows.Forms.TextBox();
|
||||
this.RedirectorSSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
@@ -79,10 +78,10 @@ namespace Netch.Forms
|
||||
this.UseCustomDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ProxyDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.UseFakeDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
new System.Windows.Forms.CheckBox();
|
||||
this.GlobalBypassIPsButton = new System.Windows.Forms.Button();
|
||||
this.v2rayTabPage = new System.Windows.Forms.TabPage();
|
||||
this.TLSAllowInsecureCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.XrayConeCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.UseMuxCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.KCPGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.mtuLabel = new System.Windows.Forms.Label();
|
||||
@@ -116,7 +115,6 @@ namespace Netch.Forms
|
||||
this.OtherDNSTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ControlButton = new System.Windows.Forms.Button();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.XrayConeCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.TabControl.SuspendLayout();
|
||||
this.GeneralTabPage.SuspendLayout();
|
||||
this.PortGroupBox.SuspendLayout();
|
||||
@@ -408,12 +406,12 @@ namespace Netch.Forms
|
||||
// NFTabPage
|
||||
//
|
||||
this.NFTabPage.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.NFTabPage.Controls.Add(this.NoProxyForTcpCheckBox);
|
||||
this.NFTabPage.Controls.Add(this.NoProxyForUdpCheckBox);
|
||||
this.NFTabPage.Controls.Add(this.ModifySystemDNSCheckBox);
|
||||
this.NFTabPage.Controls.Add(this.ModifiedDNSLabel);
|
||||
this.NFTabPage.Controls.Add(this.ModifiedDNSTextBox);
|
||||
this.NFTabPage.Controls.Add(this.RedirectorSSCheckBox);
|
||||
this.NFTabPage.Controls.Add(this.ProcessProxyProtocolLabel);
|
||||
this.NFTabPage.Controls.Add(this.ProcessProxyProtocolComboBox);
|
||||
this.NFTabPage.Location = new System.Drawing.Point(4, 25);
|
||||
this.NFTabPage.Name = "NFTabPage";
|
||||
this.NFTabPage.Padding = new System.Windows.Forms.Padding(3);
|
||||
@@ -421,27 +419,14 @@ namespace Netch.Forms
|
||||
this.NFTabPage.TabIndex = 1;
|
||||
this.NFTabPage.Text = "Process Mode";
|
||||
//
|
||||
// NoProxyForTcpCheckBox
|
||||
// ProcessProxyProtocolComboBox
|
||||
//
|
||||
this.NoProxyForTcpCheckBox.AutoSize = true;
|
||||
this.NoProxyForTcpCheckBox.Location = new System.Drawing.Point(8, 82);
|
||||
this.NoProxyForTcpCheckBox.Name = "NoProxyForTcpCheckBox";
|
||||
this.NoProxyForTcpCheckBox.Size = new System.Drawing.Size(120, 16);
|
||||
this.NoProxyForTcpCheckBox.TabIndex = 4;
|
||||
this.NoProxyForTcpCheckBox.Text = "No Proxy for Tcp";
|
||||
this.NoProxyForTcpCheckBox.UseVisualStyleBackColor = true;
|
||||
this.NoProxyForTcpCheckBox.CheckedChanged += new System.EventHandler(this.NoProxyForTcpCheckBox_CheckedChanged);
|
||||
//
|
||||
// NoProxyForUdpCheckBox
|
||||
//
|
||||
this.NoProxyForUdpCheckBox.AutoSize = true;
|
||||
this.NoProxyForUdpCheckBox.Location = new System.Drawing.Point(8, 60);
|
||||
this.NoProxyForUdpCheckBox.Name = "NoProxyForUdpCheckBox";
|
||||
this.NoProxyForUdpCheckBox.Size = new System.Drawing.Size(120, 16);
|
||||
this.NoProxyForUdpCheckBox.TabIndex = 3;
|
||||
this.NoProxyForUdpCheckBox.Text = "No Proxy for Udp";
|
||||
this.NoProxyForUdpCheckBox.UseVisualStyleBackColor = true;
|
||||
this.NoProxyForUdpCheckBox.CheckedChanged += new System.EventHandler(this.NoProxyForUdpCheckBox_CheckedChanged);
|
||||
this.ProcessProxyProtocolComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.ProcessProxyProtocolComboBox.FormattingEnabled = true;
|
||||
this.ProcessProxyProtocolComboBox.Location = new System.Drawing.Point(167, 58);
|
||||
this.ProcessProxyProtocolComboBox.Name = "ProcessProxyProtocolComboBox";
|
||||
this.ProcessProxyProtocolComboBox.Size = new System.Drawing.Size(121, 20);
|
||||
this.ProcessProxyProtocolComboBox.TabIndex = 3;
|
||||
//
|
||||
// ModifySystemDNSCheckBox
|
||||
//
|
||||
@@ -453,6 +438,15 @@ namespace Netch.Forms
|
||||
this.ModifySystemDNSCheckBox.Text = "Modify System DNS";
|
||||
this.ModifySystemDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ProcessProxyProtocolLabel
|
||||
//
|
||||
this.ProcessProxyProtocolLabel.AutoSize = true;
|
||||
this.ProcessProxyProtocolLabel.Location = new System.Drawing.Point(24, 61);
|
||||
this.ProcessProxyProtocolLabel.Name = "ProcessProxyProtocolLabel";
|
||||
this.ProcessProxyProtocolLabel.Size = new System.Drawing.Size(89, 12);
|
||||
this.ProcessProxyProtocolLabel.TabIndex = 2;
|
||||
this.ProcessProxyProtocolLabel.Text = "Proxy Protocol";
|
||||
//
|
||||
// ModifiedDNSLabel
|
||||
//
|
||||
this.ModifiedDNSLabel.AutoSize = true;
|
||||
@@ -596,11 +590,11 @@ namespace Netch.Forms
|
||||
// ProxyDNSCheckBox
|
||||
//
|
||||
this.ProxyDNSCheckBox.AutoSize = true;
|
||||
this.ProxyDNSCheckBox.Location = new System.Drawing.Point(261, 139);
|
||||
this.ProxyDNSCheckBox.Location = new System.Drawing.Point(175, 139);
|
||||
this.ProxyDNSCheckBox.Name = "ProxyDNSCheckBox";
|
||||
this.ProxyDNSCheckBox.Size = new System.Drawing.Size(138, 16);
|
||||
this.ProxyDNSCheckBox.Size = new System.Drawing.Size(216, 16);
|
||||
this.ProxyDNSCheckBox.TabIndex = 9;
|
||||
this.ProxyDNSCheckBox.Text = "Proxy DNS in Mode 2";
|
||||
this.ProxyDNSCheckBox.Text = "Proxy DNS in Proxy Rule IPs Mode";
|
||||
this.ProxyDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// UseFakeDNSCheckBox
|
||||
@@ -648,6 +642,16 @@ namespace Netch.Forms
|
||||
this.TLSAllowInsecureCheckBox.Text = "TLS AllowInsecure";
|
||||
this.TLSAllowInsecureCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// XrayConeCheckBox
|
||||
//
|
||||
this.XrayConeCheckBox.AutoSize = true;
|
||||
this.XrayConeCheckBox.Location = new System.Drawing.Point(6, 15);
|
||||
this.XrayConeCheckBox.Name = "XrayConeCheckBox";
|
||||
this.XrayConeCheckBox.Size = new System.Drawing.Size(336, 16);
|
||||
this.XrayConeCheckBox.TabIndex = 1;
|
||||
this.XrayConeCheckBox.Text = "FullCone Support (Required Server Xray-core v1.3.0+)";
|
||||
this.XrayConeCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// UseMuxCheckBox
|
||||
//
|
||||
this.UseMuxCheckBox.AutoSize = true;
|
||||
@@ -965,7 +969,7 @@ namespace Netch.Forms
|
||||
//
|
||||
// ControlButton
|
||||
//
|
||||
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ControlButton.Location = new System.Drawing.Point(397, 363);
|
||||
this.ControlButton.Name = "ControlButton";
|
||||
this.ControlButton.Size = new System.Drawing.Size(75, 23);
|
||||
@@ -987,16 +991,6 @@ namespace Netch.Forms
|
||||
this.flowLayoutPanel1.Size = new System.Drawing.Size(480, 400);
|
||||
this.flowLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// XrayConeCheckBox
|
||||
//
|
||||
this.XrayConeCheckBox.AutoSize = true;
|
||||
this.XrayConeCheckBox.Location = new System.Drawing.Point(6, 15);
|
||||
this.XrayConeCheckBox.Name = "XrayConeCheckBox";
|
||||
this.XrayConeCheckBox.Size = new System.Drawing.Size(78, 16);
|
||||
this.XrayConeCheckBox.TabIndex = 1;
|
||||
this.XrayConeCheckBox.Text = "FullCone Support (Required Server Xray-core v1.3.0+)";
|
||||
this.XrayConeCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// SettingForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
@@ -1006,7 +1000,6 @@ namespace Netch.Forms
|
||||
this.ClientSize = new System.Drawing.Size(480, 400);
|
||||
this.Controls.Add(this.flowLayoutPanel1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = ((System.Drawing.Icon) (resources.GetObject("$this.Icon")));
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "SettingForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
@@ -1033,10 +1026,10 @@ namespace Netch.Forms
|
||||
this.flowLayoutPanel1.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
private System.Windows.Forms.CheckBox XrayConeCheckBox;
|
||||
private System.Windows.Forms.TextBox StartedPingIntervalTextBox;
|
||||
private System.Windows.Forms.CheckBox NoProxyForTcpCheckBox;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1117,9 +1110,10 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.TextBox ModifiedDNSTextBox;
|
||||
private System.Windows.Forms.Label ModifiedDNSLabel;
|
||||
private System.Windows.Forms.CheckBox RedirectorSSCheckBox;
|
||||
private System.Windows.Forms.CheckBox NoProxyForUdpCheckBox;
|
||||
private System.Windows.Forms.Label ServerPingTypeLabel;
|
||||
private System.Windows.Forms.RadioButton TCPingRadioBtn;
|
||||
private System.Windows.Forms.RadioButton ICMPingRadioBtn;
|
||||
private System.Windows.Forms.ComboBox ProcessProxyProtocolComboBox;
|
||||
private System.Windows.Forms.Label ProcessProxyProtocolLabel;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
@@ -19,18 +20,9 @@ namespace Netch.Forms
|
||||
public SettingForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
Icon = Resources.icon;
|
||||
i18N.TranslateForm(this);
|
||||
InitValue();
|
||||
}
|
||||
|
||||
private void SettingForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
|
||||
Task.Run(() => BeginInvoke(new Action(() => UseFakeDNSCheckBox.Visible = Global.Flags.SupportFakeDns)));
|
||||
}
|
||||
|
||||
private void InitValue()
|
||||
{
|
||||
#region General
|
||||
|
||||
BindTextBox<ushort>(Socks5PortTextBox,
|
||||
@@ -70,13 +62,48 @@ namespace Netch.Forms
|
||||
i => Global.Settings.StartedPingInterval = i,
|
||||
Global.Settings.StartedPingInterval);
|
||||
|
||||
InitSTUN();
|
||||
object[]? stuns;
|
||||
try
|
||||
{
|
||||
stuns = File.ReadLines("bin\\stun.txt").Cast<object>().ToArray();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Warning($"Load stun.txt failed: {e.Message}");
|
||||
stuns = null;
|
||||
}
|
||||
|
||||
BindComboBox(STUN_ServerComboBox,
|
||||
s =>
|
||||
{
|
||||
var split = s.SplitRemoveEmptyEntriesAndTrimEntries(':');
|
||||
if (!split.Any())
|
||||
return false;
|
||||
|
||||
var port = split.ElementAtOrDefault(1);
|
||||
if (port != null)
|
||||
if (!ushort.TryParse(split[1], out _))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
o =>
|
||||
{
|
||||
var split = o.ToString().SplitRemoveEmptyEntriesAndTrimEntries(':');
|
||||
Global.Settings.STUN_Server = split[0];
|
||||
|
||||
var port = split.ElementAtOrDefault(1);
|
||||
Global.Settings.STUN_Server_Port = port != null ? ushort.Parse(port) : 3478;
|
||||
},
|
||||
Global.Settings.STUN_Server + ":" + Global.Settings.STUN_Server_Port,
|
||||
stuns);
|
||||
|
||||
BindTextBox<string>(AclAddrTextBox, s => true, s => Global.Settings.ACL = s, Global.Settings.ACL);
|
||||
AclAddrTextBox.Text = Global.Settings.ACL;
|
||||
|
||||
LanguageComboBox.Items.AddRange(i18N.GetTranslateList().ToArray());
|
||||
LanguageComboBox.SelectedItem = Global.Settings.Language;
|
||||
BindListComboBox(LanguageComboBox,
|
||||
o => Global.Settings.Language = o.ToString(),
|
||||
i18N.GetTranslateList().Cast<object>().ToArray(),
|
||||
Global.Settings.Language);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -84,13 +111,14 @@ namespace Netch.Forms
|
||||
|
||||
BindCheckBox(ModifySystemDNSCheckBox, b => Global.Settings.ModifySystemDNS = b, Global.Settings.ModifySystemDNS);
|
||||
|
||||
BindTextBox(ModifiedDNSTextBox, s => DNS.TrySplit(s, out _, 2), s => Global.Settings.ModifiedDNS = s, Global.Settings.ModifiedDNS);
|
||||
BindTextBox(ModifiedDNSTextBox, s => DnsUtils.TrySplit(s, out _, 2), s => Global.Settings.ModifiedDNS = s, Global.Settings.ModifiedDNS);
|
||||
|
||||
BindCheckBox(RedirectorSSCheckBox, s => Global.Settings.RedirectorSS = s, Global.Settings.RedirectorSS);
|
||||
|
||||
BindCheckBox(NoProxyForUdpCheckBox, s => Global.Settings.ProcessNoProxyForUdp = s, Global.Settings.ProcessNoProxyForUdp);
|
||||
|
||||
BindCheckBox(NoProxyForTcpCheckBox, s => Global.Settings.ProcessNoProxyForTcp = s, Global.Settings.ProcessNoProxyForTcp);
|
||||
BindListComboBox(ProcessProxyProtocolComboBox,
|
||||
s => Global.Settings.ProcessProxyProtocol = (PortType) Enum.Parse(typeof(PortType), s.ToString(), false),
|
||||
Enum.GetNames(typeof(PortType)).Cast<object>().ToArray(),
|
||||
Global.Settings.ProcessProxyProtocol.ToString());
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -114,13 +142,13 @@ namespace Netch.Forms
|
||||
BindCheckBox(UseCustomDNSCheckBox, b => { Global.Settings.TUNTAP.UseCustomDNS = b; }, Global.Settings.TUNTAP.UseCustomDNS);
|
||||
|
||||
BindTextBox(TUNTAPDNSTextBox,
|
||||
s => !UseCustomDNSCheckBox.Checked || DNS.TrySplit(s, out _, 2),
|
||||
s => !UseCustomDNSCheckBox.Checked || DnsUtils.TrySplit(s, out _, 2),
|
||||
s =>
|
||||
{
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
Global.Settings.TUNTAP.DNS = DNS.Split(s).ToList();
|
||||
Global.Settings.TUNTAP.DNS = DnsUtils.Split(s).ToList();
|
||||
},
|
||||
DNS.Join(Global.Settings.TUNTAP.DNS));
|
||||
DnsUtils.Join(Global.Settings.TUNTAP.DNS));
|
||||
|
||||
BindCheckBox(ProxyDNSCheckBox, b => Global.Settings.TUNTAP.ProxyDNS = b, Global.Settings.TUNTAP.ProxyDNS);
|
||||
BindCheckBox(UseFakeDNSCheckBox, b => Global.Settings.TUNTAP.UseFakeDNS = b, Global.Settings.TUNTAP.UseFakeDNS);
|
||||
@@ -199,27 +227,18 @@ namespace Netch.Forms
|
||||
#endregion
|
||||
}
|
||||
|
||||
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
private void SettingForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any() ? DNS.Join(Global.Settings.TUNTAP.DNS) : "1.1.1.1";
|
||||
else
|
||||
TUNTAPDNSTextBox.Text = "AioDNS";
|
||||
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
|
||||
Task.Run(() => BeginInvoke(new Action(() => UseFakeDNSCheckBox.Visible = Global.Flags.SupportFakeDns)));
|
||||
}
|
||||
|
||||
private void InitSTUN()
|
||||
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object? sender, EventArgs? e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var stuns = File.ReadLines("bin\\stun.txt");
|
||||
STUN_ServerComboBox.Items.AddRange(stuns.ToArray());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
STUN_ServerComboBox.Text = $"{Global.Settings.STUN_Server}:{Global.Settings.STUN_Server_Port}";
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any() ? DnsUtils.Join(Global.Settings.TUNTAP.DNS) : "1.1.1.1";
|
||||
else
|
||||
TUNTAPDNSTextBox.Text = "AioDNS";
|
||||
}
|
||||
|
||||
private void GlobalBypassIPsButton_Click(object sender, EventArgs e)
|
||||
@@ -235,55 +254,20 @@ namespace Netch.Forms
|
||||
|
||||
#region Check
|
||||
|
||||
var flag = true;
|
||||
foreach (var pair in _checkActions.Where(pair => !pair.Value.Invoke(pair.Key.Text)))
|
||||
{
|
||||
Utils.Utils.ChangeControlForeColor(pair.Key, Color.Red);
|
||||
flag = false;
|
||||
}
|
||||
var checkNotPassControl = _checkActions.Where(pair => !pair.Value.Invoke(pair.Key.Text)).Select(pair => pair.Key).ToList();
|
||||
foreach (Control control in checkNotPassControl)
|
||||
Utils.Utils.ChangeControlForeColor(control, Color.Red);
|
||||
|
||||
if (!flag)
|
||||
if (checkNotPassControl.Any())
|
||||
return;
|
||||
|
||||
#endregion
|
||||
|
||||
#region CheckSTUN
|
||||
|
||||
var errFlag = false;
|
||||
var stunServer = string.Empty;
|
||||
ushort stunServerPort = 3478;
|
||||
|
||||
var stun = STUN_ServerComboBox.Text.Split(':');
|
||||
|
||||
if (stun.Any())
|
||||
{
|
||||
stunServer = stun[0];
|
||||
if (stun.Length > 1)
|
||||
if (!ushort.TryParse(stun[1], out stunServerPort))
|
||||
errFlag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
errFlag = true;
|
||||
}
|
||||
|
||||
if (errFlag)
|
||||
{
|
||||
Utils.Utils.ChangeControlForeColor(STUN_ServerComboBox, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Save
|
||||
|
||||
foreach (var pair in _saveActions)
|
||||
pair.Value.Invoke(pair.Key);
|
||||
|
||||
Global.Settings.STUN_Server = stunServer;
|
||||
Global.Settings.STUN_Server_Port = stunServerPort;
|
||||
Global.Settings.Language = LanguageComboBox.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
Utils.Utils.RegisterNetchStartupItem();
|
||||
@@ -293,6 +277,8 @@ namespace Netch.Forms
|
||||
Close();
|
||||
}
|
||||
|
||||
#region BindUtils
|
||||
|
||||
private void BindTextBox(TextBox control, Func<string, bool> check, Action<string> save, object value)
|
||||
{
|
||||
BindTextBox<string>(control, check, save, value);
|
||||
@@ -329,16 +315,27 @@ namespace Netch.Forms
|
||||
_saveActions.Add(control, c => save.Invoke(((RadioButton) c).Checked));
|
||||
}
|
||||
|
||||
private void NoProxyForUdpCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
private void BindListComboBox(ComboBox control, Action<object> save, object[] values, object value, string propertyName = "SelectedItem")
|
||||
{
|
||||
if (NoProxyForUdpCheckBox.Checked)
|
||||
NoProxyForTcpCheckBox.Checked = false;
|
||||
if (control.DropDownStyle != ComboBoxStyle.DropDownList)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
control.Items.AddRange(values);
|
||||
_saveActions.Add(control, c => save.Invoke(((ComboBox) c).SelectedItem));
|
||||
Load += (_, _) => { control.SelectedItem = value; };
|
||||
}
|
||||
|
||||
private void NoProxyForTcpCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
private void BindComboBox(ComboBox control, Func<string, bool> check, Action<string> save, string value, object[]? values = null)
|
||||
{
|
||||
if (NoProxyForTcpCheckBox.Checked)
|
||||
NoProxyForUdpCheckBox.Checked = false;
|
||||
if (values != null)
|
||||
control.Items.AddRange(values);
|
||||
|
||||
_saveActions.Add(control, c => save.Invoke(((ComboBox) c).Text));
|
||||
_checkActions.Add(control, check.Invoke);
|
||||
|
||||
Load += (_, _) => { control.Text = value; };
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
1
Netch/Forms/SubscribeForm.Designer.cs
generated
1
Netch/Forms/SubscribeForm.Designer.cs
generated
@@ -235,7 +235,6 @@
|
||||
this.Controls.Add(this.MainTableLayoutPanel);
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte) (134)));
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = ((System.Drawing.Icon) (resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "SubscribeForm";
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
@@ -11,6 +12,7 @@ namespace Netch.Forms
|
||||
public SubscribeForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
Icon = Resources.icon;
|
||||
|
||||
i18N.TranslateForm(this);
|
||||
i18N.TranslateForm(pContextMenuStrip);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using WindowsJobAPI;
|
||||
@@ -30,10 +28,16 @@ namespace Netch
|
||||
/// <summary>
|
||||
/// 主窗体的静态实例
|
||||
/// </summary>
|
||||
public static MainForm MainForm;
|
||||
private static readonly Lazy<MainForm> LazyMainForm = new(() => new MainForm());
|
||||
|
||||
public static readonly Mutex Mutex = new(false, "Global\\Netch");
|
||||
|
||||
#if DEBUG
|
||||
public static bool Testing = false;
|
||||
#else
|
||||
public const bool Testing = false;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 用于读取和写入的配置
|
||||
/// </summary>
|
||||
@@ -53,55 +57,21 @@ namespace Netch
|
||||
{
|
||||
public static readonly bool IsWindows10Upper = Environment.OSVersion.Version.Major >= 10;
|
||||
|
||||
private static bool? _supportFakeDns;
|
||||
private static readonly Lazy<bool> LazySupportFakeDns = new(() => new TUNTAPController().TestFakeDNS());
|
||||
|
||||
public static bool SupportFakeDns => _supportFakeDns ??= new TUNTAPController().TestFakeDNS();
|
||||
public static bool SupportFakeDns => LazySupportFakeDns.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 出口适配器
|
||||
/// 主窗体的静态实例
|
||||
/// </summary>
|
||||
public static class Outbound
|
||||
public static MainForm MainForm => LazyMainForm.Value;
|
||||
|
||||
public static JsonSerializerOptions NewDefaultJsonSerializerOptions => new()
|
||||
{
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public static int Index = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public static IPAddress Gateway;
|
||||
|
||||
public static NetworkInterface Adapter;
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public static IPAddress Address => Adapter.GetIPProperties()
|
||||
.UnicastAddresses.First(ip => ip.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||
.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TUN/TAP 适配器
|
||||
/// </summary>
|
||||
public static class TUNTAP
|
||||
{
|
||||
/// <summary>
|
||||
/// 适配器
|
||||
/// </summary>
|
||||
public static NetworkInterface Adapter;
|
||||
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public static int Index = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 组件 ID
|
||||
/// </summary>
|
||||
public static string ComponentID = string.Empty;
|
||||
}
|
||||
WriteIndented = true,
|
||||
IgnoreNullValues = true,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
#nullable disable
|
||||
using System;
|
||||
|
||||
namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
namespace Netch.Models.GitHubRelease
|
||||
#nullable disable
|
||||
namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
public class GitHubUser
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
#nullable disable
|
||||
using System;
|
||||
|
||||
namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
public int Compare(object x, object y)
|
||||
{
|
||||
return VersionUtil.CompareVersion(x?.ToString(), y?.ToString());
|
||||
return VersionUtil.CompareVersion(x.ToString(), y.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Netch/Models/IAdapter.cs
Normal file
15
Netch/Models/IAdapter.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public interface IAdapter
|
||||
{
|
||||
public abstract int Index { get; }
|
||||
|
||||
public abstract IPAddress Gateway { get; }
|
||||
|
||||
public abstract NetworkInterface NetworkInterface { get; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Controllers;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
@@ -28,7 +28,7 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
string[] UriScheme { get; }
|
||||
|
||||
Server ParseJObject(in JObject j);
|
||||
public abstract Type ServerType { get; }
|
||||
|
||||
public void Edit(Server s);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -8,7 +9,7 @@ namespace Netch.Models
|
||||
{
|
||||
public class Mode
|
||||
{
|
||||
public readonly string FullName;
|
||||
public readonly string? FullName;
|
||||
|
||||
/// <summary>
|
||||
/// 规则
|
||||
@@ -18,11 +19,12 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 绕过中国(0. 不绕过 1. 绕过)
|
||||
/// </summary>
|
||||
public bool BypassChina = false;
|
||||
public bool BypassChina { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark;
|
||||
public string Remark { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 类型
|
||||
@@ -40,7 +42,7 @@ namespace Netch.Models
|
||||
/// 5. Socks5 + HTTP 代理(不设置到系统代理)
|
||||
/// <para />
|
||||
/// </summary>
|
||||
public int Type = 0;
|
||||
public int Type { get; set; } = 0;
|
||||
|
||||
public Mode(string fullName)
|
||||
{
|
||||
@@ -54,7 +56,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 文件相对路径(必须是存在的文件)
|
||||
/// </summary>
|
||||
public string RelativePath => ModeHelper.GetRelativePath(FullName);
|
||||
public string? RelativePath => FullName == null ? null : ModeHelper.GetRelativePath(FullName);
|
||||
|
||||
public List<string> FullRule
|
||||
{
|
||||
@@ -76,7 +78,7 @@ namespace Netch.Models
|
||||
relativePath.Replace(">", "");
|
||||
relativePath.Replace(".h", ".txt");
|
||||
|
||||
var mode = Global.Modes.FirstOrDefault(m => m.RelativePath.Equals(relativePath.ToString()));
|
||||
var mode = Global.Modes.FirstOrDefault(m => m!.FullName != null && m.RelativePath!.Equals(relativePath.ToString()));
|
||||
|
||||
if (mode == null)
|
||||
{
|
||||
@@ -111,14 +113,17 @@ namespace Netch.Models
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteFile()
|
||||
public void WriteFile(string? fullName = null)
|
||||
{
|
||||
var dir = Path.GetDirectoryName(FullName);
|
||||
if (fullName != null)
|
||||
throw new NotImplementedException();
|
||||
|
||||
var dir = Path.GetDirectoryName(FullName)!;
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
// 写入到模式文件里
|
||||
File.WriteAllText(FullName, ToFileString());
|
||||
File.WriteAllText(FullName!, ToFileString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -145,7 +150,7 @@ namespace Netch.Models
|
||||
/// 是否会转发 UDP
|
||||
public static bool TestNatRequired(this Mode mode)
|
||||
{
|
||||
return mode.Type is 0 or 1 or 2;
|
||||
return mode.Type is 0 or 2;
|
||||
}
|
||||
|
||||
/// Socks5 分流是否能被有效实施
|
||||
|
||||
69
Netch/Models/OutboundAdapter.cs
Normal file
69
Netch/Models/OutboundAdapter.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using Microsoft.Win32;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class OutboundAdapter : IAdapter
|
||||
{
|
||||
public OutboundAdapter(bool logging = true)
|
||||
{
|
||||
// 寻找出口适配器
|
||||
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0)
|
||||
{
|
||||
throw new MessageException("GetBestRoute 搜索失败");
|
||||
}
|
||||
|
||||
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces()
|
||||
.First(ni => ni.Supports(NetworkInterfaceComponent.IPv4) &&
|
||||
ni.GetIPProperties().GetIPv4Properties().Index == pRoute.dwForwardIfIndex);
|
||||
|
||||
Index = (int) pRoute.dwForwardIfIndex;
|
||||
Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b);
|
||||
_parametersRegistry =
|
||||
Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{NetworkInterface.Id}", true)!;
|
||||
|
||||
if (logging)
|
||||
{
|
||||
Logging.Info($"出口 网关 地址:{Gateway}");
|
||||
Logging.Info($"出口适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {Index}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public int Index { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public IPAddress Gateway { get; }
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
|
||||
|
||||
public string DNS
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return (string) _parametersRegistry.GetValue("NameServer");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
set => _parametersRegistry.SetValue("NameServer", value, RegistryValueKind.String);
|
||||
}
|
||||
|
||||
private readonly RegistryKey _parametersRegistry;
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,13 @@
|
||||
{
|
||||
public class Profile
|
||||
{
|
||||
public int Index;
|
||||
public string ModeRemark;
|
||||
public string ProfileName;
|
||||
public string ServerRemark;
|
||||
public int Index { get; set; }
|
||||
|
||||
public string ModeRemark { get; set; }
|
||||
|
||||
public string ProfileName { get; set; }
|
||||
|
||||
public string ServerRemark { get; set; }
|
||||
|
||||
public Profile(Server server, Mode mode, string name, int index)
|
||||
{
|
||||
@@ -15,11 +18,12 @@
|
||||
Index = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a dummy one.
|
||||
/// </summary>
|
||||
public Profile()
|
||||
{
|
||||
ServerRemark = string.Empty;
|
||||
ModeRemark = string.Empty;
|
||||
ProfileName = string.Empty;
|
||||
Index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
@@ -11,36 +12,41 @@ namespace Netch.Models
|
||||
/// 延迟
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int Delay = -1;
|
||||
public int Delay { get; private set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 组
|
||||
/// </summary>
|
||||
public string Group = "None";
|
||||
public string Group { get; set; } = "None";
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public string Hostname;
|
||||
public string Hostname { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public ushort Port;
|
||||
public ushort Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 倍率
|
||||
/// </summary>
|
||||
public double Rate = 1.0;
|
||||
public double Rate { get; } = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark;
|
||||
public string Remark { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 代理类型
|
||||
/// </summary>
|
||||
public string Type;
|
||||
public virtual string Type { get; } = string.Empty;
|
||||
|
||||
[JsonExtensionData]
|
||||
// ReSharper disable once CollectionNeverUpdated.Global
|
||||
public Dictionary<string, object> ExtensionData { get; set; } = new();
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
@@ -58,7 +64,17 @@ namespace Netch.Models
|
||||
if (Group.Equals("None") || Group.Equals(""))
|
||||
Group = "NONE";
|
||||
|
||||
return $"[{ServerHelper.GetUtilByTypeName(Type)?.ShortName ?? "WTF"}][{Group}] {remark}";
|
||||
string shortName;
|
||||
if (Type == string.Empty)
|
||||
{
|
||||
shortName = "WTF";
|
||||
}
|
||||
else
|
||||
{
|
||||
shortName = ServerHelper.GetUtilByTypeName(Type).ShortName;
|
||||
}
|
||||
|
||||
return $"[{shortName}][{Group}] {remark}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,7 +85,7 @@ namespace Netch.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
var destination = DNS.Lookup(Hostname);
|
||||
var destination = DnsUtils.Lookup(Hostname);
|
||||
if (destination == null)
|
||||
return Delay = -2;
|
||||
|
||||
@@ -106,7 +122,20 @@ namespace Netch.Models
|
||||
{
|
||||
public static string AutoResolveHostname(this Server server)
|
||||
{
|
||||
return Global.Settings.ResolveServerHostname ? DNS.Lookup(server.Hostname).ToString() : server.Hostname;
|
||||
return Global.Settings.ResolveServerHostname ? DnsUtils.Lookup(server.Hostname)!.ToString() : server.Hostname;
|
||||
}
|
||||
|
||||
public static bool Valid(this Server server)
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerHelper.GetTypeByTypeName(server.Type);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
@@ -10,75 +11,78 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public string Address = "10.0.236.10";
|
||||
public string Address { get; set; } = "10.0.236.10";
|
||||
|
||||
/// <summary>
|
||||
/// DNS
|
||||
/// </summary>
|
||||
public List<string> DNS = new();
|
||||
public List<string> DNS { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public string Gateway = "10.0.236.1";
|
||||
public string Gateway { get; set; } = "10.0.236.1";
|
||||
|
||||
/// <summary>
|
||||
/// 掩码
|
||||
/// </summary>
|
||||
public string Netmask = "255.255.255.0";
|
||||
public string Netmask { get; set; } = "255.255.255.0";
|
||||
|
||||
/// <summary>
|
||||
/// 模式 2 下是否代理 DNS
|
||||
/// </summary>
|
||||
public bool ProxyDNS = false;
|
||||
public bool ProxyDNS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 使用自定义 DNS 设置
|
||||
/// </summary>
|
||||
public bool UseCustomDNS = false;
|
||||
public bool UseCustomDNS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 使用Fake DNS
|
||||
/// </summary>
|
||||
public bool UseFakeDNS = false;
|
||||
public bool UseFakeDNS { get; set; } = false;
|
||||
}
|
||||
|
||||
public class KcpConfig
|
||||
{
|
||||
public bool congestion = false;
|
||||
public bool congestion { get; set; } = false;
|
||||
|
||||
public int downlinkCapacity = 100;
|
||||
public int mtu = 1350;
|
||||
public int downlinkCapacity { get; set; } = 100;
|
||||
|
||||
public int readBufferSize = 2;
|
||||
public int mtu { get; set; } = 1350;
|
||||
|
||||
public int tti = 50;
|
||||
public int readBufferSize { get; set; } = 2;
|
||||
|
||||
public int uplinkCapacity = 12;
|
||||
public int tti { get; set; } = 50;
|
||||
|
||||
public int writeBufferSize = 2;
|
||||
public int uplinkCapacity { get; set; } = 12;
|
||||
|
||||
public int writeBufferSize { get; set; } = 2;
|
||||
}
|
||||
|
||||
public class V2rayConfig
|
||||
{
|
||||
public bool AllowInsecure = true;
|
||||
public bool AllowInsecure { get; set; } = false;
|
||||
|
||||
public KcpConfig KcpConfig = new();
|
||||
public KcpConfig KcpConfig { get; set; } = new();
|
||||
|
||||
public bool UseMux = false;
|
||||
public bool UseMux { get; set; } = false;
|
||||
|
||||
public bool V2rayNShareLink = true;
|
||||
public bool XrayCone = false;
|
||||
public bool V2rayNShareLink { get; set; } = true;
|
||||
|
||||
public bool XrayCone { get; set; } = false;
|
||||
}
|
||||
|
||||
public class AioDNSConfig
|
||||
{
|
||||
public string ChinaDNS = "223.5.5.5";
|
||||
public string ChinaDNS { get; set; } = "223.5.5.5";
|
||||
|
||||
public string OtherDNS = "1.1.1.1";
|
||||
public string OtherDNS { get; set; } = "1.1.1.1";
|
||||
|
||||
public string Protocol = "tcp";
|
||||
public string RulePath = "bin\\china_site_list";
|
||||
public string Protocol { get; set; } = "tcp";
|
||||
|
||||
public string RulePath { get; set; } = "bin\\china_site_list";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -89,211 +93,203 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 服务器列表
|
||||
/// </summary>
|
||||
public readonly List<Server> Server = new();
|
||||
public List<Server> Server { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// ACL规则
|
||||
/// </summary>
|
||||
public string ACL = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/banAD.acl";
|
||||
public string ACL { get; set; } = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/banAD.acl";
|
||||
|
||||
public AioDNSConfig AioDNS = new();
|
||||
public AioDNSConfig AioDNS { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用DLL启动Shadowsocks
|
||||
/// </summary>
|
||||
public bool BootShadowsocksFromDLL = true;
|
||||
public bool BootShadowsocksFromDLL { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 全局绕过 IP 列表
|
||||
/// </summary>
|
||||
public List<string> BypassIPs = new();
|
||||
public List<string> BypassIPs { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 是否检查 Beta 更新
|
||||
/// </summary>
|
||||
public bool CheckBetaUpdate = false;
|
||||
public bool CheckBetaUpdate { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否打开软件时检查更新
|
||||
/// </summary>
|
||||
public bool CheckUpdateWhenOpened = true;
|
||||
public bool CheckUpdateWhenOpened { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 测试所有服务器心跳/秒
|
||||
/// </summary>
|
||||
public int DetectionTick = 10;
|
||||
public int DetectionTick { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 是否关闭窗口时退出
|
||||
/// </summary>
|
||||
public bool ExitWhenClosed = false;
|
||||
public bool ExitWhenClosed { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 本地端口
|
||||
/// </summary>
|
||||
public ushort HTTPLocalPort = 2802;
|
||||
public ushort HTTPLocalPort { get; set; } = 2802;
|
||||
|
||||
/// <summary>
|
||||
/// 语言设置
|
||||
/// </summary>
|
||||
public string Language = "System";
|
||||
public string Language { get; set; } = "System";
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 和 Socks5 本地代理地址
|
||||
/// </summary>
|
||||
public string LocalAddress = "127.0.0.1";
|
||||
public string LocalAddress { get; set; } = "127.0.0.1";
|
||||
|
||||
/// <summary>
|
||||
/// 是否启动后自动最小化
|
||||
/// </summary>
|
||||
public bool MinimizeWhenStarted = false;
|
||||
public bool MinimizeWhenStarted { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 模式选择位置
|
||||
/// </summary>
|
||||
public int ModeComboBoxSelectedIndex = 0;
|
||||
public int ModeComboBoxSelectedIndex { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 要修改为的系统 DNS
|
||||
/// </summary>
|
||||
public string ModifiedDNS = "1.1.1.1,8.8.8.8";
|
||||
public string ModifiedDNS { get; set; } = "1.1.1.1,8.8.8.8";
|
||||
|
||||
/// <summary>
|
||||
/// 修改系统 DNS
|
||||
/// </summary>
|
||||
public bool ModifySystemDNS = false;
|
||||
public bool ModifySystemDNS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// GFWList
|
||||
/// </summary>
|
||||
public string PAC = "https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white.pac";
|
||||
public string PAC { get; set; } = "https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white.pac";
|
||||
|
||||
/// <summary>
|
||||
/// PAC端口
|
||||
/// </summary>
|
||||
public int Pac_Port = 2803;
|
||||
|
||||
/// <summary>
|
||||
/// PAC URL
|
||||
/// </summary>
|
||||
public string Pac_Url = "";
|
||||
public ushort Pac_Port { get; set; } = 2803;
|
||||
|
||||
/// <summary>
|
||||
/// 不代理TCP
|
||||
/// </summary>
|
||||
public bool ProcessNoProxyForTcp = false;
|
||||
|
||||
/// <summary>
|
||||
/// 不代理UDP
|
||||
/// </summary>
|
||||
public bool ProcessNoProxyForUdp = false;
|
||||
public PortType ProcessProxyProtocol { get; set; } = PortType.Both;
|
||||
|
||||
/// <summary>
|
||||
/// 快捷配置数量
|
||||
/// </summary>
|
||||
public int ProfileCount = 4;
|
||||
public int ProfileCount { get; set; } = 4;
|
||||
|
||||
/// <summary>
|
||||
/// 已保存的快捷配置
|
||||
/// </summary>
|
||||
public List<Profile> Profiles = new();
|
||||
public List<Profile> Profiles { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 配置最大列数
|
||||
/// </summary>
|
||||
public byte ProfileTableColumnCount = 5;
|
||||
public byte ProfileTableColumnCount { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用RDR内置SS
|
||||
/// </summary>
|
||||
public bool RedirectorSS = false;
|
||||
public bool RedirectorSS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Redirector TCP 占用端口
|
||||
/// </summary>
|
||||
public ushort RedirectorTCPPort = 3901;
|
||||
public ushort RedirectorTCPPort { get; set; } = 3901;
|
||||
|
||||
/// <summary>
|
||||
/// 网页请求超时 毫秒
|
||||
/// </summary>
|
||||
public int RequestTimeout = 10000;
|
||||
public int RequestTimeout { get; set; } = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// 解析服务器主机名
|
||||
/// </summary>
|
||||
public bool ResolveServerHostname = false;
|
||||
public bool ResolveServerHostname { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否开机启动软件
|
||||
/// </summary>
|
||||
public bool RunAtStartup = false;
|
||||
public bool RunAtStartup { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 服务器选择位置
|
||||
/// </summary>
|
||||
public int ServerComboBoxSelectedIndex = 0;
|
||||
public int ServerComboBoxSelectedIndex { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 服务器测试方式 false.ICMPing true.TCPing
|
||||
/// </summary>
|
||||
public bool ServerTCPing = true;
|
||||
public bool ServerTCPing { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Socks5 本地端口
|
||||
/// </summary>
|
||||
public ushort Socks5LocalPort = 2801;
|
||||
public ushort Socks5LocalPort { get; set; } = 2801;
|
||||
|
||||
/// <summary>
|
||||
/// 启动后延迟测试间隔/秒
|
||||
/// </summary>
|
||||
public int StartedPingInterval = -1;
|
||||
public int StartedPingInterval { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 是否打开软件时启动加速
|
||||
/// </summary>
|
||||
public bool StartWhenOpened = false;
|
||||
public bool StartWhenOpened { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否退出时停止
|
||||
/// </summary>
|
||||
public bool StopWhenExited = false;
|
||||
public bool StopWhenExited { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// STUN测试服务器
|
||||
/// </summary>
|
||||
public string STUN_Server = "stun.syncthing.net";
|
||||
public string STUN_Server { get; set; } = "stun.syncthing.net";
|
||||
|
||||
/// <summary>
|
||||
/// STUN测试服务器
|
||||
/// </summary>
|
||||
public int STUN_Server_Port = 3478;
|
||||
public int STUN_Server_Port { get; set; } = 3478;
|
||||
|
||||
/// <summary>
|
||||
/// 订阅链接列表
|
||||
/// </summary>
|
||||
public List<SubscribeLink> SubscribeLink = new();
|
||||
public List<SubscribeLink> SubscribeLink { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// TUNTAP 适配器配置
|
||||
/// </summary>
|
||||
public TUNTAPConfig TUNTAP = new();
|
||||
public TUNTAPConfig TUNTAP { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// UDP Socket 占用端口
|
||||
/// </summary>
|
||||
public ushort UDPSocketPort = 18291;
|
||||
public ushort UDPSocketPort { get; set; } = 18291;
|
||||
|
||||
/// <summary>
|
||||
/// 是否打开软件时更新订阅
|
||||
/// </summary>
|
||||
public bool UpdateServersWhenOpened = false;
|
||||
public bool UpdateServersWhenOpened { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 使用代理更新订阅
|
||||
/// </summary>
|
||||
public bool UseProxyToUpdateSubscription = false;
|
||||
public bool UseProxyToUpdateSubscription { get; set; } = false;
|
||||
|
||||
public V2rayConfig V2RayConfig = new();
|
||||
public V2rayConfig V2RayConfig { get; set; } = new();
|
||||
|
||||
public bool? AlwaysStartPACServer { get; set; }
|
||||
|
||||
public Setting Clone()
|
||||
{
|
||||
|
||||
@@ -5,21 +5,21 @@
|
||||
/// <summary>
|
||||
/// 启用状态
|
||||
/// </summary>
|
||||
public bool Enable = true;
|
||||
public bool Enable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 链接
|
||||
/// </summary>
|
||||
public string Link;
|
||||
public string Link { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark;
|
||||
public string Remark { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User Agent
|
||||
/// </summary>
|
||||
public string UserAgent;
|
||||
public string UserAgent { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
30
Netch/Models/TapAdapter.cs
Normal file
30
Netch/Models/TapAdapter.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class TapAdapter : IAdapter
|
||||
{
|
||||
public TapAdapter()
|
||||
{
|
||||
Index = -1;
|
||||
ComponentID = TUNTAP.GetComponentID() ?? throw new MessageException("TAP 适配器未安装");
|
||||
|
||||
// 根据 ComponentID 寻找 Tap适配器
|
||||
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces().First(i => i.Id == ComponentID);
|
||||
Index = NetworkInterface.GetIPProperties().GetIPv4Properties().Index;
|
||||
Logging.Info($"TAP 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {Index}");
|
||||
}
|
||||
|
||||
public string ComponentID { get; }
|
||||
|
||||
public int Index { get; }
|
||||
|
||||
public IPAddress Gateway => IPAddress.Parse(Global.Settings.TUNTAP.Gateway);
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace Netch
|
||||
Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) + ";" + Path.Combine(Global.NetchDir, "bin"),
|
||||
EnvironmentVariableTarget.Process);
|
||||
|
||||
Updater.Updater.CleanOld();
|
||||
Updater.Updater.CleanOld(Global.NetchDir);
|
||||
|
||||
// 预创建目录
|
||||
var directories = new[] {"mode\\Custom", "data", "i18n", "logging"};
|
||||
@@ -39,15 +39,6 @@ namespace Netch
|
||||
// 加载配置
|
||||
Configuration.Load();
|
||||
|
||||
// 加载语言
|
||||
i18N.Load(Global.Settings.Language);
|
||||
|
||||
if (!Directory.Exists("bin") || !Directory.EnumerateFileSystemEntries("bin").Any())
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please extract all files then run the program!"));
|
||||
Environment.Exit(2);
|
||||
}
|
||||
|
||||
// 检查是否已经运行
|
||||
if (!Global.Mutex.WaitOne(0, false))
|
||||
{
|
||||
@@ -70,6 +61,15 @@ namespace Netch
|
||||
dir.Delete(true);
|
||||
}
|
||||
|
||||
// 加载语言
|
||||
i18N.Load(Global.Settings.Language);
|
||||
|
||||
if (!Directory.Exists("bin") || !Directory.EnumerateFileSystemEntries("bin").Any())
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please extract all files then run the program!"));
|
||||
Environment.Exit(2);
|
||||
}
|
||||
|
||||
Logging.Info($"版本: {UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
|
||||
Task.Run(() => { Logging.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}"); });
|
||||
Task.Run(() =>
|
||||
@@ -84,7 +84,7 @@ namespace Netch
|
||||
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(Global.MainForm = new MainForm());
|
||||
Application.Run(Global.MainForm);
|
||||
}
|
||||
|
||||
public static void Application_OnException(object sender, ThreadExceptionEventArgs e)
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<StartupObject>Netch.Netch</StartupObject>
|
||||
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||
<ApplicationIcon>Netch.ico</ApplicationIcon>
|
||||
<ApplicationIcon>Resources\Netch.ico</ApplicationIcon>
|
||||
<Platforms>x64</Platforms>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -40,14 +41,15 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.65" GeneratePathProperty="true" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.66" GeneratePathProperty="true" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.1" />
|
||||
<PackageReference Include="TaskScheduler" Version="2.9.1" />
|
||||
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.4" />
|
||||
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.5" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.5" />
|
||||
<PackageReference Include="WindowsFirewallHelper" Version="2.0.4.70-beta2" />
|
||||
<PackageReference Include="WindowsJobAPI" Version="5.0.1" />
|
||||
<PackageReference Include="WindowsProxy" Version="5.0.0" />
|
||||
@@ -73,10 +75,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\binaries\**" LinkBase="bin" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Visible="false" Include="..\binaries\**" LinkBase="bin" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Remove="..\binaries\.git" />
|
||||
<None Include="..\translations\i18n\**" LinkBase="i18n" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Include="..\modes\mode\**" LinkBase="mode" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Visible="false" Include="..\translations\i18n\**" LinkBase="i18n" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Visible="false" Include="..\modes\mode\**" LinkBase="mode" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -90,6 +92,9 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Forms\Mode\Route.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -97,6 +102,7 @@
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Remove="Forms\LogForm.resx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
30
Netch/Properties/Resources.Designer.cs
generated
30
Netch/Properties/Resources.Designer.cs
generated
@@ -60,6 +60,16 @@ namespace Netch.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] _7za {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("7za", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
@@ -110,6 +120,16 @@ namespace Netch.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||
/// </summary>
|
||||
internal static System.Drawing.Icon icon {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("icon", resourceCulture);
|
||||
return ((System.Drawing.Icon)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
@@ -149,15 +169,5 @@ namespace Netch.Properties {
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] _7za {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("7za", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,177 +1,164 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms"
|
||||
name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
|
||||
<data name="defaultTUNTAP" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\defaultTUNTAP;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</data>
|
||||
<data name="zh_CN" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\zh-CN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</data>
|
||||
<data name="speed" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\speed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="delete" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="Netch" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Netch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="Sponsor" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Sponsor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="CopyLink" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CopyLink.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\abp.js.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="7za" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\7za.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</data>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="defaultTUNTAP" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\defaultTUNTAP;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="zh_CN" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\zh-CN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="speed" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\speed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="delete" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Netch" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Netch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Sponsor" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Sponsor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="CopyLink" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CopyLink.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\abp.js.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="7za" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\7za.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="icon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Netch.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
|
Before Width: | Height: | Size: 285 KiB After Width: | Height: | Size: 285 KiB |
@@ -4,7 +4,6 @@
|
||||
"Error": "错误",
|
||||
|
||||
"If this is your first time using this software,\n please check https://netch.org to install supports first,\n or the program may report errors.": "如果你是第一次使用本软件,\n请务必前往 https://netch.org 安装程序所需依赖,\n否则程序将无法正常运行!",
|
||||
"Netch is already running": "Netch 已经在运行中",
|
||||
"Missing File or runtime components": "缺少文件或运行库",
|
||||
"Please extract all files then run the program!": "请先解压所有文件再执行程序!",
|
||||
|
||||
@@ -27,7 +26,6 @@
|
||||
|
||||
"Server": "服务器",
|
||||
"Import Servers From Clipboard": "从剪贴板导入服务器",
|
||||
"Import servers error!": "未找到可导入的链接!",
|
||||
"Add [{0}] Server": "添加 [{0}] 服务器",
|
||||
"Netch is now minimized to the notification bar, double click this icon to restore.": "Netch 已最小化至通知栏,双击此图标恢复窗口",
|
||||
"New version available": "发现新版本",
|
||||
@@ -41,6 +39,8 @@
|
||||
"Download update failed": "下载更新错误",
|
||||
"Create Process Mode": "创建进程模式",
|
||||
"Edit Process Mode": "修改进程模式",
|
||||
"Create Route Table Rule": "创建路由表规则",
|
||||
"Edit Route Table Rule": "修改路由表规则",
|
||||
|
||||
"Address": "地址",
|
||||
"Username": "用户名",
|
||||
@@ -72,11 +72,10 @@
|
||||
"Updating {0}": "正在更新 {0}",
|
||||
"Update {1} server(s) from {0}": "从 {0} 更新 {1} 个服务器",
|
||||
"Update servers error from {0}": "从 {0} 更新服务器失败",
|
||||
"Delete the corresponding group of items in the server list?": "是否删除订阅对应服务器?",
|
||||
"Confirm deletion?": "确认删除?",
|
||||
"DeleteServer": "删除订阅节点",
|
||||
"CopyLink": "复制链接",
|
||||
"Status": "状态",
|
||||
"Remark": "备注",
|
||||
"Link": "链接",
|
||||
"Unselect": "取消选择",
|
||||
|
||||
@@ -115,13 +114,9 @@
|
||||
"Please select a mode first": "请先选择一个模式",
|
||||
"Please enter a profile name first": "请先为该配置设置一个名称",
|
||||
"No saved profile here. Save a profile first by Ctrl+Click on the button": "当前按钮下没有保存配置,请先使用 CTRL + 左键 点击该按钮保存一个配置",
|
||||
"Remove this Profile?": "删除此配置?",
|
||||
"Profile Removed!": "配置已删除!",
|
||||
|
||||
"Used": "已使用",
|
||||
"Status": "状态",
|
||||
"Testing": "测试中",
|
||||
"Test done": "测试完成",
|
||||
|
||||
"Remark": "备注",
|
||||
"Filename": "文件名",
|
||||
@@ -141,15 +136,14 @@
|
||||
"File already exists.\n Please Change the filename": "文件名已存在,请修改文件名",
|
||||
"Please enter a mode filename": "请输入模式的文件名",
|
||||
|
||||
"Link": "链接",
|
||||
"Use Selected Server To Update Subscription": "使用选中的服务器更新订阅",
|
||||
"Proxy Rule IPs": "代理规则 IP",
|
||||
"Bypass Rule IPs": "绕过规则 IP",
|
||||
|
||||
"Delete": "删除",
|
||||
"CopyLink": "复制链接",
|
||||
"Delete or not ? Will clean up the corresponding group of items in the server list": "是否删除?将会清理服务器列表中对应组的项目",
|
||||
"Remark can not be empty": "备注不可为空",
|
||||
"Link can not be empty": "链接不可为空",
|
||||
"Link must start with http:// or https://": "链接必须以 http:// 或 https:// 开头",
|
||||
"Please fill in alterID": "请填写额外ID",
|
||||
|
||||
"Settings": "设置",
|
||||
"Start when opened": "打开软件时启动加速",
|
||||
@@ -160,35 +154,24 @@
|
||||
"Netmask": "子网掩码",
|
||||
"Gateway": "网关",
|
||||
"Use Custom DNS": "使用自定义 DNS",
|
||||
"Proxy DNS in Mode 2": "在模式 2 下代理 DNS",
|
||||
"Proxy DNS in Proxy Rule IPs Mode": "在 代理规则IP 模式下代理 DNS",
|
||||
"Use Fake DNS": "使用 Fake DNS",
|
||||
"Behavior": "行为",
|
||||
"Exit when closed": "关闭时退出",
|
||||
"Stop when exited": "退出时停止",
|
||||
"Global Bypass IPs": "全局直连 IP",
|
||||
"Port value illegal. Try again.": "端口值非法。请重试",
|
||||
"Check update when opened": "打开软件时检查更新",
|
||||
"Check Beta update": "检查 Beta 更新",
|
||||
"Update Servers when opened": "打开软件时更新服务器",
|
||||
"SS DLL": "SS DLL",
|
||||
"Modify System DNS": "修改系统 DNS",
|
||||
"No Proxy for Udp": "不代理 UDP 流量",
|
||||
"No Proxy for Tcp": "不代理 TCP 流量",
|
||||
"Proxy Protocol": "代理协议",
|
||||
"ProfileCount": "快捷配置数量",
|
||||
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试",
|
||||
"STUN_ServerPort value illegal. Try again.": "STUN 端口数值非法。请重试",
|
||||
"Detection interval value illegal. Try again.": "检测间隔值非法。请重试",
|
||||
"TUN/TAP driver is not detected. Is it installed now?": "未检测到 TUN/TAP 驱动,是否现在安装?",
|
||||
"Failed to set the system proxy, it may be caused by the lack of dependent programs. Do you want to jump to Netch's official website to download dependent programs?": "设置系统代理失败,可能是缺少依赖导致,是否跳转 Netch 官网下载依赖程序?",
|
||||
"Delay test after start": "启动后延迟测试",
|
||||
"Enable": "启用",
|
||||
"ServerPingType": "测速方式",
|
||||
"Detection interval(sec)": "检测间隔(秒)",
|
||||
"Detection Tick(sec)": "检测心跳(秒)",
|
||||
"STUN Server": "STUN 服务器",
|
||||
"STUN Server Port": "STUN 服务器端口",
|
||||
"Custom ACL": "自定义 ACL 规则",
|
||||
"Language": "语言",
|
||||
"Tap Network Sharing": "Tap 网络共享",
|
||||
"Resolve Server Hostname": "解析服务器主机名",
|
||||
"FullCone Support (Required Server Xray-core v1.3.0+)": "FullCone 支持(需服务端 Xray-core v1.3.0+)",
|
||||
|
||||
@@ -198,7 +181,6 @@
|
||||
|
||||
"Show": "显示",
|
||||
"Exit": "退出",
|
||||
"Unable to start? Click me to download": "无法启动?点我下载依赖",
|
||||
|
||||
"The {0} port is in use.": "{0} 端口已被占用",
|
||||
"The {0} port is reserved by system.": "{0} 端口是系统保留端口",
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Netch.Servers.Shadowsocks.Form
|
||||
{
|
||||
public class ShadowsocksForm : ServerForm
|
||||
{
|
||||
public ShadowsocksForm(Shadowsocks server = default)
|
||||
public ShadowsocksForm(Shadowsocks? server = default)
|
||||
{
|
||||
server ??= new Shadowsocks();
|
||||
Server = server;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
#nullable disable
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks.Models.SSD
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
namespace Netch.Servers.Shadowsocks.Models.SSD
|
||||
#nullable disable
|
||||
namespace Netch.Servers.Shadowsocks.Models.SSD
|
||||
{
|
||||
public class SSDServer
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#nullable disable
|
||||
namespace Netch.Servers.Shadowsocks.Models
|
||||
{
|
||||
public class ShadowsocksConfig
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
{
|
||||
@@ -67,7 +67,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
argument.Append($" --plugin {server.Plugin}" + $" --plugin-opts \"{server.PluginOption}\"");
|
||||
|
||||
if (mode.BypassChina)
|
||||
argument.Append($" --acl {Path.GetFullPath(File.Exists(Global.UserACL) ? Global.UserACL : Global.BuiltinACL)}");
|
||||
argument.Append($" --acl \"{Path.GetFullPath(File.Exists(Global.UserACL) ? Global.UserACL : Global.BuiltinACL)}\"");
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Controllers;
|
||||
@@ -8,8 +9,6 @@ using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks.Form;
|
||||
using Netch.Servers.Shadowsocks.Models.SSD;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
@@ -25,10 +24,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public string[] UriScheme { get; } = {"ss", "ssd"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
{
|
||||
return j.ToObject<Shadowsocks>();
|
||||
}
|
||||
public Type ServerType { get; } = typeof(Shadowsocks);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
@@ -61,7 +57,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
if (text.StartsWith("ssd://"))
|
||||
return ParseSsdUri(text);
|
||||
|
||||
return null;
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
@@ -80,7 +76,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public IEnumerable<Server> ParseSsdUri(string s)
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)));
|
||||
var json = JsonSerializer.Deserialize<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)))!;
|
||||
|
||||
return json.servers.Select(server => new Shadowsocks
|
||||
{
|
||||
@@ -102,93 +98,82 @@ namespace Netch.Servers.Shadowsocks
|
||||
var data = new Shadowsocks();
|
||||
|
||||
text = text.Replace("/?", "?");
|
||||
try
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
}
|
||||
|
||||
if (text.Contains("?"))
|
||||
{
|
||||
var finder = new Regex(@"^(?<data>.+?)\?(.+)$");
|
||||
var match = finder.Match(text);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
var plugins = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("plugin"));
|
||||
if (plugins != null)
|
||||
{
|
||||
var plugin = plugins.Substring(0, plugins.IndexOf(";", StringComparison.Ordinal));
|
||||
var pluginopts = plugins.Substring(plugins.IndexOf(";", StringComparison.Ordinal) + 1);
|
||||
switch (plugin)
|
||||
{
|
||||
case "obfs-local":
|
||||
case "simple-obfs":
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=http;obfs-host=" + pluginopts;
|
||||
|
||||
break;
|
||||
case "simple-obfs-tls":
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=tls;obfs-host=" + pluginopts;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
data.Plugin = plugin;
|
||||
data.PluginOption = pluginopts;
|
||||
}
|
||||
|
||||
text = match.Groups["data"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
|
||||
if (text.Contains("@"))
|
||||
{
|
||||
var finder = new Regex(@"^ss://(?<base64>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var parser = new Regex(@"^(?<method>.+?):(?<password>.+)$");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
|
||||
var base64 = ShareLink.URLSafeBase64Decode(match.Groups["base64"].Value);
|
||||
match = parser.Match(base64);
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
data.Password = match.Groups["password"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var parser = new Regex(@"^((?<method>.+?):(?<password>.+)@(?<server>.+):(?<port>\d+))");
|
||||
var match = parser.Match(ShareLink.URLSafeBase64Decode(text.Replace("ss://", "")));
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
data.Password = match.Groups["password"].Value;
|
||||
}
|
||||
|
||||
return CheckServer(data) ? data : null;
|
||||
data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
}
|
||||
catch (FormatException)
|
||||
|
||||
if (text.Contains("?"))
|
||||
{
|
||||
return null;
|
||||
var finder = new Regex(@"^(?<data>.+?)\?(.+)$");
|
||||
var match = finder.Match(text);
|
||||
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
var plugins = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("plugin"));
|
||||
if (plugins != null)
|
||||
{
|
||||
var plugin = plugins.Substring(0, plugins.IndexOf(";", StringComparison.Ordinal));
|
||||
var pluginopts = plugins.Substring(plugins.IndexOf(";", StringComparison.Ordinal) + 1);
|
||||
switch (plugin)
|
||||
{
|
||||
case "obfs-local":
|
||||
case "simple-obfs":
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=http;obfs-host=" + pluginopts;
|
||||
|
||||
break;
|
||||
case "simple-obfs-tls":
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=tls;obfs-host=" + pluginopts;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
data.Plugin = plugin;
|
||||
data.PluginOption = pluginopts;
|
||||
}
|
||||
|
||||
text = match.Groups["data"].Value;
|
||||
}
|
||||
|
||||
if (text.Contains("@"))
|
||||
{
|
||||
var finder = new Regex(@"^ss://(?<base64>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var parser = new Regex(@"^(?<method>.+?):(?<password>.+)$");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
|
||||
var base64 = ShareLink.URLSafeBase64Decode(match.Groups["base64"].Value);
|
||||
match = parser.Match(base64);
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
data.Password = match.Groups["password"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var parser = new Regex(@"^((?<method>.+?):(?<password>.+)@(?<server>.+):(?<port>\d+))");
|
||||
var match = parser.Match(ShareLink.URLSafeBase64Decode(text.Replace("ss://", "")));
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
data.Password = match.Groups["password"].Value;
|
||||
}
|
||||
|
||||
return CheckServer(data) ? data : throw new FormatException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
public class Shadowsocks : Server
|
||||
{
|
||||
public Shadowsocks()
|
||||
{
|
||||
Type = "SS";
|
||||
}
|
||||
public override string Type { get; } = "SS";
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
@@ -18,17 +15,17 @@ namespace Netch.Servers.Shadowsocks
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
public string? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 插件
|
||||
/// </summary>
|
||||
public string Plugin { get; set; }
|
||||
public string? Plugin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 插件参数
|
||||
/// </summary>
|
||||
public string PluginOption { get; set; }
|
||||
public string? PluginOption { get; set; }
|
||||
|
||||
public bool HasPlugin()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Netch.Servers.ShadowsocksR.Form
|
||||
{
|
||||
public class ShadowsocksRForm : ServerForm
|
||||
{
|
||||
public ShadowsocksRForm(ShadowsocksR server = default)
|
||||
public ShadowsocksRForm(ShadowsocksR? server = default)
|
||||
{
|
||||
server ??= new ShadowsocksR();
|
||||
Server = server;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
{
|
||||
@@ -44,7 +44,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
argument.Append($" -b {this.LocalAddress()} -l {this.Socks5LocalPort()} -u");
|
||||
if (mode.BypassChina)
|
||||
argument.Append($" --acl {Path.GetFullPath(File.Exists(Global.UserACL) ? Global.UserACL : Global.BuiltinACL)}");
|
||||
argument.Append($" --acl \"{Path.GetFullPath(File.Exists(Global.UserACL) ? Global.UserACL : Global.BuiltinACL)}\"");
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.ShadowsocksR.Form;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
@@ -22,10 +21,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public string[] UriScheme { get; } = {"ssr"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
{
|
||||
return j.ToObject<ShadowsocksR>();
|
||||
}
|
||||
public Type ServerType { get; } = typeof(ShadowsocksR);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
|
||||
@@ -5,10 +5,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
public class ShadowsocksR : Server
|
||||
{
|
||||
public ShadowsocksR()
|
||||
{
|
||||
Type = "SSR";
|
||||
}
|
||||
public override string Type { get; } = "SSR";
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
@@ -23,12 +20,12 @@ namespace Netch.Servers.ShadowsocksR
|
||||
/// <summary>
|
||||
/// 混淆参数
|
||||
/// </summary>
|
||||
public string OBFSParam { get; set; }
|
||||
public string? OBFSParam { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 协议
|
||||
@@ -38,7 +35,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
/// <summary>
|
||||
/// 协议参数
|
||||
/// </summary>
|
||||
public string ProtocolParam { get; set; }
|
||||
public string? ProtocolParam { get; set; }
|
||||
}
|
||||
|
||||
public class SSRGlobal
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Netch.Servers.Socks5.Form
|
||||
{
|
||||
public class Socks5Form : ServerForm
|
||||
{
|
||||
public Socks5Form(Socks5 server = default)
|
||||
public Socks5Form(Socks5? server = default)
|
||||
{
|
||||
server ??= new Socks5();
|
||||
Server = server;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5.Form;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Servers.Socks5
|
||||
{
|
||||
@@ -19,10 +19,7 @@ namespace Netch.Servers.Socks5
|
||||
|
||||
public string[] UriScheme { get; } = { };
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
{
|
||||
return j.ToObject<Socks5>();
|
||||
}
|
||||
public Type ServerType { get; } = typeof(Socks5);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
@@ -57,7 +54,7 @@ namespace Netch.Servers.Socks5
|
||||
.ToDictionary(splited => splited[0], splited => splited[1]);
|
||||
|
||||
if (!dict.ContainsKey("server") || !dict.ContainsKey("port"))
|
||||
return null;
|
||||
throw new FormatException();
|
||||
|
||||
var data = new Socks5
|
||||
{
|
||||
|
||||
@@ -7,17 +7,14 @@ namespace Netch.Servers.Socks5
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password;
|
||||
public string? Password;
|
||||
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
public string Username;
|
||||
public string? Username;
|
||||
|
||||
public Socks5()
|
||||
{
|
||||
Type = "Socks5";
|
||||
}
|
||||
public override string Type { get; } = "Socks5";
|
||||
|
||||
public bool Auth()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Netch.Servers.Trojan.Form
|
||||
{
|
||||
public class TrojanForm : ServerForm
|
||||
{
|
||||
public TrojanForm(Trojan server = default)
|
||||
public TrojanForm(Trojan? server = default)
|
||||
{
|
||||
server ??= new Trojan();
|
||||
Server = server;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
#nullable disable
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.Trojan.Models
|
||||
{
|
||||
@@ -7,67 +8,81 @@ namespace Netch.Servers.Trojan.Models
|
||||
/// <summary>
|
||||
/// 监听地址
|
||||
/// </summary>
|
||||
public string local_addr = "127.0.0.1";
|
||||
public string local_addr { get; set; } = "127.0.0.1";
|
||||
|
||||
/// <summary>
|
||||
/// 监听端口
|
||||
/// </summary>
|
||||
public int local_port = 2801;
|
||||
public int local_port { get; set; } = 2801;
|
||||
|
||||
/// <summary>
|
||||
/// 日志级别
|
||||
/// </summary>
|
||||
public int log_level = 1;
|
||||
public int log_level { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public List<string> password;
|
||||
public List<string> password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 远端地址
|
||||
/// </summary>
|
||||
public string remote_addr;
|
||||
public string remote_addr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 远端端口
|
||||
/// </summary>
|
||||
public int remote_port;
|
||||
public int remote_port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启动类型
|
||||
/// </summary>
|
||||
public string run_type = "client";
|
||||
public string run_type { get; set; } = "client";
|
||||
|
||||
public TrojanSSL ssl = new();
|
||||
public TrojanTCP tcp = new();
|
||||
public TrojanSSL ssl { get; set; } = new();
|
||||
|
||||
public TrojanTCP tcp { get; set; } = new();
|
||||
}
|
||||
|
||||
public class TrojanSSL
|
||||
{
|
||||
public List<string> alpn = new()
|
||||
public List<string> alpn { get; set; } = new()
|
||||
{
|
||||
"h2",
|
||||
"http/1.1"
|
||||
};
|
||||
public string cert;
|
||||
public string cipher =
|
||||
"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA";
|
||||
public string cipher_tls13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384";
|
||||
public string curves = "";
|
||||
|
||||
public bool reuse_session = true;
|
||||
public bool session_ticket = true;
|
||||
public string sni = string.Empty;
|
||||
public bool verify = false;
|
||||
public bool verify_hostname = false;
|
||||
public string cert { get; set; }
|
||||
|
||||
public string cipher { get; set; } =
|
||||
"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA";
|
||||
|
||||
public string cipher_tls13 { get; set; } = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384";
|
||||
|
||||
public string curves { get; set; } = string.Empty;
|
||||
|
||||
public bool reuse_session { get; set; } = true;
|
||||
|
||||
public bool session_ticket { get; set; } = true;
|
||||
|
||||
public string sni { get; set; } = string.Empty;
|
||||
|
||||
public bool verify { get; set; } = false;
|
||||
|
||||
public bool verify_hostname { get; set; } = false;
|
||||
}
|
||||
|
||||
public class TrojanTCP
|
||||
{
|
||||
public bool fast_open = true;
|
||||
public int fast_open_qlen = 20;
|
||||
public bool keep_alive = true;
|
||||
public bool no_delay = false;
|
||||
public bool reuse_port = false;
|
||||
public bool fast_open { get; set; } = true;
|
||||
|
||||
public int fast_open_qlen { get; set; } = 20;
|
||||
|
||||
public bool keep_alive { get; set; } = true;
|
||||
|
||||
public bool no_delay { get; set; } = false;
|
||||
|
||||
public bool reuse_port { get; set; } = false;
|
||||
}
|
||||
}
|
||||
@@ -4,19 +4,16 @@ namespace Netch.Servers.Trojan
|
||||
{
|
||||
public class Trojan : Server
|
||||
{
|
||||
public Trojan()
|
||||
{
|
||||
Type = "Trojan";
|
||||
}
|
||||
public override string Type { get; } = "Trojan";
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名
|
||||
/// </summary>
|
||||
public string Host { get; set; }
|
||||
public string? Host { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Trojan.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Netch.Servers.Trojan
|
||||
{
|
||||
@@ -19,7 +19,7 @@ namespace Netch.Servers.Trojan
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
{
|
||||
@@ -39,13 +39,7 @@ namespace Netch.Servers.Trojan
|
||||
if (!string.IsNullOrWhiteSpace(server.Host))
|
||||
trojanConfig.ssl.sni = server.Host;
|
||||
|
||||
File.WriteAllText("data\\last.json",
|
||||
JsonConvert.SerializeObject(trojanConfig,
|
||||
Formatting.Indented,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
}));
|
||||
File.WriteAllBytes("data\\last.json", JsonSerializer.SerializeToUtf8Bytes(trojanConfig, Global.NewDefaultJsonSerializerOptions));
|
||||
|
||||
StartInstanceAuto("-c ..\\data\\last.json");
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Web;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Trojan.Form;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Servers.Trojan
|
||||
{
|
||||
@@ -21,10 +20,7 @@ namespace Netch.Servers.Trojan
|
||||
|
||||
public string[] UriScheme { get; } = {"trojan"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
{
|
||||
return j.ToObject<Trojan>();
|
||||
}
|
||||
public Type ServerType { get; } = typeof(Trojan);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
@@ -52,49 +48,38 @@ namespace Netch.Servers.Trojan
|
||||
var data = new Trojan();
|
||||
|
||||
text = text.Replace("/?", "?");
|
||||
try
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
}
|
||||
data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
}
|
||||
|
||||
if (text.Contains("?"))
|
||||
{
|
||||
var reg = new Regex(@"^(?<data>.+?)\?(.+)$");
|
||||
var regmatch = reg.Match(text);
|
||||
if (text.Contains("?"))
|
||||
{
|
||||
var reg = new Regex(@"^(?<data>.+?)\?(.+)$");
|
||||
var regmatch = reg.Match(text);
|
||||
|
||||
if (regmatch.Success)
|
||||
{
|
||||
var peer = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("peer"));
|
||||
|
||||
if (peer != null)
|
||||
data.Host = peer;
|
||||
|
||||
text = regmatch.Groups["data"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
|
||||
var finder = new Regex(@"^trojan://(?<psk>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success)
|
||||
if (!regmatch.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.Password = match.Groups["psk"].Value;
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
var peer = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("peer"));
|
||||
|
||||
return new[] {data};
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return null;
|
||||
if (peer != null)
|
||||
data.Host = peer;
|
||||
|
||||
text = regmatch.Groups["data"].Value;
|
||||
}
|
||||
|
||||
var finder = new Regex(@"^trojan://(?<psk>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.Password = match.Groups["psk"].Value;
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
|
||||
return new[] {data};
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
#nullable disable
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.V2ray.Models
|
||||
{
|
||||
public class V2rayConfig
|
||||
{
|
||||
public List<Inbounds> inbounds { get; set; }
|
||||
public List<Inbounds> inbounds { get; } = new();
|
||||
|
||||
public List<Outbounds> outbounds { get; set; }
|
||||
public List<Outbounds> outbounds { get; } = new();
|
||||
|
||||
public Routing routing { get; set; }
|
||||
public Routing routing { get; } = new();
|
||||
}
|
||||
|
||||
public class Inbounds
|
||||
@@ -160,7 +161,7 @@ namespace Netch.Servers.V2ray.Models
|
||||
{
|
||||
public string domainStrategy { get; set; }
|
||||
|
||||
public List<RulesItem> rules { get; set; }
|
||||
public List<RulesItem> rules { get; } = new();
|
||||
}
|
||||
|
||||
public class StreamSettings
|
||||
@@ -207,24 +208,26 @@ namespace Netch.Servers.V2ray.Models
|
||||
|
||||
public class TCPRequest
|
||||
{
|
||||
public TCPRequestHeaders headers;
|
||||
public TCPRequestHeaders headers { get; set; }
|
||||
|
||||
public string method = "GET";
|
||||
public string method { get; set; } = "GET";
|
||||
|
||||
public string path = "/";
|
||||
public string version = "1.1";
|
||||
public string path { get; set; } = "/";
|
||||
|
||||
public string version { get; set; } = "1.1";
|
||||
}
|
||||
|
||||
public class TCPRequestHeaders
|
||||
{
|
||||
//public string User_Agent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36";
|
||||
|
||||
public string Accept_Encoding = "gzip, deflate";
|
||||
public string Accept_Encoding { get; set; } = "gzip, deflate";
|
||||
|
||||
public string Connection = "keep-alive";
|
||||
public string Host;
|
||||
public string Connection { get; set; } = "keep-alive";
|
||||
|
||||
public string Pragma = "no-cache";
|
||||
public string Host { get; set; }
|
||||
|
||||
public string Pragma { get; set; } = "no-cache";
|
||||
}
|
||||
|
||||
public class KcpSettings
|
||||
|
||||
@@ -8,55 +8,56 @@
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public string add = string.Empty;
|
||||
public string add { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 额外 ID
|
||||
/// </summary>
|
||||
public string aid = string.Empty;
|
||||
public string aid { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名(HTTP,WS)
|
||||
/// </summary>
|
||||
public string host = string.Empty;
|
||||
public string? host { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 用户 ID
|
||||
/// </summary>
|
||||
public string id = string.Empty;
|
||||
public string id { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 传输协议
|
||||
/// </summary>
|
||||
public string net = string.Empty;
|
||||
public string net { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装路径
|
||||
/// </summary>
|
||||
public string path = string.Empty;
|
||||
public string? path { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public string port = string.Empty;
|
||||
public string port { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string ps = string.Empty;
|
||||
public string ps { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用 TLS
|
||||
/// </summary>
|
||||
public string tls = string.Empty;
|
||||
public string tls { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装类型
|
||||
/// </summary>
|
||||
public string type = string.Empty;
|
||||
public string type { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 链接版本
|
||||
/// </summary>
|
||||
public string v = string.Empty;
|
||||
public string v { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray.Models;
|
||||
using Newtonsoft.Json;
|
||||
using V2rayConfig = Netch.Servers.V2ray.Models.V2rayConfig;
|
||||
|
||||
namespace Netch.Servers.V2ray.Utils
|
||||
@@ -11,24 +11,15 @@ namespace Netch.Servers.V2ray.Utils
|
||||
{
|
||||
public static string GenerateClientConfig(Server server, Mode mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var v2rayConfig = new V2rayConfig();
|
||||
var v2rayConfig = new V2rayConfig();
|
||||
|
||||
inbound(server, ref v2rayConfig);
|
||||
inbound(server, ref v2rayConfig);
|
||||
|
||||
routing(server, mode, ref v2rayConfig);
|
||||
routing(server, mode, ref v2rayConfig);
|
||||
|
||||
outbound(server, mode, ref v2rayConfig);
|
||||
outbound(server, mode, ref v2rayConfig);
|
||||
|
||||
return JsonConvert.SerializeObject(v2rayConfig,
|
||||
Formatting.Indented,
|
||||
new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return JsonSerializer.Serialize(v2rayConfig, Global.NewDefaultJsonSerializerOptions);
|
||||
}
|
||||
|
||||
private static void inbound(Server server, ref V2rayConfig v2rayConfig)
|
||||
@@ -46,10 +37,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
}
|
||||
};
|
||||
|
||||
v2rayConfig.inbounds = new List<Inbounds>
|
||||
{
|
||||
inbound
|
||||
};
|
||||
v2rayConfig.inbounds.Add(inbound);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -99,18 +87,13 @@ namespace Netch.Servers.V2ray.Utils
|
||||
if (mode.Type is 0 or 1 or 2)
|
||||
blockRuleObject.ip.Add("geoip:private");
|
||||
|
||||
v2rayConfig.routing = new Routing
|
||||
{
|
||||
rules = new List<RulesItem>()
|
||||
};
|
||||
|
||||
static bool CheckRuleItem(ref RulesItem rulesItem)
|
||||
{
|
||||
bool ipResult, domainResult;
|
||||
if (!(ipResult = rulesItem.ip.Any()))
|
||||
if (!(ipResult = rulesItem.ip?.Any() ?? false))
|
||||
rulesItem.ip = null;
|
||||
|
||||
if (!(domainResult = rulesItem.domain.Any()))
|
||||
if (!(domainResult = rulesItem.domain?.Any() ?? false))
|
||||
rulesItem.domain = null;
|
||||
|
||||
return ipResult || domainResult;
|
||||
@@ -242,7 +225,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
}
|
||||
}
|
||||
|
||||
v2rayConfig.outbounds = new List<Outbounds>
|
||||
v2rayConfig.outbounds.AddRange(new[]
|
||||
{
|
||||
outbound,
|
||||
new()
|
||||
@@ -253,7 +236,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
{
|
||||
tag = "block", protocol = "blackhole"
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -321,7 +304,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
{
|
||||
host = new List<string>
|
||||
{
|
||||
string.IsNullOrWhiteSpace(server.Host) ? server.Hostname : server.Host
|
||||
string.IsNullOrWhiteSpace(server.Host) ? server.Hostname : server.Host!
|
||||
},
|
||||
path = server.Path
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Netch.Servers.V2ray
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
public virtual void Start(in Server s, in Mode mode)
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace Netch.Servers.V2ray
|
||||
{
|
||||
base.InitInstance(argument);
|
||||
if (!Global.Settings.V2RayConfig.XrayCone)
|
||||
Instance.StartInfo.Environment["XRAY_CONE_DISABLED"] = "true";
|
||||
Instance!.StartInfo.Environment["XRAY_CONE_DISABLED"] = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,77 +8,66 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.V2ray
|
||||
{
|
||||
internal static class V2rayUtils
|
||||
public static class V2rayUtils
|
||||
{
|
||||
public static IEnumerable<Server> ParseVUri(string text)
|
||||
{
|
||||
var scheme = ShareLink.GetUriScheme(text);
|
||||
try
|
||||
var scheme = ShareLink.GetUriScheme(text).ToLower();
|
||||
var server = scheme switch {"vmess" => new VMess.VMess(), "vless" => new VLESS.VLESS(), _ => throw new ArgumentOutOfRangeException()};
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
var server = new VMess.VMess();
|
||||
if (text.Contains("#"))
|
||||
server.Remark = Uri.UnescapeDataString(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
}
|
||||
|
||||
if (text.Contains("?"))
|
||||
{
|
||||
var parameter = HttpUtility.ParseQueryString(text.Split('?')[1]);
|
||||
text = text.Substring(0, text.IndexOf("?", StringComparison.Ordinal));
|
||||
server.TransferProtocol = parameter.Get("type") ?? "tcp";
|
||||
server.EncryptMethod = parameter.Get("encryption") ?? scheme switch {"vless" => "none", _ => "auto"};
|
||||
switch (server.TransferProtocol)
|
||||
{
|
||||
server.Remark = Uri.UnescapeDataString(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
case "tcp":
|
||||
break;
|
||||
case "kcp":
|
||||
server.FakeType = parameter.Get("headerType") ?? "none";
|
||||
server.Path = Uri.UnescapeDataString(parameter.Get("seed") ?? "");
|
||||
break;
|
||||
case "ws":
|
||||
server.Path = Uri.UnescapeDataString(parameter.Get("path") ?? "/");
|
||||
server.Host = Uri.UnescapeDataString(parameter.Get("host") ?? "");
|
||||
break;
|
||||
case "h2":
|
||||
server.Path = Uri.UnescapeDataString(parameter.Get("path") ?? "/");
|
||||
server.Host = Uri.UnescapeDataString(parameter.Get("host") ?? "");
|
||||
break;
|
||||
case "quic":
|
||||
server.QUICSecure = parameter.Get("quicSecurity") ?? "none";
|
||||
server.QUICSecret = parameter.Get("key") ?? "";
|
||||
server.FakeType = parameter.Get("headerType") ?? "none";
|
||||
break;
|
||||
}
|
||||
|
||||
if (text.Contains("?"))
|
||||
server.TLSSecureType = parameter.Get("security") ?? "none";
|
||||
if (server.TLSSecureType != "none")
|
||||
{
|
||||
var parameter = HttpUtility.ParseQueryString(text.Split('?')[1]);
|
||||
text = text.Substring(0, text.IndexOf("?", StringComparison.Ordinal));
|
||||
server.TransferProtocol = parameter.Get("type") ?? "tcp";
|
||||
server.EncryptMethod = parameter.Get("encryption") ?? scheme switch {"vless" => "none", _ => "auto"};
|
||||
switch (server.TransferProtocol)
|
||||
{
|
||||
case "tcp":
|
||||
break;
|
||||
case "kcp":
|
||||
server.FakeType = parameter.Get("headerType") ?? "none";
|
||||
server.Path = Uri.UnescapeDataString(parameter.Get("seed") ?? "");
|
||||
break;
|
||||
case "ws":
|
||||
server.Path = Uri.UnescapeDataString(parameter.Get("path") ?? "/");
|
||||
server.Host = Uri.UnescapeDataString(parameter.Get("host") ?? "");
|
||||
break;
|
||||
case "h2":
|
||||
server.Path = Uri.UnescapeDataString(parameter.Get("path") ?? "/");
|
||||
server.Host = Uri.UnescapeDataString(parameter.Get("host") ?? "");
|
||||
break;
|
||||
case "quic":
|
||||
server.QUICSecure = parameter.Get("quicSecurity") ?? "none";
|
||||
server.QUICSecret = parameter.Get("key") ?? "";
|
||||
server.FakeType = parameter.Get("headerType") ?? "none";
|
||||
break;
|
||||
}
|
||||
|
||||
server.TLSSecureType = parameter.Get("security") ?? "none";
|
||||
if (server.TLSSecureType != "none")
|
||||
{
|
||||
server.Host = parameter.Get("sni") ?? "";
|
||||
if (server.TLSSecureType == "xtls")
|
||||
((VLESS.VLESS) server).Flow = parameter.Get("flow") ?? "";
|
||||
}
|
||||
server.Host = parameter.Get("sni") ?? "";
|
||||
if (server.TLSSecureType == "xtls")
|
||||
((VLESS.VLESS) server).Flow = parameter.Get("flow") ?? "";
|
||||
}
|
||||
|
||||
var finder = new Regex(@$"^{scheme}://(?<guid>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var match = finder.Match(text.Split('?')[0]);
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
server.UserID = match.Groups["guid"].Value;
|
||||
server.Hostname = match.Groups["server"].Value;
|
||||
server.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
|
||||
return new[]
|
||||
{
|
||||
server
|
||||
};
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
return null;
|
||||
}
|
||||
|
||||
var finder = new Regex(@$"^{scheme}://(?<guid>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var match = finder.Match(text.Split('?')[0]);
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
server.UserID = match.Groups["guid"].Value;
|
||||
server.Hostname = match.Groups["server"].Value;
|
||||
server.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
|
||||
return new[] {server};
|
||||
}
|
||||
|
||||
public static string GetVShareLink(Server s, string scheme = "vmess")
|
||||
@@ -102,26 +91,27 @@ namespace Netch.Servers.V2ray
|
||||
parameter.Add("headerType", server.FakeType);
|
||||
|
||||
if (!server.Path.IsNullOrWhiteSpace())
|
||||
parameter.Add("seed", Uri.EscapeDataString(server.Path));
|
||||
parameter.Add("seed", Uri.EscapeDataString(server.Path!));
|
||||
|
||||
break;
|
||||
case "ws":
|
||||
parameter.Add("path", Uri.EscapeDataString(server.Path.IsNullOrWhiteSpace() ? "/" : server.Path));
|
||||
parameter.Add("path", Uri.EscapeDataString(server.Path.IsNullOrWhiteSpace() ? "/" : server.Path!));
|
||||
if (!server.Host.IsNullOrWhiteSpace())
|
||||
parameter.Add("host", Uri.EscapeDataString(server.Host));
|
||||
parameter.Add("host", Uri.EscapeDataString(server.Host!));
|
||||
|
||||
break;
|
||||
case "h2":
|
||||
parameter.Add("path", Uri.EscapeDataString(server.Path.IsNullOrWhiteSpace() ? "/" : server.Path));
|
||||
parameter.Add("path", Uri.EscapeDataString(server.Path.IsNullOrWhiteSpace() ? "/" : server.Path!));
|
||||
if (!server.Host.IsNullOrWhiteSpace())
|
||||
parameter.Add("host", Uri.EscapeDataString(server.Host));
|
||||
parameter.Add("host", Uri.EscapeDataString(server.Host!));
|
||||
|
||||
break;
|
||||
case "quic":
|
||||
if (server.QUICSecure != "none")
|
||||
if (server.QUICSecure is not (null or "none"))
|
||||
{
|
||||
parameter.Add("quicSecurity", server.QUICSecure);
|
||||
parameter.Add("key", server.QUICSecret);
|
||||
parameter.Add("key", server.QUICSecret!);
|
||||
// TODO Import and Create null value Check
|
||||
}
|
||||
|
||||
if (server.FakeType != "none")
|
||||
@@ -135,13 +125,13 @@ namespace Netch.Servers.V2ray
|
||||
parameter.Add("security", server.TLSSecureType);
|
||||
|
||||
if (!server.Host.IsNullOrWhiteSpace())
|
||||
parameter.Add("sni", server.Host);
|
||||
parameter.Add("sni", server.Host!);
|
||||
|
||||
if (server.TLSSecureType == "xtls")
|
||||
{
|
||||
var flow = ((VLESS.VLESS) server).Flow.Replace("-udp443", "");
|
||||
var flow = ((VLESS.VLESS) server).Flow;
|
||||
if (!flow.IsNullOrWhiteSpace())
|
||||
parameter.Add("flow", flow);
|
||||
parameter.Add("flow", flow!.Replace("-udp443", ""));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,7 @@ namespace Netch.Servers.VLESS
|
||||
{
|
||||
public class VLESS : VMess.VMess
|
||||
{
|
||||
public VLESS()
|
||||
{
|
||||
Type = "VLESS";
|
||||
}
|
||||
public override string Type { get; } = "VLESS";
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
@@ -27,7 +24,7 @@ namespace Netch.Servers.VLESS
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string Flow { get; set; }
|
||||
public string? Flow { get; set; }
|
||||
}
|
||||
|
||||
public class VLESSGlobal
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Netch.Servers.VLESS.VLESSForm
|
||||
{
|
||||
internal class VLESSForm : ServerForm
|
||||
{
|
||||
public VLESSForm(VLESS server = default)
|
||||
public VLESSForm(VLESS? server = default)
|
||||
{
|
||||
server ??= new VLESS();
|
||||
Server = server;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Servers.VLESS
|
||||
{
|
||||
@@ -18,10 +18,7 @@ namespace Netch.Servers.VLESS
|
||||
|
||||
public string[] UriScheme { get; } = {"vless"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
{
|
||||
return j.ToObject<VLESS>();
|
||||
}
|
||||
public Type ServerType { get; } = typeof(VLESS);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
@@ -50,7 +47,6 @@ namespace Netch.Servers.VLESS
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Netch.Servers.VMess.Form
|
||||
{
|
||||
public class VMessForm : ServerForm
|
||||
{
|
||||
public VMessForm(VMess server = default)
|
||||
public VMessForm(VMess? server = default)
|
||||
{
|
||||
server ??= new VMess();
|
||||
Server = server;
|
||||
|
||||
@@ -7,15 +7,12 @@ namespace Netch.Servers.VMess
|
||||
{
|
||||
private string _tlsSecureType = VMessGlobal.TLSSecure[0];
|
||||
|
||||
public VMess()
|
||||
{
|
||||
Type = "VMess";
|
||||
}
|
||||
public override string Type { get; } = "VMess";
|
||||
|
||||
/// <summary>
|
||||
/// 用户 ID
|
||||
/// </summary>
|
||||
public string UserID { get; set; }
|
||||
public string UserID { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 额外 ID
|
||||
@@ -40,22 +37,22 @@ namespace Netch.Servers.VMess
|
||||
/// <summary>
|
||||
/// 伪装域名
|
||||
/// </summary>
|
||||
public string Host { get; set; }
|
||||
public string? Host { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 传输路径
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
public string? Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// QUIC 加密方式
|
||||
/// </summary>
|
||||
public string QUICSecure { get; set; } = VMessGlobal.QUIC[0];
|
||||
public string? QUICSecure { get; set; } = VMessGlobal.QUIC[0];
|
||||
|
||||
/// <summary>
|
||||
/// QUIC 加密密钥
|
||||
/// </summary>
|
||||
public string QUICSecret { get; set; } = string.Empty;
|
||||
public string? QUICSecret { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// TLS 底层传输安全
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
using Netch.Servers.V2ray.Models;
|
||||
using Netch.Servers.VMess.Form;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Servers.VMess
|
||||
{
|
||||
@@ -22,19 +23,7 @@ namespace Netch.Servers.VMess
|
||||
|
||||
public string[] UriScheme { get; } = {"vmess"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
{
|
||||
// TODO Remove Migrate code
|
||||
var server = j.ToObject<VMess>();
|
||||
if (server == null)
|
||||
return null;
|
||||
|
||||
string quic;
|
||||
if ((quic = j.GetValue("QUIC")?.ToString()) != null)
|
||||
server.QUICSecure = quic;
|
||||
|
||||
return server;
|
||||
}
|
||||
public Type ServerType { get; } = typeof(VMess);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
@@ -52,20 +41,24 @@ namespace Netch.Servers.VMess
|
||||
{
|
||||
var server = (VMess) s;
|
||||
|
||||
var vmessJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
v = "2",
|
||||
ps = server.Remark,
|
||||
add = server.Hostname,
|
||||
port = server.Port,
|
||||
id = server.UserID,
|
||||
aid = server.AlterID,
|
||||
net = server.TransferProtocol,
|
||||
type = server.FakeType,
|
||||
host = server.Host,
|
||||
path = server.Path,
|
||||
tls = server.TLSSecureType
|
||||
});
|
||||
var vmessJson = JsonSerializer.Serialize(new V2rayNSharing
|
||||
{
|
||||
v = "2",
|
||||
ps = server.Remark,
|
||||
add = server.Hostname,
|
||||
port = server.Port.ToString(),
|
||||
id = server.UserID,
|
||||
aid = server.AlterID.ToString(),
|
||||
net = server.TransferProtocol,
|
||||
type = server.FakeType,
|
||||
host = server.Host,
|
||||
path = server.Path,
|
||||
tls = server.TLSSecureType
|
||||
},
|
||||
new JsonSerializerOptions
|
||||
{
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
});
|
||||
|
||||
return "vmess://" + ShareLink.URLSafeBase64Encode(vmessJson);
|
||||
}
|
||||
@@ -82,16 +75,18 @@ namespace Netch.Servers.VMess
|
||||
{
|
||||
var data = new VMess();
|
||||
|
||||
V2rayNSharing vmess;
|
||||
string s;
|
||||
try
|
||||
{
|
||||
vmess = JsonConvert.DeserializeObject<V2rayNSharing>(ShareLink.URLSafeBase64Decode(text.Substring(8)));
|
||||
s = ShareLink.URLSafeBase64Decode(text.Substring(8));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return V2rayUtils.ParseVUri(text);
|
||||
}
|
||||
|
||||
V2rayNSharing vmess = JsonSerializer.Deserialize<V2rayNSharing>(s)!;
|
||||
|
||||
data.Remark = vmess.ps;
|
||||
data.Hostname = vmess.add;
|
||||
data.Port = ushort.Parse(vmess.port);
|
||||
@@ -102,7 +97,7 @@ namespace Netch.Servers.VMess
|
||||
|
||||
if (data.TransferProtocol == "quic")
|
||||
{
|
||||
if (VMessGlobal.QUIC.Contains(vmess.host))
|
||||
if (VMessGlobal.QUIC.Contains(vmess.host!))
|
||||
{
|
||||
data.QUICSecure = vmess.host;
|
||||
data.QUICSecret = vmess.path;
|
||||
@@ -117,31 +112,11 @@ namespace Netch.Servers.VMess
|
||||
data.TLSSecureType = vmess.tls;
|
||||
data.EncryptMethod = "auto"; // V2Ray 加密方式不包括在链接中,主动添加一个
|
||||
|
||||
return CheckServer(data) ? new[] {data} : null;
|
||||
return new[] {data};
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (VMess) s;
|
||||
if (!VMessGlobal.TransferProtocols.Contains(server.TransferProtocol))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess 传输协议:{server.TransferProtocol}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (server.FakeType.Length != 0 && !VMessGlobal.FakeTypes.Contains(server.FakeType))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess 伪装类型:{server.FakeType}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (server.TransferProtocol == "quic")
|
||||
if (!VMessGlobal.QUIC.Contains(server.QUICSecure))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess QUIC 加密方式:{server.QUICSecure}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,28 +3,54 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Netch.Forms;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Controllers;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Updater
|
||||
{
|
||||
public static class Updater
|
||||
public class Updater
|
||||
{
|
||||
public static void UpdateNetch(string updateFilePath)
|
||||
{
|
||||
var tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
var extractPath = Path.Combine(tempFolder, "extract");
|
||||
int exitCode;
|
||||
if ((exitCode = Extract(updateFilePath, extractPath, true, tempFolder)) != 0)
|
||||
{
|
||||
MessageBoxX.Show($"7za exit with code {exitCode}");
|
||||
return;
|
||||
}
|
||||
private static IEnumerable<string> _keepDirectory = new List<string>(new[] {"data", "mode\\Custom"});
|
||||
private readonly string _targetPath;
|
||||
private readonly string _tempFolder;
|
||||
private readonly string _updateFilePath;
|
||||
|
||||
foreach (var file in Directory.GetFiles(Global.NetchDir, "*", SearchOption.AllDirectories))
|
||||
private Updater(string updateFilePath, string targetPath)
|
||||
{
|
||||
_targetPath = targetPath;
|
||||
_tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(_tempFolder);
|
||||
|
||||
_updateFilePath = Path.GetFullPath(updateFilePath);
|
||||
_keepDirectory = _keepDirectory.Select(s => Path.Combine(targetPath, s));
|
||||
}
|
||||
|
||||
private void ApplyUpdate()
|
||||
{
|
||||
var extractPath = Path.Combine(_tempFolder, "extract");
|
||||
int exitCode;
|
||||
if ((exitCode = Extract(extractPath, true)) != 0)
|
||||
throw new Exception(i18N.Translate($"7za exit with code {exitCode}"));
|
||||
|
||||
MarkFilesOld();
|
||||
|
||||
MoveAllFilesOver(Path.Combine(extractPath, "Netch"), _targetPath);
|
||||
|
||||
Configuration.Save();
|
||||
Global.Mutex.ReleaseMutex();
|
||||
Process.Start(Global.NetchExecutable);
|
||||
Global.MainForm.Exit(true, false);
|
||||
}
|
||||
|
||||
private void MarkFilesOld()
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(_targetPath, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
if (new[] {"data", "mode\\Custom"}.ToList().Any(p => file.StartsWith(Path.Combine(Global.NetchDir, p))))
|
||||
if (_keepDirectory.Any(p => file.StartsWith(p)))
|
||||
continue;
|
||||
|
||||
try
|
||||
@@ -36,31 +62,19 @@ namespace Netch.Updater
|
||||
throw new Exception("Updater wasn't able to rename file: " + file);
|
||||
}
|
||||
}
|
||||
|
||||
MoveDirectory(Path.Combine(extractPath, "Netch"), Global.NetchDir, true);
|
||||
|
||||
Global.Mutex.ReleaseMutex();
|
||||
Process.Start(Global.NetchExecutable);
|
||||
Global.MainForm.Exit(true);
|
||||
}
|
||||
|
||||
private static int Extract(string archiveFileName, string destDirName, bool overwrite, string tempFolder = null)
|
||||
private int Extract(string destDirName, bool overwrite)
|
||||
{
|
||||
tempFolder ??= Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
var temp7za = Path.Combine(tempFolder, "7za.exe");
|
||||
archiveFileName = Path.GetFullPath(archiveFileName);
|
||||
destDirName = Path.GetFullPath(destDirName);
|
||||
|
||||
if (!Directory.Exists(tempFolder))
|
||||
Directory.CreateDirectory(tempFolder);
|
||||
var temp7za = Path.Combine(_tempFolder, "7za.exe");
|
||||
|
||||
if (!File.Exists(temp7za))
|
||||
File.WriteAllBytes(temp7za, Resources._7za);
|
||||
|
||||
var argument = new StringBuilder();
|
||||
argument.Append($" x \"{archiveFileName}\" -o\"{destDirName}\" ");
|
||||
argument.Append($" x \"{_updateFilePath}\" -o\"{destDirName}\"");
|
||||
if (overwrite)
|
||||
argument.Append(" -y ");
|
||||
argument.Append(" -y");
|
||||
|
||||
var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
@@ -68,87 +82,35 @@ namespace Netch.Updater
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
FileName = temp7za,
|
||||
Arguments = argument.ToString()
|
||||
});
|
||||
})!;
|
||||
|
||||
process?.WaitForExit();
|
||||
return process?.ExitCode ?? 2;
|
||||
process.WaitForExit();
|
||||
return process.ExitCode;
|
||||
}
|
||||
|
||||
public static FileInfo FindFile(string filename, string directory)
|
||||
private static void MoveAllFilesOver(string source, string target)
|
||||
{
|
||||
var DirStack = new Stack<string>();
|
||||
DirStack.Push(directory);
|
||||
|
||||
while (DirStack.Count > 0)
|
||||
foreach (string directory in Directory.GetDirectories(source))
|
||||
{
|
||||
var DirInfo = new DirectoryInfo(DirStack.Pop());
|
||||
try
|
||||
{
|
||||
foreach (var DirChildInfo in DirInfo.GetDirectories())
|
||||
DirStack.Push(DirChildInfo.FullName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
string dirName = Path.GetFileName(directory);
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var FileChildInfo in DirInfo.GetFiles())
|
||||
if (FileChildInfo.Name == filename)
|
||||
return FileChildInfo;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
if (!Directory.Exists(Path.Combine(target, dirName)))
|
||||
Directory.CreateDirectory(Path.Combine(target, dirName));
|
||||
|
||||
MoveAllFilesOver(directory, Path.Combine(target, dirName));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void MoveDirectory(string sourceDirName, string destDirName, bool overwrite)
|
||||
{
|
||||
sourceDirName = Path.GetFullPath(sourceDirName);
|
||||
destDirName = Path.GetFullPath(destDirName);
|
||||
if (!overwrite)
|
||||
foreach (string file in Directory.GetFiles(source))
|
||||
{
|
||||
Directory.Move(sourceDirName, destDirName);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var dir in Directory.GetDirectories(sourceDirName, "*", SearchOption.AllDirectories))
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
foreach (var f in Directory.GetFiles(sourceDirName, "*", SearchOption.AllDirectories))
|
||||
try
|
||||
{
|
||||
File.Move(f, f.Replace(sourceDirName, destDirName));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new Exception("Updater wasn't able to move file: " + f);
|
||||
}
|
||||
var destFile = Path.Combine(target, Path.GetFileName(file));
|
||||
File.Delete(destFile);
|
||||
File.Move(file, destFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TestFileFree(string FileName)
|
||||
public static void CleanOld(string targetPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Move(FileName, FileName);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void CleanOld()
|
||||
{
|
||||
foreach (var f in Directory.GetFiles(Global.NetchDir, "*.old", SearchOption.AllDirectories))
|
||||
foreach (var f in Directory.GetFiles(targetPath, "*.old", SearchOption.AllDirectories))
|
||||
try
|
||||
{
|
||||
File.Delete(f);
|
||||
@@ -158,5 +120,41 @@ namespace Netch.Updater
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task DownloadAndUpdate(string downloadPath,
|
||||
string targetPath,
|
||||
DownloadProgressChangedEventHandler onDownloadProgressChanged)
|
||||
{
|
||||
var keyword = (string?) null;
|
||||
|
||||
if (!UpdateChecker.GetFileNameAndHashFromMarkdownForm(UpdateChecker.LatestRelease.body, out var fileName, out var sha256, keyword))
|
||||
throw new Exception(i18N.Translate("parse release note failed"));
|
||||
|
||||
var fileFullPath = Path.Combine(downloadPath, fileName);
|
||||
var updater = new Updater(fileFullPath, targetPath);
|
||||
|
||||
if (!(File.Exists(fileFullPath) && Utils.Utils.SHA256CheckSum(fileFullPath) == sha256))
|
||||
{
|
||||
using WebClient client = new();
|
||||
try
|
||||
{
|
||||
client.DownloadProgressChanged += onDownloadProgressChanged;
|
||||
await client.DownloadFileTaskAsync(new Uri(UpdateChecker.LatestRelease.assets[0].browser_download_url), fileFullPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(i18N.Translate("Download Update Failed", ": ") + e.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.DownloadProgressChanged -= onDownloadProgressChanged;
|
||||
}
|
||||
|
||||
if (Utils.Utils.SHA256CheckSum(fileFullPath) != sha256)
|
||||
throw new Exception(i18N.Translate("The downloaded file has the wrong hash"));
|
||||
}
|
||||
|
||||
updater.ApplyUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Netch.Utils
|
||||
public static class Bandwidth
|
||||
{
|
||||
public static ulong received;
|
||||
public static TraceEventSession tSession;
|
||||
public static TraceEventSession? tSession;
|
||||
|
||||
private static readonly string[] Suffix = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"};
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Netch.Utils
|
||||
{
|
||||
case null:
|
||||
break;
|
||||
case SSController ssController when ssController.DllFlag:
|
||||
case SSController {DllFlag: true}:
|
||||
instances.Add(Process.GetCurrentProcess());
|
||||
break;
|
||||
case Guard instanceController:
|
||||
@@ -73,13 +73,13 @@ namespace Netch.Utils
|
||||
case null:
|
||||
break;
|
||||
case HTTPController httpController:
|
||||
instances.Add(httpController.pPrivoxyController.Instance);
|
||||
instances.Add(httpController.PrivoxyController.Instance!);
|
||||
break;
|
||||
case NFController _:
|
||||
instances.Add(Process.GetCurrentProcess());
|
||||
break;
|
||||
case Guard instanceController:
|
||||
instances.Add(instanceController.Instance);
|
||||
instances.Add(instanceController.Instance!);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Netch.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -17,35 +18,22 @@ namespace Netch.Utils
|
||||
/// 设置
|
||||
/// </summary>
|
||||
public static readonly string SETTINGS_JSON = $"{DATA_DIR}\\settings.json";
|
||||
private static readonly JsonSerializerOptions JsonSerializerOptions = Global.NewDefaultJsonSerializerOptions;
|
||||
|
||||
static Configuration()
|
||||
{
|
||||
JsonSerializerOptions.Converters.Add(new ServerConverterWithTypeDiscriminator());
|
||||
JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
public static void Load()
|
||||
{
|
||||
if (Directory.Exists(DATA_DIR) && File.Exists(SETTINGS_JSON))
|
||||
if (File.Exists(SETTINGS_JSON))
|
||||
{
|
||||
try
|
||||
{
|
||||
var settingJObject = (JObject) JsonConvert.DeserializeObject(File.ReadAllText(SETTINGS_JSON));
|
||||
Global.Settings = settingJObject?.ToObject<Setting>() ?? new Setting();
|
||||
Global.Settings.Server.Clear();
|
||||
|
||||
if (settingJObject?["Server"] != null)
|
||||
foreach (JObject server in settingJObject["Server"])
|
||||
{
|
||||
var serverResult = ServerHelper.ParseJObject(server);
|
||||
if (serverResult != null)
|
||||
Global.Settings.Server.Add(serverResult);
|
||||
}
|
||||
|
||||
if (settingJObject?["Profiles"] != null && Global.Settings.Profiles.Any() && settingJObject["Profiles"].First()?["Index"] == null)
|
||||
foreach (var profile in Global.Settings.Profiles)
|
||||
profile.Index = Global.Settings.Profiles.IndexOf(profile);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
}
|
||||
Global.Settings = ParseSetting(File.ReadAllText(SETTINGS_JSON));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -57,6 +45,33 @@ namespace Netch.Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static Setting ParseSetting(string text)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = JsonSerializer.Deserialize<Setting>(text, JsonSerializerOptions)!;
|
||||
|
||||
#region Check Profile
|
||||
|
||||
settings.Profiles.RemoveAll(p => p.ServerRemark == string.Empty || p.ModeRemark == string.Empty);
|
||||
|
||||
if (settings.Profiles.Any(p => settings.Profiles.Any(p1 => p1 != p && p1.Index == p.Index)))
|
||||
for (var i = 0; i < settings.Profiles.Count; i++)
|
||||
settings.Profiles[i].Index = i;
|
||||
|
||||
#endregion
|
||||
|
||||
return settings;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
Utils.Open(Logging.LogFile);
|
||||
Environment.Exit(-1);
|
||||
return null!;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存配置
|
||||
/// </summary>
|
||||
@@ -65,13 +80,7 @@ namespace Netch.Utils
|
||||
if (!Directory.Exists(DATA_DIR))
|
||||
Directory.CreateDirectory(DATA_DIR);
|
||||
|
||||
File.WriteAllText(SETTINGS_JSON,
|
||||
JsonConvert.SerializeObject(Global.Settings,
|
||||
Formatting.Indented,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
}));
|
||||
File.WriteAllBytes(SETTINGS_JSON, JsonSerializer.SerializeToUtf8Bytes(Global.Settings, JsonSerializerOptions));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,44 +3,22 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class DNS
|
||||
public static class DnsUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存
|
||||
/// </summary>
|
||||
public static Hashtable Cache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 出口网卡 DNS
|
||||
/// <para></para>
|
||||
/// 依赖 <see cref="Global.Outbound.Adapter" />
|
||||
/// </summary>
|
||||
public static string OutboundDNS
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return (string) AdapterRegistry().GetValue("NameServer");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
set => AdapterRegistry(true).SetValue("NameServer", value, RegistryValueKind.String);
|
||||
}
|
||||
private static readonly Hashtable Cache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 查询
|
||||
/// </summary>
|
||||
/// <param name="hostname">主机名</param>
|
||||
/// <returns></returns>
|
||||
public static IPAddress Lookup(string hostname)
|
||||
public static IPAddress? Lookup(string hostname)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -64,18 +42,19 @@ namespace Netch.Utils
|
||||
}
|
||||
}
|
||||
|
||||
private static RegistryKey AdapterRegistry(bool write = false)
|
||||
/// <summary>
|
||||
/// 查询
|
||||
/// </summary>
|
||||
/// <param name="hostname">主机名</param>
|
||||
/// <returns></returns>
|
||||
public static void ClearCache()
|
||||
{
|
||||
if (Global.Outbound.Adapter == null)
|
||||
Utils.SearchOutboundAdapter();
|
||||
|
||||
return Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{Global.Outbound.Adapter.Id}",
|
||||
write);
|
||||
Cache.Clear();
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Split(string dns)
|
||||
{
|
||||
return dns.Split(',').Where(ip => !string.IsNullOrWhiteSpace(ip)).Select(ip => ip.Trim());
|
||||
return dns.SplitRemoveEmptyEntriesAndTrimEntries(',');
|
||||
}
|
||||
|
||||
public static bool TrySplit(string value, out IEnumerable<string> result, ushort maxCount = 0)
|
||||
@@ -9,17 +9,6 @@ namespace Netch.Utils
|
||||
public static class Firewall
|
||||
{
|
||||
private const string Netch = "Netch";
|
||||
private static readonly string[] ProgramPath =
|
||||
{
|
||||
"bin/NTT.exe",
|
||||
"bin/Privoxy.exe",
|
||||
"bin/Shadowsocks.exe",
|
||||
"bin/ShadowsocksR.exe",
|
||||
"bin/Trojan.exe",
|
||||
"bin/tun2socks.exe",
|
||||
"bin/xray.exe",
|
||||
"Netch.exe"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Netch 自带程序添加防火墙
|
||||
@@ -43,12 +32,8 @@ namespace Netch.Utils
|
||||
RemoveNetchFwRules();
|
||||
}
|
||||
|
||||
foreach (var p in ProgramPath)
|
||||
{
|
||||
var path = Path.GetFullPath(p);
|
||||
if (File.Exists(path))
|
||||
AddFwRule(Netch, path);
|
||||
}
|
||||
foreach (var path in Directory.GetFiles(Global.NetchDir, "*.exe", SearchOption.AllDirectories))
|
||||
AddFwRule(Netch, path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -66,7 +51,8 @@ namespace Netch.Utils
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var rule in FirewallManager.Instance.Rules.Where(r => r.Name == Netch))
|
||||
foreach (var rule in FirewallManager.Instance.Rules.Where(r
|
||||
=> r.ApplicationName?.StartsWith(Global.NetchDir, StringComparison.OrdinalIgnoreCase) ?? r.Name == Netch))
|
||||
FirewallManager.Instance.Rules.Remove(rule);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -1,86 +1,67 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
public class HttpWebServer
|
||||
{
|
||||
private HttpListener _listener;
|
||||
private readonly Func<HttpListenerRequest, string> _responderMethod;
|
||||
private readonly Func<HttpListenerRequest, string>? _responderMethod;
|
||||
private HttpListener? _listener;
|
||||
|
||||
public HttpWebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
|
||||
{
|
||||
try
|
||||
{
|
||||
_listener = new HttpListener();
|
||||
_listener = new HttpListener();
|
||||
|
||||
if (!HttpListener.IsSupported)
|
||||
throw new NotSupportedException("Needs Windows XP SP2, Server 2003 or later.");
|
||||
// URI prefixes are required, for example
|
||||
// "http://localhost:8080/index/".
|
||||
if (prefixes == null || prefixes.Length == 0)
|
||||
throw new ArgumentException("prefixes");
|
||||
|
||||
// URI prefixes are required, for example
|
||||
// "http://localhost:8080/index/".
|
||||
if (prefixes == null || prefixes.Length == 0)
|
||||
throw new ArgumentException("prefixes");
|
||||
// A responder method is required
|
||||
if (method == null)
|
||||
throw new ArgumentException("method");
|
||||
|
||||
// A responder method is required
|
||||
if (method == null)
|
||||
throw new ArgumentException("method");
|
||||
foreach (var s in prefixes)
|
||||
_listener.Prefixes.Add(s);
|
||||
|
||||
foreach (var s in prefixes)
|
||||
_listener.Prefixes.Add(s);
|
||||
|
||||
_responderMethod = method;
|
||||
_listener.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Error("HttpWebServer():" + ex.Message);
|
||||
}
|
||||
_responderMethod = method;
|
||||
_listener.Start();
|
||||
}
|
||||
|
||||
public HttpWebServer(Func<HttpListenerRequest, string> method, params string[] prefixes) : this(prefixes, method)
|
||||
{
|
||||
}
|
||||
|
||||
public void Run()
|
||||
public void StartWaitingRequest()
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(o =>
|
||||
Logging.Info("Webserver running...");
|
||||
while (_listener?.IsListening ?? false)
|
||||
{
|
||||
Logging.Info("Webserver running...");
|
||||
HttpListenerContext ctx;
|
||||
try
|
||||
{
|
||||
while (_listener.IsListening)
|
||||
ThreadPool.QueueUserWorkItem(c =>
|
||||
{
|
||||
var ctx = c as HttpListenerContext;
|
||||
try
|
||||
{
|
||||
var rstr = _responderMethod(ctx.Request);
|
||||
var buf = Encoding.UTF8.GetBytes(rstr);
|
||||
ctx.Response.StatusCode = 200;
|
||||
ctx.Response.ContentType = "application/x-ns-proxy-autoconfig";
|
||||
ctx.Response.ContentLength64 = buf.Length;
|
||||
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
} // suppress any exceptions
|
||||
finally
|
||||
{
|
||||
// always close the stream
|
||||
ctx.Response.OutputStream.Close();
|
||||
}
|
||||
},
|
||||
_listener.GetContext());
|
||||
ctx = _listener.GetContext();
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
//Logging.Error(ex.Message, ex);
|
||||
Logging.Error(ex.Message);
|
||||
} // suppress any exceptions
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var rstr = _responderMethod!(ctx.Request);
|
||||
var buf = Encoding.UTF8.GetBytes(rstr);
|
||||
ctx.Response.StatusCode = 200;
|
||||
ctx.Response.ContentType = "application/x-ns-proxy-autoconfig";
|
||||
ctx.Response.ContentLength64 = buf.Length;
|
||||
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ctx.Response.OutputStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
|
||||
@@ -1,111 +1,74 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using WindowsProxy;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Controllers;
|
||||
|
||||
namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 提供PAC功能支持
|
||||
/// </summary>
|
||||
internal class PACServerHandle
|
||||
internal static class PACServerHandle
|
||||
{
|
||||
private static readonly Hashtable httpWebServer = new();
|
||||
private static readonly Hashtable pacList = new();
|
||||
private static HttpWebServer? _httpWebServer;
|
||||
private static string? _pacContent;
|
||||
|
||||
public static void InitPACServer(string address)
|
||||
public static string InitPACServer(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!pacList.ContainsKey(address))
|
||||
pacList.Add(address, GetPacList(address));
|
||||
_pacContent = GetPacList(address);
|
||||
var prefixes = $"http://{address}:{Global.Settings.Pac_Port}/pac/";
|
||||
|
||||
var prefixes = string.Format("http://{0}:{1}/pac/", address, Global.Settings.Pac_Port);
|
||||
_httpWebServer = new HttpWebServer(SendResponse, prefixes);
|
||||
Task.Run(() => _httpWebServer.StartWaitingRequest());
|
||||
|
||||
var ws = new HttpWebServer(SendResponse, prefixes);
|
||||
ws.Run();
|
||||
|
||||
if (!httpWebServer.ContainsKey(address) && ws != null)
|
||||
httpWebServer.Add(address, ws);
|
||||
|
||||
Global.Settings.Pac_Url = GetPacUrl();
|
||||
|
||||
using var service = new ProxyService
|
||||
{
|
||||
AutoConfigUrl = Global.Settings.Pac_Url
|
||||
};
|
||||
|
||||
service.Pac();
|
||||
|
||||
Logging.Info(service.Set(service.Query()) + "");
|
||||
Logging.Info($"Webserver InitServer OK: {Global.Settings.Pac_Url}");
|
||||
var pacUrl = GetPacUrl();
|
||||
Logging.Info($"Webserver InitServer OK: {pacUrl}");
|
||||
return pacUrl;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
Logging.Error("Webserver InitServer " + ex.Message);
|
||||
Logging.Error("Webserver InitServer Failed");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public static string SendResponse(HttpListenerRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var arrAddress = request.UserHostAddress.Split(':');
|
||||
var address = "127.0.0.1";
|
||||
if (arrAddress.Length > 0)
|
||||
address = arrAddress[0];
|
||||
|
||||
return pacList[address].ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Error("Webserver SendResponse " + ex.Message);
|
||||
return ex.Message;
|
||||
}
|
||||
return _pacContent!;
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (httpWebServer == null)
|
||||
return;
|
||||
|
||||
foreach (var key in httpWebServer.Keys)
|
||||
{
|
||||
Logging.Info("Webserver Stop " + key);
|
||||
((HttpWebServer) httpWebServer[key]).Stop();
|
||||
}
|
||||
|
||||
httpWebServer.Clear();
|
||||
_httpWebServer?.Stop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
Logging.Error("Webserver Stop " + ex.Message);
|
||||
// ignored
|
||||
}
|
||||
|
||||
_httpWebServer = null;
|
||||
}
|
||||
|
||||
private static string GetPacList(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lstProxy = new List<string>();
|
||||
lstProxy.Add(string.Format("PROXY {0}:{1};", address, Global.Settings.HTTPLocalPort));
|
||||
var proxy = $"PROXY {address}:{Global.Settings.HTTPLocalPort};";
|
||||
var pacfile = Path.Combine(Global.NetchDir, "bin\\pac.txt");
|
||||
|
||||
var proxy = string.Join("", lstProxy.ToArray());
|
||||
var strPacfile = Path.Combine(Global.NetchDir, "bin\\pac.txt");
|
||||
|
||||
var pac = File.ReadAllText(strPacfile, Encoding.UTF8).Replace("__PROXY__", proxy);
|
||||
var pac = File.ReadAllText(pacfile, Encoding.UTF8).Replace("__PROXY__", proxy);
|
||||
return pac;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new MessageException("Pac file not found!");
|
||||
}
|
||||
|
||||
return "No pac content";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -114,9 +77,7 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
/// <returns></returns>
|
||||
public static string GetPacUrl()
|
||||
{
|
||||
var pacUrl = string.Format("http://127.0.0.1:{0}/pac/?t={1}", Global.Settings.Pac_Port, DateTime.Now.ToString("yyyyMMddHHmmssfff"));
|
||||
|
||||
return pacUrl;
|
||||
return $"http://127.0.0.1:{Global.Settings.Pac_Port}/pac/?t={DateTime.Now:yyyyMMddHHmmssfff}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,8 +39,15 @@ namespace Netch.Utils
|
||||
|
||||
private static void Write(string text, LogLevel logLevel)
|
||||
{
|
||||
var contents = $@"[{DateTime.Now}][{logLevel.ToString()}] {text}{Global.EOF}";
|
||||
if (Global.Testing)
|
||||
{
|
||||
Console.WriteLine(contents);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (FileLock)
|
||||
File.AppendAllText(LogFile, $@"[{DateTime.Now}][{logLevel.ToString()}] {text}{Global.EOF}");
|
||||
File.AppendAllText(LogFile, contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ namespace Netch.Utils
|
||||
|
||||
try
|
||||
{
|
||||
var splited = text.Substring(1).Split(',').Select(s => s.Trim()).ToArray();
|
||||
var splited = text.Substring(1).SplitTrimEntries(',');
|
||||
|
||||
mode.Remark = splited[0];
|
||||
|
||||
@@ -141,41 +141,36 @@ namespace Netch.Utils
|
||||
};
|
||||
}
|
||||
|
||||
public static IModeController GetModeControllerByType(int type, out ushort? port, out string portName, out PortType portType)
|
||||
public static IModeController? GetModeControllerByType(int type, out ushort? port, out string portName, out PortType portType)
|
||||
{
|
||||
IModeController modeController;
|
||||
port = null;
|
||||
portName = string.Empty;
|
||||
portType = PortType.Both;
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
modeController = new NFController();
|
||||
port = Global.Settings.RedirectorTCPPort;
|
||||
portName = "Redirector TCP";
|
||||
portType = PortType.TCP;
|
||||
break;
|
||||
return new NFController();
|
||||
case 1:
|
||||
case 2:
|
||||
modeController = new TUNTAPController();
|
||||
break;
|
||||
return new TUNTAPController();
|
||||
case 3:
|
||||
case 5:
|
||||
modeController = new HTTPController();
|
||||
port = Global.Settings.HTTPLocalPort;
|
||||
portName = "HTTP";
|
||||
portType = PortType.TCP;
|
||||
StatusPortInfoText.HttpPort = (ushort) port;
|
||||
break;
|
||||
return new HTTPController();
|
||||
case 4:
|
||||
modeController = null;
|
||||
break;
|
||||
return null;
|
||||
case 6:
|
||||
return new PcapController();
|
||||
default:
|
||||
Logging.Error("未知模式类型");
|
||||
throw new MessageException();
|
||||
throw new MessageException("未知模式类型");
|
||||
}
|
||||
|
||||
return modeController;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Netch.Utils
|
||||
Exit
|
||||
}
|
||||
|
||||
public static event EventHandler<Commands> Called;
|
||||
public static event EventHandler<Commands>? Called;
|
||||
|
||||
private static void OnCalled(Commands e)
|
||||
{
|
||||
@@ -62,7 +62,7 @@ namespace Netch.Utils
|
||||
{
|
||||
try
|
||||
{
|
||||
using var udpClient = new UdpClient(Global.Settings.UDPSocketPort);
|
||||
using var udpClient = new UdpClient(new IPEndPoint(IPAddress.Loopback, Global.Settings.UDPSocketPort));
|
||||
udpClient.Connect(IPAddress.Loopback, Global.Settings.UDPSocketPort);
|
||||
var sendBytes = Encoding.ASCII.GetBytes(command.ToString());
|
||||
await udpClient.SendAsync(sendBytes, sendBytes.Length);
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace Netch.Utils
|
||||
|
||||
private static void GetReservedPortRange(PortType portType, ref List<Range> targetList)
|
||||
{
|
||||
var lines = new List<string>();
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
@@ -41,32 +40,20 @@ namespace Netch.Utils
|
||||
}
|
||||
};
|
||||
|
||||
process.OutputDataReceived += (s, e) =>
|
||||
{
|
||||
if (e.Data != null)
|
||||
lines.Add(e.Data);
|
||||
};
|
||||
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.WaitForExit();
|
||||
var output = process.StandardOutput.ReadToEnd();
|
||||
|
||||
var splitLine = false;
|
||||
foreach (var line in lines)
|
||||
if (!splitLine)
|
||||
{
|
||||
if (line.StartsWith("-"))
|
||||
splitLine = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line == string.Empty)
|
||||
break;
|
||||
foreach (var line in output.SplitRemoveEmptyEntriesAndTrimEntries('\n'))
|
||||
{
|
||||
var value = line.Trim().SplitRemoveEmptyEntries(' ');
|
||||
if (value.Length != 2)
|
||||
continue;
|
||||
|
||||
var value = line.Trim().Split(' ').Where(s => s != string.Empty).ToArray();
|
||||
if (!ushort.TryParse(value[0], out var start) || !ushort.TryParse(value[1], out var end))
|
||||
continue;
|
||||
|
||||
targetList.Add(new Range(ushort.Parse(value[0]), ushort.Parse(value[1])));
|
||||
}
|
||||
targetList.Add(new Range(start, end));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user