Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Titanium-Web-Proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Titanium-Web-Proxy
Commits
e928c25a
Commit
e928c25a
authored
May 12, 2017
by
Jehonathan Thomas
Committed by
GitHub
May 12, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #215 from justcoding121/develop
Beta merge
parents
b62f9f14
e7b254f1
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
491 additions
and
375 deletions
+491
-375
Program.cs
Examples/Titanium.Web.Proxy.Examples.Basic/Program.cs
+4
-4
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+6
-4
README.md
README.md
+1
-1
CertificateManagerTests.cs
...s/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs
+1
-1
CertificateHandler.cs
Titanium.Web.Proxy/CertificateHandler.cs
+2
-2
ByteArrayExtensions.cs
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
+2
-2
Firefox.cs
Titanium.Web.Proxy/Helpers/Firefox.cs
+3
-3
Network.cs
Titanium.Web.Proxy/Helpers/Network.cs
+80
-42
EndPoint.cs
Titanium.Web.Proxy/Models/EndPoint.cs
+6
-6
ExternalProxy.cs
Titanium.Web.Proxy/Models/ExternalProxy.cs
+10
-5
BCCertificateMaker.cs
Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs
+4
-4
WinCertificateMaker.cs
...nium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs
+40
-40
CertificateManager.cs
Titanium.Web.Proxy/Network/CertificateManager.cs
+35
-11
ProxyClient.cs
Titanium.Web.Proxy/Network/ProxyClient.cs
+1
-1
TcpConnection.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
+1
-1
TcpConnectionFactory.cs
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+153
-152
TcpRow.cs
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
+7
-7
TcpTable.cs
Titanium.Web.Proxy/Network/Tcp/TcpTable.cs
+2
-2
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+122
-76
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+8
-8
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+3
-3
No files found.
Examples/Titanium.Web.Proxy.Examples.Basic/Program.cs
View file @
e928c25a
...
...
@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
public
class
Program
{
private
static
readonly
ProxyTestController
C
ontroller
=
new
ProxyTestController
();
private
static
readonly
ProxyTestController
c
ontroller
=
new
ProxyTestController
();
public
static
void
Main
(
string
[]
args
)
{
...
...
@@ -15,13 +15,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Start proxy controller
C
ontroller
.
StartProxy
();
c
ontroller
.
StartProxy
();
Console
.
WriteLine
(
"Hit any key to exit.."
);
Console
.
WriteLine
();
Console
.
Read
();
C
ontroller
.
Stop
();
c
ontroller
.
Stop
();
}
...
...
@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
if
(
eventType
!=
2
)
return
false
;
try
{
C
ontroller
.
Stop
();
c
ontroller
.
Stop
();
}
catch
{
...
...
Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
e928c25a
using
System
;
using
System.Collections.Generic
;
using
System.Net
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Models
;
...
...
@@ -9,10 +10,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
public
class
ProxyTestController
{
private
ProxyServer
proxyServer
;
private
readonly
ProxyServer
proxyServer
;
//share requestBody outside handlers
private
Dictionary
<
Guid
,
string
>
requestBodyHistory
;
private
readonly
Dictionary
<
Guid
,
string
>
requestBodyHistory
=
new
Dictionary
<
Guid
,
string
>()
;
public
ProxyTestController
()
{
...
...
@@ -21,9 +22,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
//optionally set the Certificate Engine
//Under Mono only BouncyCastle will be supported
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;
requestBodyHistory
=
new
Dictionary
<
Guid
,
string
>();
//optionally set the Root Certificate
//proxyServer.RootCertificate = new X509Certificate2("myCert.pfx", string.Empty, X509KeyStorageFlags.Exportable);
}
public
void
StartProxy
()
...
...
README.md
View file @
e928c25a
...
...
@@ -112,7 +112,7 @@ Sample request and response event handlers
```
csharp
//To access requestBody from OnResponse handler
private
Dictionary
<
Guid
,
string
>
requestBodyHistory
;
private
Dictionary
<
Guid
,
string
>
requestBodyHistory
=
new
Dictionary
<
Guid
,
string
>()
;
public
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
...
...
Tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs
View file @
e928c25a
...
...
@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.UnitTests
[
TestClass
]
public
class
CertificateManagerTests
{
private
readonly
static
string
[]
hostNames
private
static
readonly
string
[]
hostNames
=
new
string
[]
{
"facebook.com"
,
"youtube.com"
,
"google.com"
,
"bing.com"
,
"yahoo.com"
};
...
...
Titanium.Web.Proxy/CertificateHandler.cs
View file @
e928c25a
...
...
@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns></returns>
internal
bool
ValidateServerCertificate
(
private
bool
ValidateServerCertificate
(
object
sender
,
X509Certificate
certificate
,
X509Chain
chain
,
...
...
@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy
/// <param name="remoteCertificate"></param>
/// <param name="acceptableIssuers"></param>
/// <returns></returns>
internal
X509Certificate
SelectClientCertificate
(
private
X509Certificate
SelectClientCertificate
(
object
sender
,
string
targetHost
,
X509CertificateCollection
localCertificates
,
...
...
Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs
View file @
e928c25a
...
...
@@ -5,7 +5,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <summary>
/// Extension methods for Byte Arrays.
/// </summary>
public
static
class
ByteArrayExtensions
internal
static
class
ByteArrayExtensions
{
/// <summary>
/// Get the sub array from byte of data
...
...
@@ -15,7 +15,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="index"></param>
/// <param name="length"></param>
/// <returns></returns>
public
static
T
[]
SubArray
<
T
>(
this
T
[]
data
,
int
index
,
int
length
)
internal
static
T
[]
SubArray
<
T
>(
this
T
[]
data
,
int
index
,
int
length
)
{
var
result
=
new
T
[
length
];
Array
.
Copy
(
data
,
index
,
result
,
0
,
length
);
...
...
Titanium.Web.Proxy/Helpers/Firefox.cs
View file @
e928c25a
...
...
@@ -6,12 +6,12 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// A helper class to set proxy settings for firefox
/// </summary>
public
class
FireFoxProxySettingsManager
internal
class
FireFoxProxySettingsManager
{
/// <summary>
/// Add Firefox settings.
/// </summary>
public
void
AddFirefox
()
internal
void
AddFirefox
()
{
try
{
...
...
@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// Remove firefox settings.
/// </summary>
public
void
RemoveFirefox
()
internal
void
RemoveFirefox
()
{
try
{
...
...
Titanium.Web.Proxy/Helpers/Network.cs
View file @
e928c25a
using
System.Linq
;
using
System.Net
;
namespace
Titanium.Web.Proxy.Helpers
{
internal
class
NetworkHelper
{
private
static
int
FindProcessIdFromLocalPort
(
int
port
,
IpVersion
ipVersion
)
{
var
tcpRow
=
TcpHelper
.
GetExtendedTcpTable
(
ipVersion
).
FirstOrDefault
(
row
=>
row
.
LocalEndPoint
.
Port
==
port
);
return
tcpRow
?.
ProcessId
??
0
;
}
internal
static
int
GetProcessIdFromPort
(
int
port
,
bool
ipV6Enabled
)
{
var
processId
=
FindProcessIdFromLocalPort
(
port
,
IpVersion
.
Ipv4
);
if
(
processId
>
0
&&
!
ipV6Enabled
)
{
return
processId
;
}
return
FindProcessIdFromLocalPort
(
port
,
IpVersion
.
Ipv6
);
}
/// <summary>
/// Adapated from below link
/// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
internal
static
bool
IsLocalIpAddress
(
IPAddress
address
)
{
// get local IP addresses
var
localIPs
=
Dns
.
GetHostAddresses
(
Dns
.
GetHostName
());
// test if any host IP equals to any local IP or to localhost
return
IPAddress
.
IsLoopback
(
address
)
||
localIPs
.
Contains
(
address
);
}
}
}
using
System.Linq
;
using
System.Net
;
using
System.Net.Sockets
;
namespace
Titanium.Web.Proxy.Helpers
{
internal
class
NetworkHelper
{
private
static
int
FindProcessIdFromLocalPort
(
int
port
,
IpVersion
ipVersion
)
{
var
tcpRow
=
TcpHelper
.
GetExtendedTcpTable
(
ipVersion
).
FirstOrDefault
(
row
=>
row
.
LocalEndPoint
.
Port
==
port
);
return
tcpRow
?.
ProcessId
??
0
;
}
internal
static
int
GetProcessIdFromPort
(
int
port
,
bool
ipV6Enabled
)
{
var
processId
=
FindProcessIdFromLocalPort
(
port
,
IpVersion
.
Ipv4
);
if
(
processId
>
0
&&
!
ipV6Enabled
)
{
return
processId
;
}
return
FindProcessIdFromLocalPort
(
port
,
IpVersion
.
Ipv6
);
}
/// <summary>
/// Adapated from below link
/// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
internal
static
bool
IsLocalIpAddress
(
IPAddress
address
)
{
// get local IP addresses
var
localIPs
=
Dns
.
GetHostAddresses
(
Dns
.
GetHostName
());
// test if any host IP equals to any local IP or to localhost
return
IPAddress
.
IsLoopback
(
address
)
||
localIPs
.
Contains
(
address
);
}
internal
static
bool
IsLocalIpAddress
(
string
hostName
)
{
bool
isLocalhost
=
false
;
IPHostEntry
localhost
=
Dns
.
GetHostEntry
(
"127.0.0.1"
);
if
(
hostName
==
localhost
.
HostName
)
{
IPHostEntry
hostEntry
=
Dns
.
GetHostEntry
(
hostName
);
isLocalhost
=
hostEntry
.
AddressList
.
Any
(
IPAddress
.
IsLoopback
);
}
if
(!
isLocalhost
)
{
localhost
=
Dns
.
GetHostEntry
(
Dns
.
GetHostName
());
IPAddress
ipAddress
=
null
;
if
(
IPAddress
.
TryParse
(
hostName
,
out
ipAddress
))
isLocalhost
=
localhost
.
AddressList
.
Any
(
x
=>
x
.
Equals
(
ipAddress
));
if
(!
isLocalhost
)
{
try
{
var
hostEntry
=
Dns
.
GetHostEntry
(
hostName
);
isLocalhost
=
localhost
.
AddressList
.
Any
(
x
=>
hostEntry
.
AddressList
.
Any
(
x
.
Equals
));
}
catch
(
SocketException
)
{
}
}
}
return
isLocalhost
;
}
}
}
Titanium.Web.Proxy/Models/EndPoint.cs
View file @
e928c25a
...
...
@@ -53,8 +53,8 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
class
ExplicitProxyEndPoint
:
ProxyEndPoint
{
private
List
<
string
>
_
excludedHttpsHostNameRegex
;
private
List
<
string
>
_
includedHttpsHostNameRegex
;
private
List
<
string
>
excludedHttpsHostNameRegex
;
private
List
<
string
>
includedHttpsHostNameRegex
;
internal
bool
IsSystemHttpProxy
{
get
;
set
;
}
...
...
@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
List
<
string
>
ExcludedHttpsHostNameRegex
{
get
{
return
_
excludedHttpsHostNameRegex
;
}
get
{
return
excludedHttpsHostNameRegex
;
}
set
{
if
(
IncludedHttpsHostNameRegex
!=
null
)
...
...
@@ -73,7 +73,7 @@ namespace Titanium.Web.Proxy.Models
throw
new
ArgumentException
(
"Cannot set excluded when included is set"
);
}
_
excludedHttpsHostNameRegex
=
value
;
excludedHttpsHostNameRegex
=
value
;
}
}
...
...
@@ -82,7 +82,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
List
<
string
>
IncludedHttpsHostNameRegex
{
get
{
return
_
includedHttpsHostNameRegex
;
}
get
{
return
includedHttpsHostNameRegex
;
}
set
{
if
(
ExcludedHttpsHostNameRegex
!=
null
)
...
...
@@ -90,7 +90,7 @@ namespace Titanium.Web.Proxy.Models
throw
new
ArgumentException
(
"Cannot set included when excluded is set"
);
}
_
includedHttpsHostNameRegex
=
value
;
includedHttpsHostNameRegex
=
value
;
}
}
...
...
Titanium.Web.Proxy/Models/ExternalProxy.cs
View file @
e928c25a
...
...
@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
class
ExternalProxy
{
private
static
readonly
Lazy
<
NetworkCredential
>
D
efaultCredentials
=
new
Lazy
<
NetworkCredential
>(()
=>
CredentialCache
.
DefaultNetworkCredentials
);
private
static
readonly
Lazy
<
NetworkCredential
>
d
efaultCredentials
=
new
Lazy
<
NetworkCredential
>(()
=>
CredentialCache
.
DefaultNetworkCredentials
);
private
string
userName
;
private
string
password
;
...
...
@@ -18,16 +18,21 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
bool
UseDefaultCredentials
{
get
;
set
;
}
/// <summary>
/// Bypass this proxy for connections to localhost?
/// </summary>
public
bool
BypassForLocalhost
{
get
;
set
;
}
/// <summary>
/// Username.
/// </summary>
public
string
UserName
{
get
{
return
UseDefaultCredentials
?
D
efaultCredentials
.
Value
.
UserName
:
userName
;
}
get
{
return
UseDefaultCredentials
?
d
efaultCredentials
.
Value
.
UserName
:
userName
;
}
set
{
userName
=
value
;
if
(
D
efaultCredentials
.
Value
.
UserName
!=
userName
)
if
(
d
efaultCredentials
.
Value
.
UserName
!=
userName
)
{
UseDefaultCredentials
=
false
;
}
...
...
@@ -39,12 +44,12 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public
string
Password
{
get
{
return
UseDefaultCredentials
?
D
efaultCredentials
.
Value
.
Password
:
password
;
}
get
{
return
UseDefaultCredentials
?
d
efaultCredentials
.
Value
.
Password
:
password
;
}
set
{
password
=
value
;
if
(
D
efaultCredentials
.
Value
.
Password
!=
password
)
if
(
d
efaultCredentials
.
Value
.
Password
!=
password
)
{
UseDefaultCredentials
=
false
;
}
...
...
Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs
View file @
e928c25a
...
...
@@ -21,10 +21,10 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <summary>
/// Implements certificate generation operations.
/// </summary>
public
class
BCCertificateMaker
:
ICertificateMaker
internal
class
BCCertificateMaker
:
ICertificateMaker
{
private
const
int
C
ertificateValidDays
=
1825
;
private
const
int
C
ertificateGraceDays
=
366
;
private
const
int
c
ertificateValidDays
=
1825
;
private
const
int
c
ertificateGraceDays
=
366
;
/// <summary>
/// Makes the certificate.
...
...
@@ -187,7 +187,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
return
certificate
;
}
return
MakeCertificateInternal
(
isRoot
,
subject
,
$"CN=
{
subject
}
"
,
DateTime
.
UtcNow
.
AddDays
(-
CertificateGraceDays
),
DateTime
.
UtcNow
.
AddDays
(
C
ertificateValidDays
),
isRoot
?
null
:
signingCert
);
return
MakeCertificateInternal
(
isRoot
,
subject
,
$"CN=
{
subject
}
"
,
DateTime
.
UtcNow
.
AddDays
(-
certificateGraceDays
),
DateTime
.
UtcNow
.
AddDays
(
c
ertificateValidDays
),
isRoot
?
null
:
signingCert
);
}
}
...
...
Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs
View file @
e928c25a
...
...
@@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// Certificate Maker - uses MakeCert
/// Calls COM objects using reflection
/// </summary>
public
class
WinCertificateMaker
:
ICertificateMaker
internal
class
WinCertificateMaker
:
ICertificateMaker
{
private
readonly
Type
typeX500DN
;
...
...
@@ -42,12 +42,12 @@ namespace Titanium.Web.Proxy.Network.Certificate
private
readonly
string
sProviderName
=
"Microsoft Enhanced Cryptographic Provider v1.0"
;
private
object
_S
haredPrivateKey
;
private
object
s
haredPrivateKey
;
/// <summary>
/// Constructor.
/// </summary>
public
WinCertificateMaker
()
internal
WinCertificateMaker
()
{
typeX500DN
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX500DistinguishedName"
,
true
);
typeX509PrivateKey
=
Type
.
GetTypeFromProgID
(
"X509Enrollment.CX509PrivateKey"
,
true
);
...
...
@@ -105,7 +105,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
if
(!
isRoot
)
{
sharedPrivateKey
=
_S
haredPrivateKey
;
sharedPrivateKey
=
this
.
s
haredPrivateKey
;
}
if
(
sharedPrivateKey
==
null
)
...
...
@@ -130,52 +130,52 @@ namespace Titanium.Web.Proxy.Network.Certificate
if
(!
isRoot
)
{
_S
haredPrivateKey
=
sharedPrivateKey
;
this
.
s
haredPrivateKey
=
sharedPrivateKey
;
}
}
typeValue
=
new
object
[
1
];
var
OID
=
Activator
.
CreateInstance
(
typeOID
);
var
oid
=
Activator
.
CreateInstance
(
typeOID
);
typeValue
[
0
]
=
"1.3.6.1.5.5.7.3.1"
;
typeOID
.
InvokeMember
(
"InitializeFromValue"
,
BindingFlags
.
InvokeMethod
,
null
,
OID
,
typeValue
);
typeOID
.
InvokeMember
(
"InitializeFromValue"
,
BindingFlags
.
InvokeMethod
,
null
,
oid
,
typeValue
);
var
OIDS
=
Activator
.
CreateInstance
(
typeOIDS
);
typeValue
[
0
]
=
OID
;
typeOIDS
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
OIDS
,
typeValue
);
var
oids
=
Activator
.
CreateInstance
(
typeOIDS
);
typeValue
[
0
]
=
oid
;
typeOIDS
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
oids
,
typeValue
);
var
EKU
Ext
=
Activator
.
CreateInstance
(
typeEKUExt
);
typeValue
[
0
]
=
OIDS
;
typeEKUExt
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
EKU
Ext
,
typeValue
);
var
eku
Ext
=
Activator
.
CreateInstance
(
typeEKUExt
);
typeValue
[
0
]
=
oids
;
typeEKUExt
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
eku
Ext
,
typeValue
);
var
R
equestCert
=
Activator
.
CreateInstance
(
typeRequestCert
);
var
r
equestCert
=
Activator
.
CreateInstance
(
typeRequestCert
);
typeValue
=
new
[]
{
1
,
sharedPrivateKey
,
string
.
Empty
};
typeRequestCert
.
InvokeMember
(
"InitializeFromPrivateKey"
,
BindingFlags
.
InvokeMethod
,
null
,
R
equestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"InitializeFromPrivateKey"
,
BindingFlags
.
InvokeMethod
,
null
,
r
equestCert
,
typeValue
);
typeValue
=
new
[]
{
x500CertDN
};
typeRequestCert
.
InvokeMember
(
"Subject"
,
BindingFlags
.
PutDispProperty
,
null
,
R
equestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"Subject"
,
BindingFlags
.
PutDispProperty
,
null
,
r
equestCert
,
typeValue
);
typeValue
[
0
]
=
x500RootCertDN
;
typeRequestCert
.
InvokeMember
(
"Issuer"
,
BindingFlags
.
PutDispProperty
,
null
,
R
equestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"Issuer"
,
BindingFlags
.
PutDispProperty
,
null
,
r
equestCert
,
typeValue
);
typeValue
[
0
]
=
validFrom
;
typeRequestCert
.
InvokeMember
(
"NotBefore"
,
BindingFlags
.
PutDispProperty
,
null
,
R
equestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"NotBefore"
,
BindingFlags
.
PutDispProperty
,
null
,
r
equestCert
,
typeValue
);
typeValue
[
0
]
=
validTo
;
typeRequestCert
.
InvokeMember
(
"NotAfter"
,
BindingFlags
.
PutDispProperty
,
null
,
R
equestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"NotAfter"
,
BindingFlags
.
PutDispProperty
,
null
,
r
equestCert
,
typeValue
);
var
KU
Ext
=
Activator
.
CreateInstance
(
typeKUExt
);
var
ku
Ext
=
Activator
.
CreateInstance
(
typeKUExt
);
typeValue
[
0
]
=
176
;
typeKUExt
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
KU
Ext
,
typeValue
);
typeKUExt
.
InvokeMember
(
"InitializeEncode"
,
BindingFlags
.
InvokeMethod
,
null
,
ku
Ext
,
typeValue
);
var
certificate
=
typeRequestCert
.
InvokeMember
(
"X509Extensions"
,
BindingFlags
.
GetProperty
,
null
,
R
equestCert
,
null
);
var
certificate
=
typeRequestCert
.
InvokeMember
(
"X509Extensions"
,
BindingFlags
.
GetProperty
,
null
,
r
equestCert
,
null
);
typeValue
=
new
object
[
1
];
if
(!
isRoot
)
{
typeValue
[
0
]
=
KU
Ext
;
typeValue
[
0
]
=
ku
Ext
;
typeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
certificate
,
typeValue
);
}
typeValue
[
0
]
=
EKU
Ext
;
typeValue
[
0
]
=
eku
Ext
;
typeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
certificate
,
typeValue
);
if
(!
isRoot
)
...
...
@@ -203,12 +203,12 @@ namespace Titanium.Web.Proxy.Network.Certificate
if
(!
isRoot
)
{
var
S
ignerCertificate
=
Activator
.
CreateInstance
(
typeSignerCertificate
);
var
s
ignerCertificate
=
Activator
.
CreateInstance
(
typeSignerCertificate
);
typeValue
=
new
object
[]
{
0
,
0
,
12
,
signingCertificate
.
Thumbprint
};
typeSignerCertificate
.
InvokeMember
(
"Initialize"
,
BindingFlags
.
InvokeMethod
,
null
,
S
ignerCertificate
,
typeValue
);
typeValue
=
new
[]
{
S
ignerCertificate
};
typeRequestCert
.
InvokeMember
(
"SignerCertificate"
,
BindingFlags
.
PutDispProperty
,
null
,
R
equestCert
,
typeValue
);
typeSignerCertificate
.
InvokeMember
(
"Initialize"
,
BindingFlags
.
InvokeMethod
,
null
,
s
ignerCertificate
,
typeValue
);
typeValue
=
new
[]
{
s
ignerCertificate
};
typeRequestCert
.
InvokeMember
(
"SignerCertificate"
,
BindingFlags
.
PutDispProperty
,
null
,
r
equestCert
,
typeValue
);
}
else
{
...
...
@@ -220,24 +220,24 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeX509Extensions
.
InvokeMember
(
"Add"
,
BindingFlags
.
InvokeMethod
,
null
,
certificate
,
typeValue
);
}
OID
=
Activator
.
CreateInstance
(
typeOID
);
oid
=
Activator
.
CreateInstance
(
typeOID
);
typeValue
=
new
object
[]
{
1
,
0
,
0
,
hashAlg
};
typeOID
.
InvokeMember
(
"InitializeFromAlgorithmName"
,
BindingFlags
.
InvokeMethod
,
null
,
OID
,
typeValue
);
typeOID
.
InvokeMember
(
"InitializeFromAlgorithmName"
,
BindingFlags
.
InvokeMethod
,
null
,
oid
,
typeValue
);
typeValue
=
new
[]
{
OID
};
typeRequestCert
.
InvokeMember
(
"HashAlgorithm"
,
BindingFlags
.
PutDispProperty
,
null
,
R
equestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
R
equestCert
,
null
);
typeValue
=
new
[]
{
oid
};
typeRequestCert
.
InvokeMember
(
"HashAlgorithm"
,
BindingFlags
.
PutDispProperty
,
null
,
r
equestCert
,
typeValue
);
typeRequestCert
.
InvokeMember
(
"Encode"
,
BindingFlags
.
InvokeMethod
,
null
,
r
equestCert
,
null
);
var
X
509Enrollment
=
Activator
.
CreateInstance
(
typeX509Enrollment
);
var
x
509Enrollment
=
Activator
.
CreateInstance
(
typeX509Enrollment
);
typeValue
[
0
]
=
R
equestCert
;
typeX509Enrollment
.
InvokeMember
(
"InitializeFromRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
X
509Enrollment
,
typeValue
);
typeValue
[
0
]
=
r
equestCert
;
typeX509Enrollment
.
InvokeMember
(
"InitializeFromRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
x
509Enrollment
,
typeValue
);
if
(
isRoot
)
{
typeValue
[
0
]
=
fullSubject
;
typeX509Enrollment
.
InvokeMember
(
"CertificateFriendlyName"
,
BindingFlags
.
PutDispProperty
,
null
,
X
509Enrollment
,
typeValue
);
typeX509Enrollment
.
InvokeMember
(
"CertificateFriendlyName"
,
BindingFlags
.
PutDispProperty
,
null
,
x
509Enrollment
,
typeValue
);
}
...
...
@@ -245,15 +245,15 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeValue
[
0
]
=
0
;
var
createCertRequest
=
typeX509Enrollment
.
InvokeMember
(
"CreateRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
X
509Enrollment
,
typeValue
);
var
createCertRequest
=
typeX509Enrollment
.
InvokeMember
(
"CreateRequest"
,
BindingFlags
.
InvokeMethod
,
null
,
x
509Enrollment
,
typeValue
);
typeValue
=
new
[]
{
2
,
createCertRequest
,
0
,
string
.
Empty
};
typeX509Enrollment
.
InvokeMember
(
"InstallResponse"
,
BindingFlags
.
InvokeMethod
,
null
,
X
509Enrollment
,
typeValue
);
typeX509Enrollment
.
InvokeMember
(
"InstallResponse"
,
BindingFlags
.
InvokeMethod
,
null
,
x
509Enrollment
,
typeValue
);
typeValue
=
new
object
[]
{
null
,
0
,
1
};
try
{
var
empty
=
(
string
)
typeX509Enrollment
.
InvokeMember
(
"CreatePFX"
,
BindingFlags
.
InvokeMethod
,
null
,
X
509Enrollment
,
typeValue
);
var
empty
=
(
string
)
typeX509Enrollment
.
InvokeMember
(
"CreatePFX"
,
BindingFlags
.
InvokeMethod
,
null
,
x
509Enrollment
,
typeValue
);
return
new
X509Certificate2
(
Convert
.
FromBase64String
(
empty
),
string
.
Empty
,
X509KeyStorageFlags
.
Exportable
);
}
catch
(
Exception
)
...
...
Titanium.Web.Proxy/Network/CertificateManager.cs
View file @
e928c25a
...
...
@@ -31,6 +31,10 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
internal
class
CertificateManager
:
IDisposable
{
private
const
string
defaultRootCertificateIssuer
=
"Titanium"
;
private
const
string
defaultRootRootCertificateName
=
"Titanium Root Certificate Authority"
;
private
readonly
ICertificateMaker
certEngine
;
private
bool
clearCertificates
{
get
;
set
;
}
...
...
@@ -66,8 +70,8 @@ namespace Titanium.Web.Proxy.Network
certEngine
=
new
WinCertificateMaker
();
}
Issuer
=
issuer
;
RootCertificateName
=
rootCertificateName
;
Issuer
=
issuer
??
defaultRootCertificateIssuer
;
RootCertificateName
=
rootCertificateName
??
defaultRootRootCertificateName
;
certificateCache
=
new
ConcurrentDictionary
<
string
,
CachedCertificate
>();
}
...
...
@@ -88,7 +92,7 @@ namespace Titanium.Web.Proxy.Network
return
fileName
;
}
internal
X509Certificate2
Get
RootCertificate
()
internal
X509Certificate2
Load
RootCertificate
()
{
var
fileName
=
GetRootCertificatePath
();
if
(!
File
.
Exists
(
fileName
))
return
null
;
...
...
@@ -108,11 +112,16 @@ namespace Titanium.Web.Proxy.Network
/// <returns>true if succeeded, else false</returns>
internal
bool
CreateTrustedRootCertificate
()
{
RootCertificate
=
GetRootCertificate
();
if
(
RootCertificate
==
null
)
{
RootCertificate
=
LoadRootCertificate
();
}
if
(
RootCertificate
!=
null
)
{
return
true
;
}
try
{
RootCertificate
=
CreateCertificate
(
RootCertificateName
,
true
);
...
...
@@ -121,6 +130,7 @@ namespace Titanium.Web.Proxy.Network
{
exceptionFunc
(
e
);
}
if
(
RootCertificate
!=
null
)
{
try
...
...
@@ -133,9 +143,23 @@ namespace Titanium.Web.Proxy.Network
exceptionFunc
(
e
);
}
}
return
RootCertificate
!=
null
;
}
/// <summary>
/// Trusts the root certificate.
/// </summary>
/// <param name="exceptionFunc"></param>
internal
void
TrustRootCertificate
(
Action
<
Exception
>
exceptionFunc
)
{
//current user
TrustRootCertificate
(
StoreLocation
.
CurrentUser
,
exceptionFunc
);
//current system
TrustRootCertificate
(
StoreLocation
.
LocalMachine
,
exceptionFunc
);
}
/// <summary>
/// Create an SSL certificate
/// </summary>
...
...
@@ -144,15 +168,13 @@ namespace Titanium.Web.Proxy.Network
/// <returns></returns>
internal
virtual
X509Certificate2
CreateCertificate
(
string
certificateName
,
bool
isRootCertificate
)
{
if
(
certificateCache
.
ContainsKey
(
certificateName
))
{
var
cached
=
certificateCache
[
certificateName
];
cached
.
LastAccess
=
DateTime
.
Now
;
return
cached
.
Certificate
;
}
X509Certificate2
certificate
=
null
;
lock
(
string
.
Intern
(
certificateName
))
{
...
...
@@ -160,6 +182,11 @@ namespace Titanium.Web.Proxy.Network
{
try
{
if
(!
isRootCertificate
&&
RootCertificate
==
null
)
{
CreateTrustedRootCertificate
();
}
certificate
=
certEngine
.
MakeCertificate
(
certificateName
,
isRootCertificate
,
RootCertificate
);
}
catch
(
Exception
e
)
...
...
@@ -168,7 +195,7 @@ namespace Titanium.Web.Proxy.Network
}
if
(
certificate
!=
null
&&
!
certificateCache
.
ContainsKey
(
certificateName
))
{
certificateCache
.
Add
(
certificateName
,
new
CachedCertificate
()
{
Certificate
=
certificate
});
certificateCache
.
Add
(
certificateName
,
new
CachedCertificate
{
Certificate
=
certificate
});
}
}
else
...
...
@@ -182,10 +209,7 @@ namespace Titanium.Web.Proxy.Network
}
}
return
certificate
;
}
/// <summary>
...
...
Titanium.Web.Proxy/Network/ProxyClient.cs
View file @
e928c25a
...
...
@@ -7,7 +7,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// This class wraps Tcp connection to client
/// </summary>
public
class
ProxyClient
internal
class
ProxyClient
{
/// <summary>
/// TcpClient used to communicate with client
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs
View file @
e928c25a
...
...
@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary>
/// An object that holds TcpConnection to a particular server and port
/// </summary>
public
class
TcpConnection
:
IDisposable
internal
class
TcpConnection
:
IDisposable
{
internal
ExternalProxy
UpStreamHttpProxy
{
get
;
set
;
}
...
...
Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
e928c25a
using
System
;
using
System.Net.Sockets
;
using
System.Text
;
using
System.Threading.Tasks
;
using
System.IO
;
using
System.Net.Security
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
System.Security.Authentication
;
using
System.Linq
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Network.Tcp
{
using
System.Net
;
/// <summary>
/// A class that manages Tcp Connection to server used by this proxy server
/// </summary>
internal
class
TcpConnectionFactory
{
/// <summary>
/// Creates a TCP connection to server
/// </summary>
/// <param name="bufferSize"></param>
/// <param name="connectionTimeOutSeconds"></param>
/// <param name="remoteHostName"></param>
/// <param name="httpVersion"></param>
/// <param name="isHttps"></param>
/// <param name="remotePort"></param>
/// <param name="supportedSslProtocols"></param>
/// <param name="remoteCertificateValidationCallback"></param>
/// <param name="localCertificateSelectionCallback"></param>
/// <param name="externalHttpProxy"></param>
/// <param name="externalHttpsProxy"></param>
/// <param name="clientStream"></param>
/// <param name="upStreamEndPoint"></param>
/// <returns></returns>
internal
async
Task
<
TcpConnection
>
CreateClient
(
int
bufferSize
,
int
connectionTimeOutSeconds
,
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
bool
isHttps
,
SslProtocols
supportedSslProtocols
,
RemoteCertificateValidationCallback
remoteCertificateValidationCallback
,
LocalCertificateSelectionCallback
localCertificateSelectionCallback
,
ExternalProxy
externalHttpProxy
,
ExternalProxy
externalHttpsProxy
,
Stream
clientStream
,
EndPoint
upStreamEndPoint
)
{
TcpClient
client
;
Stream
stream
;
if
(
isHttps
)
{
SslStream
sslStream
=
null
;
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if
(
externalHttpsProxy
!=
null
&&
externalHttpsProxy
.
HostName
!=
remoteHostName
)
{
client
=
new
TcpClient
();
client
.
Client
.
Bind
(
upStreamEndPoint
);
await
client
.
ConnectAsync
(
externalHttpsProxy
.
HostName
,
externalHttpsProxy
.
Port
);
stream
=
client
.
GetStream
();
using
(
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
bufferSize
,
true
)
{
NewLine
=
ProxyConstants
.
NewLine
})
{
await
writer
.
WriteLineAsync
(
$"CONNECT
{
remoteHostName
}
:
{
remotePort
}
HTTP/
{
httpVersion
}
"
);
await
writer
.
WriteLineAsync
(
$"Host:
{
remoteHostName
}
:
{
remotePort
}
"
);
await
writer
.
WriteLineAsync
(
"Connection: Keep-Alive"
);
if
(!
string
.
IsNullOrEmpty
(
externalHttpsProxy
.
UserName
)
&&
externalHttpsProxy
.
Password
!=
null
)
{
await
writer
.
WriteLineAsync
(
"Proxy-Connection: keep-alive"
);
await
writer
.
WriteLineAsync
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
externalHttpsProxy
.
UserName
+
":"
+
externalHttpsProxy
.
Password
)));
}
await
writer
.
WriteLineAsync
();
await
writer
.
FlushAsync
();
writer
.
Close
();
}
using
(
var
reader
=
new
CustomBinaryReader
(
stream
))
{
var
result
=
await
reader
.
ReadLineAsync
();
if
(!
new
[]
{
"200 OK"
,
"connection established"
}.
Any
(
s
=>
result
.
ToLower
().
Contains
(
s
.
ToLower
())))
{
throw
new
Exception
(
"Upstream proxy failed to create a secure tunnel"
);
}
await
reader
.
ReadAllLinesAsync
();
}
}
else
{
client
=
new
TcpClient
();
client
.
Client
.
Bind
(
upStreamEndPoint
);
await
client
.
ConnectAsync
(
remoteHostName
,
remotePort
);
stream
=
client
.
GetStream
();
}
try
{
sslStream
=
new
SslStream
(
stream
,
true
,
remoteCertificateValidationCallback
,
localCertificateSelectionCallback
);
await
sslStream
.
AuthenticateAsClientAsync
(
remoteHostName
,
null
,
supportedSslProtocols
,
false
);
stream
=
sslStream
;
}
catch
{
sslStream
?.
Dispose
();
throw
;
}
}
else
{
if
(
externalHttpProxy
!=
null
&&
externalHttpProxy
.
HostName
!=
remoteHostName
)
{
client
=
new
TcpClient
();
client
.
Client
.
Bind
(
upStreamEndPoint
);
await
client
.
ConnectAsync
(
externalHttpProxy
.
HostName
,
externalHttpProxy
.
Port
);
stream
=
client
.
GetStream
();
}
else
{
client
=
new
TcpClient
();
client
.
Client
.
Bind
(
upStreamEndPoint
);
await
client
.
ConnectAsync
(
remoteHostName
,
remotePort
);
stream
=
client
.
GetStream
();
}
}
client
.
ReceiveTimeout
=
connectionTimeOutSeconds
*
1000
;
client
.
SendTimeout
=
connectionTimeOutSeconds
*
1000
;
stream
.
ReadTimeout
=
connectionTimeOutSeconds
*
1000
;
stream
.
WriteTimeout
=
connectionTimeOutSeconds
*
1000
;
return
new
TcpConnection
()
{
UpStreamHttpProxy
=
externalHttpProxy
,
UpStreamHttpsProxy
=
externalHttpsProxy
,
HostName
=
remoteHostName
,
Port
=
remotePort
,
IsHttps
=
isHttps
,
TcpClient
=
client
,
StreamReader
=
new
CustomBinaryReader
(
stream
),
Stream
=
stream
,
Version
=
httpVersion
};
}
}
using
System
;
using
System.Net.Sockets
;
using
System.Text
;
using
System.Threading.Tasks
;
using
System.IO
;
using
System.Net.Security
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
System.Security.Authentication
;
using
System.Linq
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Network.Tcp
{
using
System.Net
;
/// <summary>
/// A class that manages Tcp Connection to server used by this proxy server
/// </summary>
internal
class
TcpConnectionFactory
{
/// <summary>
/// Creates a TCP connection to server
/// </summary>
/// <param name="bufferSize"></param>
/// <param name="connectionTimeOutSeconds"></param>
/// <param name="remoteHostName"></param>
/// <param name="httpVersion"></param>
/// <param name="isHttps"></param>
/// <param name="remotePort"></param>
/// <param name="supportedSslProtocols"></param>
/// <param name="remoteCertificateValidationCallback"></param>
/// <param name="localCertificateSelectionCallback"></param>
/// <param name="externalHttpProxy"></param>
/// <param name="externalHttpsProxy"></param>
/// <param name="clientStream"></param>
/// <param name="upStreamEndPoint"></param>
/// <returns></returns>
internal
async
Task
<
TcpConnection
>
CreateClient
(
int
bufferSize
,
int
connectionTimeOutSeconds
,
string
remoteHostName
,
int
remotePort
,
Version
httpVersion
,
bool
isHttps
,
SslProtocols
supportedSslProtocols
,
RemoteCertificateValidationCallback
remoteCertificateValidationCallback
,
LocalCertificateSelectionCallback
localCertificateSelectionCallback
,
ExternalProxy
externalHttpProxy
,
ExternalProxy
externalHttpsProxy
,
Stream
clientStream
,
IPEndPoint
upStreamEndPoint
)
{
TcpClient
client
;
Stream
stream
;
bool
isLocalhost
=
(
externalHttpsProxy
==
null
&&
externalHttpProxy
==
null
)
?
false
:
NetworkHelper
.
IsLocalIpAddress
(
remoteHostName
);
bool
useHttpsProxy
=
externalHttpsProxy
!=
null
&&
externalHttpsProxy
.
HostName
!=
remoteHostName
&&
(
externalHttpsProxy
.
BypassForLocalhost
&&
!
isLocalhost
);
bool
useHttpProxy
=
externalHttpProxy
!=
null
&&
externalHttpProxy
.
HostName
!=
remoteHostName
&&
(
externalHttpProxy
.
BypassForLocalhost
&&
!
isLocalhost
);
if
(
isHttps
)
{
SslStream
sslStream
=
null
;
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if
(
useHttpsProxy
)
{
client
=
new
TcpClient
(
upStreamEndPoint
);
await
client
.
ConnectAsync
(
externalHttpsProxy
.
HostName
,
externalHttpsProxy
.
Port
);
stream
=
client
.
GetStream
();
using
(
var
writer
=
new
StreamWriter
(
stream
,
Encoding
.
ASCII
,
bufferSize
,
true
)
{
NewLine
=
ProxyConstants
.
NewLine
})
{
await
writer
.
WriteLineAsync
(
$"CONNECT
{
remoteHostName
}
:
{
remotePort
}
HTTP/
{
httpVersion
}
"
);
await
writer
.
WriteLineAsync
(
$"Host:
{
remoteHostName
}
:
{
remotePort
}
"
);
await
writer
.
WriteLineAsync
(
"Connection: Keep-Alive"
);
if
(!
string
.
IsNullOrEmpty
(
externalHttpsProxy
.
UserName
)
&&
externalHttpsProxy
.
Password
!=
null
)
{
await
writer
.
WriteLineAsync
(
"Proxy-Connection: keep-alive"
);
await
writer
.
WriteLineAsync
(
"Proxy-Authorization"
+
": Basic "
+
Convert
.
ToBase64String
(
Encoding
.
UTF8
.
GetBytes
(
externalHttpsProxy
.
UserName
+
":"
+
externalHttpsProxy
.
Password
)));
}
await
writer
.
WriteLineAsync
();
await
writer
.
FlushAsync
();
writer
.
Close
();
}
using
(
var
reader
=
new
CustomBinaryReader
(
stream
))
{
var
result
=
await
reader
.
ReadLineAsync
();
if
(!
new
[]
{
"200 OK"
,
"connection established"
}.
Any
(
s
=>
result
.
ToLower
().
Contains
(
s
.
ToLower
())))
{
throw
new
Exception
(
"Upstream proxy failed to create a secure tunnel"
);
}
await
reader
.
ReadAllLinesAsync
();
}
}
else
{
client
=
new
TcpClient
(
upStreamEndPoint
);
await
client
.
ConnectAsync
(
remoteHostName
,
remotePort
);
stream
=
client
.
GetStream
();
}
try
{
sslStream
=
new
SslStream
(
stream
,
true
,
remoteCertificateValidationCallback
,
localCertificateSelectionCallback
);
await
sslStream
.
AuthenticateAsClientAsync
(
remoteHostName
,
null
,
supportedSslProtocols
,
false
);
stream
=
sslStream
;
}
catch
{
sslStream
?.
Dispose
();
throw
;
}
}
else
{
if
(
useHttpProxy
)
{
client
=
new
TcpClient
(
upStreamEndPoint
);
await
client
.
ConnectAsync
(
externalHttpProxy
.
HostName
,
externalHttpProxy
.
Port
);
stream
=
client
.
GetStream
();
}
else
{
client
=
new
TcpClient
(
upStreamEndPoint
);
await
client
.
ConnectAsync
(
remoteHostName
,
remotePort
);
stream
=
client
.
GetStream
();
}
}
client
.
ReceiveTimeout
=
connectionTimeOutSeconds
*
1000
;
client
.
SendTimeout
=
connectionTimeOutSeconds
*
1000
;
stream
.
ReadTimeout
=
connectionTimeOutSeconds
*
1000
;
stream
.
WriteTimeout
=
connectionTimeOutSeconds
*
1000
;
return
new
TcpConnection
()
{
UpStreamHttpProxy
=
externalHttpProxy
,
UpStreamHttpsProxy
=
externalHttpsProxy
,
HostName
=
remoteHostName
,
Port
=
remotePort
,
IsHttps
=
isHttps
,
TcpClient
=
client
,
StreamReader
=
new
CustomBinaryReader
(
stream
),
Stream
=
stream
,
Version
=
httpVersion
};
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Network/Tcp/TcpRow.cs
View file @
e928c25a
...
...
@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// Initializes a new instance of the <see cref="TcpRow"/> class.
/// </summary>
/// <param name="tcpRow">TcpRow struct.</param>
public
TcpRow
(
NativeMethods
.
TcpRow
tcpRow
)
internal
TcpRow
(
NativeMethods
.
TcpRow
tcpRow
)
{
ProcessId
=
tcpRow
.
owningPid
;
...
...
@@ -29,16 +29,16 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary>
/// Gets the local end point.
/// </summary>
public
IPEndPoint
LocalEndPoint
{
get
;
}
internal
IPEndPoint
LocalEndPoint
{
get
;
}
/// <summary>
/// Gets the remote end point.
/// </summary>
public
IPEndPoint
RemoteEndPoint
{
get
;
}
/// <summary>
/// Gets the remote end point.
/// </summary>
internal
IPEndPoint
RemoteEndPoint
{
get
;
}
/// <summary>
/// Gets the process identifier.
/// </summary>
public
int
ProcessId
{
get
;
}
internal
int
ProcessId
{
get
;
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Network/Tcp/TcpTable.cs
View file @
e928c25a
...
...
@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// Initializes a new instance of the <see cref="TcpTable"/> class.
/// </summary>
/// <param name="tcpRows">TcpRow collection to initialize with.</param>
public
TcpTable
(
IEnumerable
<
TcpRow
>
tcpRows
)
internal
TcpTable
(
IEnumerable
<
TcpRow
>
tcpRows
)
{
this
.
tcpRows
=
tcpRows
;
}
...
...
@@ -25,7 +25,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary>
/// Gets the TCP rows.
/// </summary>
public
IEnumerable
<
TcpRow
>
TcpRows
=>
tcpRows
;
internal
IEnumerable
<
TcpRow
>
TcpRows
=>
tcpRows
;
/// <summary>
/// Returns an enumerator that iterates through the collection.
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
e928c25a
...
...
@@ -19,11 +19,10 @@ namespace Titanium.Web.Proxy
/// </summary>
public
partial
class
ProxyServer
:
IDisposable
{
/// <summary>
/// Is the root certificate used by this proxy is valid?
/// </summary>
private
bool
certValidated
{
get
;
set
;
}
private
bool
?
certValidated
{
get
;
set
;
}
/// <summary>
/// Is the proxy currently running
...
...
@@ -33,7 +32,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Manages certificates used by this proxy
/// </summary>
private
CertificateManager
certificate
Cache
Manager
{
get
;
set
;
}
private
CertificateManager
certificateManager
{
get
;
set
;
}
/// <summary>
/// An default exception log func
...
...
@@ -45,6 +44,8 @@ namespace Titanium.Web.Proxy
/// </summary>
private
Action
<
Exception
>
exceptionFunc
;
private
bool
trustRootCertificate
;
/// <summary>
/// A object that creates tcp connection to server
/// </summary>
...
...
@@ -66,27 +67,65 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Buffer size used throughout this proxy
/// </summary>
public
int
BUFFER_SIZE
{
get
;
set
;
}
=
8192
;
public
int
BufferSize
{
get
;
set
;
}
=
8192
;
/// <summary>
/// The root certificate
/// </summary>
public
X509Certificate2
RootCertificate
{
get
{
return
certificateManager
.
RootCertificate
;
}
set
{
certificateManager
.
RootCertificate
=
value
;
}
}
/// <summary>
/// Name of the root certificate issuer
/// Name of the root certificate issuer
/// (This is valid only when RootCertificate property is not set)
/// </summary>
public
string
RootCertificateIssuerName
{
get
;
set
;
}
public
string
RootCertificateIssuerName
{
get
{
return
certificateManager
.
Issuer
;
}
set
{
CreateCertificateManager
(
certificateManager
.
RootCertificateName
,
value
);
certValidated
=
null
;
}
}
/// <summary>
/// Name of the root certificate
/// (This is valid only when RootCertificate property is not set)
/// If no certificate is provided then a default Root Certificate will be created and used
/// The provided root certificate
has to be in the
proxy exe directory with the private key
///
The root certificate file should be named as
"rootCert.pfx"
/// The provided root certificate
will be stored in
proxy exe directory with the private key
///
Root certificate file will be named as
"rootCert.pfx"
/// </summary>
public
string
RootCertificateName
{
get
;
set
;
}
public
string
RootCertificateName
{
get
{
return
certificateManager
.
RootCertificateName
;
}
set
{
CreateCertificateManager
(
value
,
certificateManager
.
Issuer
);
certValidated
=
null
;
}
}
/// <summary>
/// Trust the RootCertificate used by this proxy server
/// Note that this do not make the client trust the certificate!
/// This would import the root certificate to the certificate store of machine that runs this proxy server
/// </summary>
public
bool
TrustRootCertificate
{
get
;
set
;
}
public
bool
TrustRootCertificate
{
get
{
return
trustRootCertificate
;
}
set
{
trustRootCertificate
=
value
;
if
(
value
)
{
EnsureRootCertificate
();
}
}
}
/// <summary>
/// Select Certificate Engine
...
...
@@ -211,7 +250,9 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Constructor
/// </summary>
public
ProxyServer
()
:
this
(
null
,
null
)
{
}
public
ProxyServer
()
:
this
(
null
,
null
)
{
}
/// <summary>
/// Constructor.
...
...
@@ -220,9 +261,6 @@ namespace Titanium.Web.Proxy
/// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param>
public
ProxyServer
(
string
rootCertificateName
,
string
rootCertificateIssuerName
)
{
RootCertificateName
=
rootCertificateName
;
RootCertificateIssuerName
=
rootCertificateIssuerName
;
//default values
ConnectionTimeOutSeconds
=
120
;
CertificateCacheTimeOutMinutes
=
60
;
...
...
@@ -233,8 +271,8 @@ namespace Titanium.Web.Proxy
#if !DEBUG
new
FireFoxProxySettingsManager
();
#endif
RootCertificateName
=
RootCertificateName
??
"Titanium Root Certificate Authority"
;
RootCertificateIssuerName
=
RootCertificateIssuerName
??
"Titanium"
;
CreateCertificateManager
(
rootCertificateName
,
rootCertificateIssuerName
)
;
}
/// <summary>
...
...
@@ -328,8 +366,10 @@ namespace Titanium.Web.Proxy
.
ToList
()
.
ForEach
(
x
=>
x
.
IsSystemHttpsProxy
=
false
);
EnsureRootCertificate
();
//If certificate was trusted by the machine
if
(
certValidated
)
if
(
certValidated
==
true
)
{
systemProxySettingsManager
.
SetHttpsProxy
(
Equals
(
endPoint
.
IpAddress
,
IPAddress
.
Any
)
|
...
...
@@ -397,23 +437,6 @@ namespace Titanium.Web.Proxy
throw
new
Exception
(
"Proxy is already running."
);
}
certificateCacheManager
=
new
CertificateManager
(
CertificateEngine
,
RootCertificateIssuerName
,
RootCertificateName
,
ExceptionFunc
);
certValidated
=
certificateCacheManager
.
CreateTrustedRootCertificate
();
if
(
TrustRootCertificate
)
{
//current user
certificateCacheManager
.
TrustRootCertificate
(
StoreLocation
.
CurrentUser
,
ExceptionFunc
);
//current system
certificateCacheManager
.
TrustRootCertificate
(
StoreLocation
.
LocalMachine
,
ExceptionFunc
);
}
if
(
ForwardToUpstreamGateway
&&
GetCustomUpStreamHttpProxyFunc
==
null
&&
GetCustomUpStreamHttpsProxyFunc
==
null
)
{
...
...
@@ -426,32 +449,11 @@ namespace Titanium.Web.Proxy
Listen
(
endPoint
);
}
certificate
Cache
Manager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
certificateManager
.
ClearIdleCertificates
(
CertificateCacheTimeOutMinutes
);
proxyRunning
=
true
;
}
/// <summary>
/// Gets the system up stream proxy.
/// </summary>
/// <param name="sessionEventArgs">The <see cref="SessionEventArgs"/> instance containing the event data.</param>
/// <returns><see cref="ExternalProxy"/> instance containing valid proxy configuration from PAC/WAPD scripts if any exists.</returns>
private
Task
<
ExternalProxy
>
GetSystemUpStreamProxy
(
SessionEventArgs
sessionEventArgs
)
{
// Use built-in WebProxy class to handle PAC/WAPD scripts.
var
systemProxyResolver
=
new
WebProxy
();
var
systemProxyUri
=
systemProxyResolver
.
GetProxy
(
sessionEventArgs
.
WebSession
.
Request
.
RequestUri
);
// TODO: Apply authorization
var
systemProxy
=
new
ExternalProxy
{
HostName
=
systemProxyUri
.
Host
,
Port
=
systemProxyUri
.
Port
};
return
Task
.
FromResult
(
systemProxy
);
}
/// <summary>
/// Stop this proxy server
...
...
@@ -480,11 +482,24 @@ namespace Titanium.Web.Proxy
ProxyEndPoints
.
Clear
();
certificate
Cache
Manager
?.
StopClearIdleCertificates
();
certificateManager
?.
StopClearIdleCertificates
();
proxyRunning
=
false
;
}
/// <summary>
/// Dispose Proxy.
/// </summary>
public
void
Dispose
()
{
if
(
proxyRunning
)
{
Stop
();
}
certificateManager
?.
Dispose
();
}
/// <summary>
/// Listen on the given end point on local machine
/// </summary>
...
...
@@ -499,16 +514,7 @@ namespace Titanium.Web.Proxy
endPoint
.
Listener
.
BeginAcceptTcpClient
(
OnAcceptConnection
,
endPoint
);
}
/// <summary>
/// Quit listening on the given end point
/// </summary>
/// <param name="endPoint"></param>
private
void
QuitListen
(
ProxyEndPoint
endPoint
)
{
endPoint
.
Listener
.
Stop
();
endPoint
.
Listener
.
Server
.
Close
();
endPoint
.
Listener
.
Server
.
Dispose
();
}
/// <summary>
/// Verifiy if its safe to set this end point as System proxy
...
...
@@ -528,6 +534,48 @@ namespace Titanium.Web.Proxy
}
}
/// <summary>
/// Gets the system up stream proxy.
/// </summary>
/// <param name="sessionEventArgs">The <see cref="SessionEventArgs"/> instance containing the event data.</param>
/// <returns><see cref="ExternalProxy"/> instance containing valid proxy configuration from PAC/WAPD scripts if any exists.</returns>
private
Task
<
ExternalProxy
>
GetSystemUpStreamProxy
(
SessionEventArgs
sessionEventArgs
)
{
// Use built-in WebProxy class to handle PAC/WAPD scripts.
var
systemProxyResolver
=
new
WebProxy
();
var
systemProxyUri
=
systemProxyResolver
.
GetProxy
(
sessionEventArgs
.
WebSession
.
Request
.
RequestUri
);
// TODO: Apply authorization
var
systemProxy
=
new
ExternalProxy
{
HostName
=
systemProxyUri
.
Host
,
Port
=
systemProxyUri
.
Port
};
return
Task
.
FromResult
(
systemProxy
);
}
private
void
CreateCertificateManager
(
string
rootCertificateName
,
string
rootCertificateIssuerName
)
{
certificateManager
=
new
CertificateManager
(
CertificateEngine
,
rootCertificateIssuerName
,
rootCertificateName
,
ExceptionFunc
);
}
private
void
EnsureRootCertificate
()
{
if
(!
certValidated
.
HasValue
)
{
certValidated
=
certificateManager
.
CreateTrustedRootCertificate
();
if
(
TrustRootCertificate
)
{
certificateManager
.
TrustRootCertificate
(
ExceptionFunc
);
}
}
}
/// <summary>
/// When a connection is received from client act
/// </summary>
...
...
@@ -599,18 +647,16 @@ namespace Titanium.Web.Proxy
}
/// <summary>
///
Dispose Proxy.
///
Quit listening on the given end point
/// </summary>
public
void
Dispose
()
/// <param name="endPoint"></param>
private
void
QuitListen
(
ProxyEndPoint
endPoint
)
{
if
(
proxyRunning
)
{
Stop
();
}
certificateCacheManager
?.
Dispose
();
endPoint
.
Listener
.
Stop
();
endPoint
.
Listener
.
Server
.
Close
();
endPoint
.
Listener
.
Server
.
Dispose
();
}
/// <summary>
/// Invocator for BeforeRequest event.
/// </summary>
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
e928c25a
...
...
@@ -115,7 +115,7 @@ namespace Titanium.Web.Proxy
sslStream
=
new
SslStream
(
clientStream
,
true
);
var
certificate
=
endPoint
.
GenericCertificate
??
certificate
Cache
Manager
.
CreateCertificate
(
httpRemoteUri
.
Host
,
false
);
var
certificate
=
endPoint
.
GenericCertificate
??
certificateManager
.
CreateCertificate
(
httpRemoteUri
.
Host
,
false
);
//Successfully managed to authenticate the client using the fake certificate
await
sslStream
.
AuthenticateAsServerAsync
(
certificate
,
false
,
...
...
@@ -147,7 +147,7 @@ namespace Titanium.Web.Proxy
//write back successfull CONNECT response
await
WriteConnectResponse
(
clientStreamWriter
,
version
);
await
TcpHelper
.
SendRaw
(
B
UFFER_SIZE
,
ConnectionTimeOutSeconds
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
await
TcpHelper
.
SendRaw
(
B
ufferSize
,
ConnectionTimeOutSeconds
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
null
,
version
,
null
,
false
,
SupportedSslProtocols
,
ValidateServerCertificate
,
...
...
@@ -185,7 +185,7 @@ namespace Titanium.Web.Proxy
var
sslStream
=
new
SslStream
(
clientStream
,
true
);
//implement in future once SNI supported by SSL stream, for now use the same certificate
var
certificate
=
certificate
Cache
Manager
.
CreateCertificate
(
endPoint
.
GenericCertificateName
,
false
);
var
certificate
=
certificateManager
.
CreateCertificate
(
endPoint
.
GenericCertificateName
,
false
);
try
{
...
...
@@ -245,7 +245,7 @@ namespace Titanium.Web.Proxy
args
.
CustomUpStreamHttpProxyUsed
=
customUpStreamHttpProxy
;
args
.
CustomUpStreamHttpsProxyUsed
=
customUpStreamHttpsProxy
;
connection
=
await
tcpConnectionFactory
.
CreateClient
(
B
UFFER_SIZE
,
ConnectionTimeOutSeconds
,
connection
=
await
tcpConnectionFactory
.
CreateClient
(
B
ufferSize
,
ConnectionTimeOutSeconds
,
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
args
.
WebSession
.
Request
.
RequestUri
.
Port
,
args
.
WebSession
.
Request
.
HttpVersion
,
args
.
IsHttps
,
SupportedSslProtocols
,
ValidateServerCertificate
,
...
...
@@ -378,7 +378,7 @@ namespace Titanium.Web.Proxy
}
var
args
=
new
SessionEventArgs
(
B
UFFER_SIZE
,
HandleHttpSessionResponse
)
new
SessionEventArgs
(
B
ufferSize
,
HandleHttpSessionResponse
)
{
ProxyClient
=
{
TcpClient
=
client
},
WebSession
=
{
ConnectHeaders
=
connectHeaders
}
...
...
@@ -487,7 +487,7 @@ namespace Titanium.Web.Proxy
//if upgrading to websocket then relay the requet without reading the contents
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
{
await
TcpHelper
.
SendRaw
(
B
UFFER_SIZE
,
ConnectionTimeOutSeconds
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
await
TcpHelper
.
SendRaw
(
B
ufferSize
,
ConnectionTimeOutSeconds
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
httpCmd
,
httpVersion
,
args
.
WebSession
.
Request
.
RequestHeaders
,
args
.
IsHttps
,
SupportedSslProtocols
,
ValidateServerCertificate
,
SelectClientCertificate
,
...
...
@@ -581,14 +581,14 @@ namespace Titanium.Web.Proxy
//send the request body bytes to server
if
(
args
.
WebSession
.
Request
.
ContentLength
>
0
)
{
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
B
UFFER_SIZE
,
postStream
,
args
.
WebSession
.
Request
.
ContentLength
);
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStream
(
B
ufferSize
,
postStream
,
args
.
WebSession
.
Request
.
ContentLength
);
}
//Need to revist, find any potential bugs
//send the request body bytes to server in chunks
else
if
(
args
.
WebSession
.
Request
.
IsChunked
)
{
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
B
UFFER_SIZE
,
postStream
);
await
args
.
ProxyClient
.
ClientStreamReader
.
CopyBytesToStreamChunked
(
B
ufferSize
,
postStream
);
}
}
}
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
e928c25a
...
...
@@ -22,7 +22,7 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
p
ublic
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
p
rivate
async
Task
HandleHttpSessionResponse
(
SessionEventArgs
args
)
{
//read response & headers from server
await
args
.
WebSession
.
ReceiveResponse
();
...
...
@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy
||
!
args
.
WebSession
.
Response
.
ResponseKeepAlive
)
{
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
B
UFFER_SIZE
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
.
WriteResponseBody
(
B
ufferSize
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
}
//write response if connection:keep-alive header exist and when version is http/1.0
...
...
@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy
else
if
(
args
.
WebSession
.
Response
.
ResponseKeepAlive
&&
args
.
WebSession
.
Response
.
HttpVersion
.
Minor
==
0
)
{
await
args
.
WebSession
.
ServerConnection
.
StreamReader
.
WriteResponseBody
(
B
UFFER_SIZE
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
.
WriteResponseBody
(
B
ufferSize
,
args
.
ProxyClient
.
ClientStream
,
args
.
WebSession
.
Response
.
IsChunked
,
args
.
WebSession
.
Response
.
ContentLength
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment