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
7d115949
Commit
7d115949
authored
Feb 06, 2016
by
titanium007
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #41 from titanium007/release
Release 2.1
parents
60c23d7e
1b650f08
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
573 additions
and
128 deletions
+573
-128
default.ps1
.build/default.ps1
+1
-1
README.md
README.md
+43
-8
Program.cs
Titanium.Web.Proxy.Test/Program.cs
+0
-16
ProxyTestController.cs
Titanium.Web.Proxy.Test/ProxyTestController.cs
+33
-11
HttpWebResponseExtensions.cs
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
+8
-2
StreamExtensions.cs
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
+7
-3
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+184
-12
Tcp.cs
Titanium.Web.Proxy/Helpers/Tcp.cs
+3
-3
EndPoint.cs
Titanium.Web.Proxy/Models/EndPoint.cs
+56
-0
TcpConnectionManager.cs
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
+2
-1
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+158
-51
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+73
-17
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+1
-1
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+3
-1
appveyor.yml
appveyor.yml
+1
-1
No files found.
.build/default.ps1
View file @
7d115949
...
...
@@ -21,7 +21,7 @@ if(!$Configuration) { $Configuration = $env:Configuration }
if
(!
$Configuration
)
{
$Configuration
=
"Release"
}
if
(!
$Version
)
{
$Version
=
$env
:APPVEYOR_BUILD_VERSION
}
if
(!
$Version
)
{
$Version
=
"
1
.0.
$BuildNumber
"
}
if
(!
$Version
)
{
$Version
=
"
2
.0.
$BuildNumber
"
}
if
(!
$Branch
)
{
$Branch
=
$env
:APPVEYOR_REPO_BRANCH
}
if
(!
$Branch
)
{
$Branch
=
"local"
}
...
...
README.md
View file @
7d115949
...
...
@@ -22,7 +22,7 @@ Refer the HTTP Proxy Server library in your project, look up Test project to lea
Install by nuget:
Install-Package Titanium.Web.Proxy
Install-Package Titanium.Web.Proxy
-Pre
After installing nuget package mark following files to be copied to app directory
...
...
@@ -34,13 +34,46 @@ Setup HTTP proxy:
```
csharp
// listen to client request & server response events
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
ProxyServer
.
EnableSSL
=
true
;
ProxyServer
.
SetAsSystemProxy
=
true
;
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
//for example dropbox.com
var
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Any
,
8000
,
true
){
ExcludedHttpsHostNameRegex
=
new
List
<
string
>()
{
"dropbox.com"
}
};
//An explicit endpoint is where the client knows about the existance of a proxy
//So client sends request in a proxy friendly manner
ProxyServer
.
AddEndPoint
(
explicitEndPoint
);
ProxyServer
.
Start
();
//Transparent endpoint is usefull for reverse proxying (client is not aware of the existance of proxy)
//A transparent endpoint usually requires a network router port forwarding HTTP(S) packets to this endpoint
//Currently do not support Server Name Indication (It is not currently supported by SslStream class)
//That means that the transparent endpoint will always provide the same Generic Certificate to all HTTPS requests
//In this example only google.com will work for HTTPS requests
//Other sites will receive a certificate mismatch warning on browser
//Please read about it before asking questions!
var
transparentEndPoint
=
new
TransparentProxyEndPoint
(
IPAddress
.
Any
,
8001
,
true
)
{
GenericCertificateName
=
"google.com"
};
ProxyServer
.
AddEndPoint
(
transparentEndPoint
);
foreach
(
var
endPoint
in
ProxyServer
.
ProxyEndPoints
)
Console
.
WriteLine
(
"Listening on '{0}' endpoint at Ip {1} and port: {2} "
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
//You can also add/remove end points after proxy has been started
ProxyServer
.
RemoveEndPoint
(
transparentEndPoint
);
//Only explicit proxies can be set as system proxy!
ProxyServer
.
SetAsSystemHttpProxy
(
explicitEndPoint
);
ProxyServer
.
SetAsSystemHttpsProxy
(
explicitEndPoint
);
//wait here (You can use something else as a wait function, I am using this as a demo)
Console
.
Read
();
...
...
@@ -113,6 +146,8 @@ Sample request and response event handlers
```
Future updates
============
*
Add callbacks for client/server certificate validation/selection
*
Support mutual authentication
*
Add Server Name Indication (SNI) for transparent endpoints
*
Support HTTP 2.0
*
Support modification of web socket requests
Titanium.Web.Proxy.Test/Program.cs
View file @
7d115949
...
...
@@ -14,22 +14,6 @@ namespace Titanium.Web.Proxy.Test
NativeMethods
.
SetConsoleCtrlHandler
(
NativeMethods
.
Handler
,
true
);
Console
.
Write
(
"Do you want to monitor HTTPS? (Y/N):"
);
var
readLine
=
Console
.
ReadLine
();
if
(
readLine
!=
null
&&
readLine
.
Trim
().
ToLower
()
==
"y"
)
{
Controller
.
EnableSsl
=
true
;
}
Console
.
Write
(
"Do you want to set this as a System Proxy? (Y/N):"
);
var
line
=
Console
.
ReadLine
();
if
(
line
!=
null
&&
line
.
Trim
().
ToLower
()
==
"y"
)
{
Controller
.
SetAsSystemProxy
=
true
;
}
//Start proxy controller
Controller
.
StartProxy
();
...
...
Titanium.Web.Proxy.Test/ProxyTestController.cs
View file @
7d115949
using
System
;
using
System.Collections.Generic
;
using
System.Net
;
using
System.Text.RegularExpressions
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.Test
{
public
class
ProxyTestController
{
public
int
ListeningPort
{
get
;
set
;
}
public
bool
EnableSsl
{
get
;
set
;
}
public
bool
SetAsSystemProxy
{
get
;
set
;
}
public
void
StartProxy
()
{
ProxyServer
.
BeforeRequest
+=
OnRequest
;
ProxyServer
.
BeforeResponse
+=
OnResponse
;
ProxyServer
.
EnableSsl
=
EnableSsl
;
ProxyServer
.
SetAsSystemProxy
=
SetAsSystemProxy
;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
//for example dropbox.com
ProxyServer
.
ExcludedHttpsHostNameRegex
.
Add
(
".dropbox.com"
);
var
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Any
,
8000
,
true
){
ExcludedHttpsHostNameRegex
=
new
List
<
string
>()
{
"dropbox.com"
}
};
//An explicit endpoint is where the client knows about the existance of a proxy
//So client sends request in a proxy friendly manner
ProxyServer
.
AddEndPoint
(
explicitEndPoint
);
ProxyServer
.
Start
();
ProxyServer
.
ListeningPort
=
ProxyServer
.
ListeningPort
;
//Transparent endpoint is usefull for reverse proxying (client is not aware of the existance of proxy)
//A transparent endpoint usually requires a network router port forwarding HTTP(S) packets to this endpoint
//Currently do not support Server Name Indication (It is not currently supported by SslStream class)
//That means that the transparent endpoint will always provide the same Generic Certificate to all HTTPS requests
//In this example only google.com will work for HTTPS requests
//Other sites will receive a certificate mismatch warning on browser
//Please read about it before asking questions!
var
transparentEndPoint
=
new
TransparentProxyEndPoint
(
IPAddress
.
Any
,
8001
,
true
)
{
GenericCertificateName
=
"google.com"
};
ProxyServer
.
AddEndPoint
(
transparentEndPoint
);
foreach
(
var
endPoint
in
ProxyServer
.
ProxyEndPoints
)
Console
.
WriteLine
(
"Listening on '{0}' endpoint at Ip {1} and port: {2} "
,
endPoint
.
GetType
().
Name
,
endPoint
.
IpAddress
,
endPoint
.
Port
);
Console
.
WriteLine
(
"Proxy listening on local machine port: {0} "
,
ProxyServer
.
ListeningPort
);
//You can also add/remove end points after proxy has been started
ProxyServer
.
RemoveEndPoint
(
transparentEndPoint
);
//Only explicit proxies can be set as system proxy!
ProxyServer
.
SetAsSystemHttpProxy
(
explicitEndPoint
);
ProxyServer
.
SetAsSystemHttpsProxy
(
explicitEndPoint
);
}
public
void
Stop
()
...
...
@@ -39,7 +62,6 @@ namespace Titanium.Web.Proxy.Test
ProxyServer
.
Stop
();
}
//Test On Request, intecept requests
//Read browser URL send back to proxy by the injection script in OnResponse event
public
void
OnRequest
(
object
sender
,
SessionEventArgs
e
)
...
...
Titanium.Web.Proxy/Extensions/HttpWebResponseExtensions.cs
View file @
7d115949
...
...
@@ -8,8 +8,14 @@ namespace Titanium.Web.Proxy.Extensions
{
public
static
Encoding
GetResponseEncoding
(
this
HttpWebSession
response
)
{
if
(
string
.
IsNullOrEmpty
(
response
.
Response
.
CharacterSet
))
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
return
Encoding
.
GetEncoding
(
response
.
Response
.
CharacterSet
.
Replace
(
@""""
,
string
.
Empty
));
if
(
string
.
IsNullOrEmpty
(
response
.
Response
.
CharacterSet
))
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
try
{
return
Encoding
.
GetEncoding
(
response
.
Response
.
CharacterSet
.
Replace
(
@""""
,
string
.
Empty
));
}
catch
{
return
Encoding
.
GetEncoding
(
"ISO-8859-1"
);
}
}
}
}
\ No newline at end of file
Titanium.Web.Proxy/Extensions/StreamExtensions.cs
View file @
7d115949
...
...
@@ -8,13 +8,17 @@ namespace Titanium.Web.Proxy.Extensions
{
public
static
void
CopyToAsync
(
this
Stream
input
,
string
initialData
,
Stream
output
,
int
bufferSize
)
{
var
bytes
=
Encoding
.
ASCII
.
GetBytes
(
initialData
);
output
.
Write
(
bytes
,
0
,
bytes
.
Length
);
if
(!
string
.
IsNullOrEmpty
(
initialData
))
{
var
bytes
=
Encoding
.
ASCII
.
GetBytes
(
initialData
);
output
.
Write
(
bytes
,
0
,
bytes
.
Length
);
}
CopyToAsync
(
input
,
output
,
bufferSize
);
}
//http://stackoverflow.com/questions/1540658/net-asynchronous-stream-read-write
p
ublic
static
void
CopyToAsync
(
this
Stream
input
,
Stream
output
,
int
bufferSize
)
p
rivate
static
void
CopyToAsync
(
this
Stream
input
,
Stream
output
,
int
bufferSize
)
{
try
{
...
...
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
7d115949
using
System
;
using
System.Runtime.InteropServices
;
using
Microsoft.Win32
;
using
System.Text.RegularExpressions
;
using
System.Collections.Generic
;
using
System.Linq
;
namespace
Titanium.Web.Proxy.Helpers
{
...
...
@@ -11,36 +14,135 @@ namespace Titanium.Web.Proxy.Helpers
int
dwBufferLength
);
}
internal
class
HttpSystemProxyValue
{
public
string
HostName
{
get
;
set
;
}
public
int
Port
{
get
;
set
;
}
public
bool
IsSecure
{
get
;
set
;
}
public
override
string
ToString
()
{
if
(!
IsSecure
)
return
"http="
+
HostName
+
":"
+
Port
;
else
return
"https="
+
HostName
+
":"
+
Port
;
}
}
public
static
class
SystemProxyHelper
{
public
const
int
InternetOptionSettingsChanged
=
39
;
public
const
int
InternetOptionRefresh
=
37
;
private
static
object
_prevProxyServer
;
private
static
object
_prevProxyEnable
;
public
static
void
EnableProxyHttp
(
string
hostname
,
int
port
)
public
static
void
SetHttpProxy
(
string
hostname
,
int
port
)
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
reg
!=
null
)
{
_prevProxyEnable
=
reg
.
GetValue
(
"ProxyEnable"
);
_prevProxyServer
=
reg
.
GetValue
(
"ProxyServer"
);
prepareRegistry
(
reg
);
var
exisitingContent
=
reg
.
GetValue
(
"ProxyServer"
)
as
string
;
var
existingSystemProxyValues
=
GetSystemProxyValues
(
exisitingContent
);
existingSystemProxyValues
.
RemoveAll
(
x
=>
!
x
.
IsSecure
);
existingSystemProxyValues
.
Add
(
new
HttpSystemProxyValue
()
{
HostName
=
hostname
,
IsSecure
=
false
,
Port
=
port
});
reg
.
SetValue
(
"ProxyEnable"
,
1
);
reg
.
SetValue
(
"ProxyServer"
,
"http="
+
hostname
+
":"
+
port
+
";"
);
reg
.
SetValue
(
"ProxyServer"
,
String
.
Join
(
";"
,
existingSystemProxyValues
.
Select
(
x
=>
x
.
ToString
()).
ToArray
()));
}
Refresh
();
}
public
static
void
RemoveHttpProxy
()
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
reg
!=
null
)
{
if
(
reg
.
GetValue
(
"ProxyServer"
)!=
null
)
{
var
exisitingContent
=
reg
.
GetValue
(
"ProxyServer"
)
as
string
;
var
existingSystemProxyValues
=
GetSystemProxyValues
(
exisitingContent
);
existingSystemProxyValues
.
RemoveAll
(
x
=>
!
x
.
IsSecure
);
if
(!(
existingSystemProxyValues
.
Count
()
==
0
))
{
reg
.
SetValue
(
"ProxyEnable"
,
1
);
reg
.
SetValue
(
"ProxyServer"
,
String
.
Join
(
";"
,
existingSystemProxyValues
.
Select
(
x
=>
x
.
ToString
()).
ToArray
()));
}
else
{
reg
.
SetValue
(
"ProxyEnable"
,
0
);
reg
.
SetValue
(
"ProxyServer"
,
string
.
Empty
);
}
}
}
Refresh
();
}
public
static
void
EnableProxyHttps
(
string
hostname
,
int
port
)
public
static
void
SetHttpsProxy
(
string
hostname
,
int
port
)
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
reg
!=
null
)
{
prepareRegistry
(
reg
);
var
exisitingContent
=
reg
.
GetValue
(
"ProxyServer"
)
as
string
;
var
existingSystemProxyValues
=
GetSystemProxyValues
(
exisitingContent
);
existingSystemProxyValues
.
RemoveAll
(
x
=>
x
.
IsSecure
);
existingSystemProxyValues
.
Add
(
new
HttpSystemProxyValue
()
{
HostName
=
hostname
,
IsSecure
=
true
,
Port
=
port
});
reg
.
SetValue
(
"ProxyEnable"
,
1
);
reg
.
SetValue
(
"ProxyServer"
,
"http="
+
hostname
+
":"
+
port
+
";https="
+
hostname
+
":"
+
port
);
reg
.
SetValue
(
"ProxyServer"
,
String
.
Join
(
";"
,
existingSystemProxyValues
.
Select
(
x
=>
x
.
ToString
()).
ToArray
()));
}
Refresh
();
}
public
static
void
RemoveHttpsProxy
()
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
reg
!=
null
)
{
if
(
reg
.
GetValue
(
"ProxyServer"
)
!=
null
)
{
var
exisitingContent
=
reg
.
GetValue
(
"ProxyServer"
)
as
string
;
var
existingSystemProxyValues
=
GetSystemProxyValues
(
exisitingContent
);
existingSystemProxyValues
.
RemoveAll
(
x
=>
x
.
IsSecure
);
if
(!(
existingSystemProxyValues
.
Count
()
==
0
))
{
reg
.
SetValue
(
"ProxyEnable"
,
1
);
reg
.
SetValue
(
"ProxyServer"
,
String
.
Join
(
";"
,
existingSystemProxyValues
.
Select
(
x
=>
x
.
ToString
()).
ToArray
()));
}
else
{
reg
.
SetValue
(
"ProxyEnable"
,
0
);
reg
.
SetValue
(
"ProxyServer"
,
string
.
Empty
);
}
}
}
Refresh
();
}
...
...
@@ -48,18 +150,88 @@ namespace Titanium.Web.Proxy.Helpers
{
var
reg
=
Registry
.
CurrentUser
.
OpenSubKey
(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
,
true
);
if
(
reg
!=
null
)
{
reg
.
SetValue
(
"ProxyEnable"
,
_prevProxyEnable
);
if
(
_prevProxyServer
!=
null
)
reg
.
SetValue
(
"ProxyServer"
,
_prevProxyServer
);
reg
.
SetValue
(
"ProxyEnable"
,
0
);
reg
.
SetValue
(
"ProxyServer"
,
string
.
Empty
);
}
Refresh
();
}
private
static
List
<
HttpSystemProxyValue
>
GetSystemProxyValues
(
string
prevServerValue
)
{
var
result
=
new
List
<
HttpSystemProxyValue
>();
if
(
string
.
IsNullOrWhiteSpace
(
prevServerValue
))
return
result
;
var
proxyValues
=
prevServerValue
.
Split
(
';'
);
if
(
proxyValues
.
Length
>
0
)
{
foreach
(
var
value
in
proxyValues
)
{
var
parsedValue
=
parseProxyValue
(
value
);
if
(
parsedValue
!=
null
)
result
.
Add
(
parsedValue
);
}
}
else
{
var
parsedValue
=
parseProxyValue
(
prevServerValue
);
if
(
parsedValue
!=
null
)
result
.
Add
(
parsedValue
);
}
return
result
;
}
private
static
HttpSystemProxyValue
parseProxyValue
(
string
value
)
{
var
tmp
=
Regex
.
Replace
(
value
,
@"\s+"
,
" "
).
Trim
().
ToLower
();
if
(
tmp
.
StartsWith
(
"http="
))
{
var
endPoint
=
tmp
.
Substring
(
5
);
return
new
HttpSystemProxyValue
()
{
HostName
=
endPoint
.
Split
(
':'
)[
0
],
Port
=
int
.
Parse
(
endPoint
.
Split
(
':'
)[
1
]),
IsSecure
=
false
};
}
else
if
(
tmp
.
StartsWith
(
"https="
))
{
var
endPoint
=
tmp
.
Substring
(
5
);
return
new
HttpSystemProxyValue
()
{
HostName
=
endPoint
.
Split
(
':'
)[
0
],
Port
=
int
.
Parse
(
endPoint
.
Split
(
':'
)[
1
]),
IsSecure
=
true
};
}
return
null
;
}
private
static
void
prepareRegistry
(
RegistryKey
reg
)
{
if
(
reg
.
GetValue
(
"ProxyEnable"
)
==
null
)
{
reg
.
SetValue
(
"ProxyEnable"
,
0
);
}
if
(
reg
.
GetValue
(
"ProxyServer"
)
==
null
||
reg
.
GetValue
(
"ProxyEnable"
)
as
string
==
"0"
)
{
reg
.
SetValue
(
"ProxyServer"
,
string
.
Empty
);
}
}
private
static
void
Refresh
()
{
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
InternetOptionSettingsChanged
,
IntPtr
.
Zero
,
0
);
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
InternetOptionSettingsChanged
,
IntPtr
.
Zero
,
0
);
NativeMethods
.
InternetSetOption
(
IntPtr
.
Zero
,
InternetOptionRefresh
,
IntPtr
.
Zero
,
0
);
}
}
...
...
Titanium.Web.Proxy/Helpers/Tcp.cs
View file @
7d115949
...
...
@@ -51,7 +51,7 @@ namespace Titanium.Web.Proxy.Helpers
try
{
sslStream
=
new
SslStream
(
tunnelStream
);
sslStream
.
AuthenticateAsClient
(
hostName
);
sslStream
.
AuthenticateAsClient
(
hostName
,
null
,
ProxyServer
.
SupportedProtocols
,
false
);
tunnelStream
=
sslStream
;
}
catch
...
...
@@ -69,10 +69,10 @@ namespace Titanium.Web.Proxy.Helpers
if
(
sb
!=
null
)
clientStream
.
CopyToAsync
(
sb
.
ToString
(),
tunnelStream
,
BUFFER_SIZE
);
else
clientStream
.
CopyToAsync
(
tunnelStream
,
BUFFER_SIZE
);
clientStream
.
CopyToAsync
(
string
.
Empty
,
tunnelStream
,
BUFFER_SIZE
);
});
var
receiveRelay
=
Task
.
Factory
.
StartNew
(()
=>
tunnelStream
.
CopyToAsync
(
clientStream
,
BUFFER_SIZE
));
var
receiveRelay
=
Task
.
Factory
.
StartNew
(()
=>
tunnelStream
.
CopyToAsync
(
string
.
Empty
,
clientStream
,
BUFFER_SIZE
));
Task
.
WaitAll
(
sendRelay
,
receiveRelay
);
}
...
...
Titanium.Web.Proxy/Models/EndPoint.cs
0 → 100644
View file @
7d115949
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Net.Sockets
;
using
System.Text
;
namespace
Titanium.Web.Proxy.Models
{
public
abstract
class
ProxyEndPoint
{
public
ProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
{
this
.
IpAddress
=
IpAddress
;
this
.
Port
=
Port
;
this
.
EnableSsl
=
EnableSsl
;
}
public
IPAddress
IpAddress
{
get
;
internal
set
;
}
public
int
Port
{
get
;
internal
set
;
}
public
bool
EnableSsl
{
get
;
internal
set
;
}
internal
TcpListener
listener
{
get
;
set
;
}
}
public
class
ExplicitProxyEndPoint
:
ProxyEndPoint
{
internal
bool
IsSystemHttpProxy
{
get
;
set
;
}
internal
bool
IsSystemHttpsProxy
{
get
;
set
;
}
public
List
<
string
>
ExcludedHttpsHostNameRegex
{
get
;
set
;
}
public
ExplicitProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
:
base
(
IpAddress
,
Port
,
EnableSsl
)
{
}
}
public
class
TransparentProxyEndPoint
:
ProxyEndPoint
{
//Name of the Certificate need to be sent (same as the hostname we want to proxy)
//This is valid only when UseServerNameIndication is set to false
public
string
GenericCertificateName
{
get
;
set
;
}
// public bool UseServerNameIndication { get; set; }
public
TransparentProxyEndPoint
(
IPAddress
IpAddress
,
int
Port
,
bool
EnableSsl
)
:
base
(
IpAddress
,
Port
,
EnableSsl
)
{
this
.
GenericCertificateName
=
"localhost"
;
}
}
}
Titanium.Web.Proxy/Network/TcpConnectionManager.cs
View file @
7d115949
...
...
@@ -9,6 +9,7 @@ using System.IO;
using
System.Net.Security
;
using
Titanium.Web.Proxy.Helpers
;
using
System.Threading
;
using
System.Security.Authentication
;
namespace
Titanium.Web.Proxy.Network
{
...
...
@@ -76,7 +77,7 @@ namespace Titanium.Web.Proxy.Network
try
{
sslStream
=
new
SslStream
(
stream
);
sslStream
.
AuthenticateAsClient
(
Hostname
);
sslStream
.
AuthenticateAsClient
(
Hostname
,
null
,
ProxyServer
.
SupportedProtocols
,
false
);
stream
=
(
Stream
)
sslStream
;
}
catch
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
7d115949
This diff is collapsed.
Click to expand it.
Titanium.Web.Proxy/RequestHandler.cs
View file @
7d115949
...
...
@@ -15,12 +15,14 @@ using Titanium.Web.Proxy.Extensions;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Network
;
using
Titanium.Web.Proxy.Models
;
using
System.Security.Cryptography.X509Certificates
;
namespace
Titanium.Web.Proxy
{
partial
class
ProxyServer
{
private
static
void
HandleClient
(
TcpClient
client
)
//This is called when client is aware of proxy
private
static
void
HandleClient
(
ExplicitProxyEndPoint
endPoint
,
TcpClient
client
)
{
Stream
clientStream
=
client
.
GetStream
();
var
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
Encoding
.
ASCII
);
...
...
@@ -51,10 +53,10 @@ namespace Titanium.Web.Proxy
var
httpVersion
=
httpCmdSplit
[
2
];
var
excluded
=
ExcludedHttpsHostNameRegex
.
Any
(
x
=>
Regex
.
IsMatch
(
httpRemoteUri
.
Host
,
x
))
;
var
excluded
=
endPoint
.
ExcludedHttpsHostNameRegex
!=
null
?
endPoint
.
ExcludedHttpsHostNameRegex
.
Any
(
x
=>
Regex
.
IsMatch
(
httpRemoteUri
.
Host
,
x
))
:
false
;
//Client wants to create a secure tcp tunnel (its a HTTPS request)
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
&&
!
excluded
&&
httpRemoteUri
.
Port
==
443
)
if
(
httpVerb
.
ToUpper
()
==
"CONNECT"
&&
!
excluded
&&
httpRemoteUri
.
Port
!=
80
)
{
httpRemoteUri
=
new
Uri
(
"https://"
+
httpCmdSplit
[
1
]);
clientStreamReader
.
ReadAllLines
();
...
...
@@ -68,9 +70,10 @@ namespace Titanium.Web.Proxy
try
{
sslStream
=
new
SslStream
(
clientStream
,
true
);
//Successfully managed to authenticate the client using the fake certificate
sslStream
.
AuthenticateAsServer
(
certificate
,
false
,
SslProtocols
.
Tls
|
SslProtocols
.
Ssl3
|
SslProtocols
.
Ssl2
,
false
);
SupportedProtocols
,
false
);
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
,
Encoding
.
ASCII
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
...
...
@@ -95,15 +98,18 @@ namespace Titanium.Web.Proxy
{
clientStreamReader
.
ReadAllLines
();
WriteConnectResponse
(
clientStreamWriter
,
httpVersion
);
TcpHelper
.
SendRaw
(
clientStreamReader
.
BaseStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
TcpHelper
.
SendRaw
(
clientStream
,
null
,
null
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
false
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
}
//Now create the request
HandleHttpSessionRequest
(
client
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
httpRemoteUri
.
OriginalString
:
null
);
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
?
true
:
false
);
}
catch
{
...
...
@@ -111,9 +117,61 @@ namespace Titanium.Web.Proxy
}
}
//This is called when requests are routed through router to this endpoint
//For ssl requests
private
static
void
HandleClient
(
TransparentProxyEndPoint
endPoint
,
TcpClient
tcpClient
)
{
Stream
clientStream
=
tcpClient
.
GetStream
();
CustomBinaryReader
clientStreamReader
=
null
;
StreamWriter
clientStreamWriter
=
null
;
X509Certificate2
certificate
=
null
;
if
(
endPoint
.
EnableSsl
)
{
var
sslStream
=
new
SslStream
(
clientStream
,
true
);
//if(endPoint.UseServerNameIndication)
//{
// //implement in future once SNI supported by SSL stream
// certificate = CertManager.CreateCertificate(endPoint.GenericCertificateName);
//}
//else
certificate
=
CertManager
.
CreateCertificate
(
endPoint
.
GenericCertificateName
);
try
{
//Successfully managed to authenticate the client using the fake certificate
sslStream
.
AuthenticateAsServer
(
certificate
,
false
,
SslProtocols
.
Tls
,
false
);
clientStreamReader
=
new
CustomBinaryReader
(
sslStream
,
Encoding
.
ASCII
);
clientStreamWriter
=
new
StreamWriter
(
sslStream
);
//HTTPS server created - we can now decrypt the client's traffic
}
catch
(
Exception
)
{
if
(
sslStream
!=
null
)
sslStream
.
Dispose
();
Dispose
(
tcpClient
,
sslStream
,
clientStreamReader
,
clientStreamWriter
,
null
);
return
;
}
clientStream
=
sslStream
;
}
else
{
clientStreamReader
=
new
CustomBinaryReader
(
clientStream
,
Encoding
.
ASCII
);
}
var
httpCmd
=
clientStreamReader
.
ReadLine
();
//Now create the request
HandleHttpSessionRequest
(
tcpClient
,
httpCmd
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
true
);
}
private
static
void
HandleHttpSessionRequest
(
TcpClient
client
,
string
httpCmd
,
Stream
clientStream
,
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
string
secureTunnelHostName
)
CustomBinaryReader
clientStreamReader
,
StreamWriter
clientStreamWriter
,
bool
IsHttps
)
{
TcpConnection
connection
=
null
;
string
lastRequestHostName
=
null
;
...
...
@@ -135,8 +193,8 @@ namespace Titanium.Web.Proxy
var
httpCmdSplit
=
httpCmd
.
Split
(
SpaceSplit
,
3
);
var
httpMethod
=
httpCmdSplit
[
0
];
var
httpRemoteUri
=
new
Uri
(
secureTunnelHostName
==
null
?
httpCmdSplit
[
1
]
:
(
secureTunnelHostName
+
httpCmdSplit
[
1
]));
var
httpVersion
=
httpCmdSplit
[
2
];
Version
version
;
...
...
@@ -149,11 +207,6 @@ namespace Titanium.Web.Proxy
version
=
new
Version
(
1
,
0
);
}
if
(
httpRemoteUri
.
Scheme
==
Uri
.
UriSchemeHttps
)
{
args
.
IsHttps
=
true
;
}
args
.
ProxySession
.
Request
.
RequestHeaders
=
new
List
<
HttpHeader
>();
...
...
@@ -166,10 +219,13 @@ namespace Titanium.Web.Proxy
SetRequestHeaders
(
args
.
ProxySession
.
Request
.
RequestHeaders
,
args
.
ProxySession
);
var
httpRemoteUri
=
new
Uri
(!
IsHttps
?
httpCmdSplit
[
1
]
:
(
string
.
Concat
(
"https://"
,
args
.
ProxySession
.
Request
.
Hostname
,
httpCmdSplit
[
1
])));
args
.
IsHttps
=
IsHttps
;
if
(
args
.
ProxySession
.
Request
.
UpgradeToWebSocket
)
{
TcpHelper
.
SendRaw
(
clientStream
Reader
.
BaseStream
,
httpCmd
,
args
.
ProxySession
.
Request
.
RequestHeaders
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
httpRemoteUri
.
Scheme
==
Uri
.
UriScheme
Https
);
TcpHelper
.
SendRaw
(
clientStream
,
httpCmd
,
args
.
ProxySession
.
Request
.
RequestHeaders
,
httpRemoteUri
.
Host
,
httpRemoteUri
.
Port
,
args
.
Is
Https
);
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
return
;
}
...
...
@@ -249,7 +305,7 @@ namespace Titanium.Web.Proxy
Dispose
(
client
,
clientStream
,
clientStreamReader
,
clientStreamWriter
,
args
);
break
;
}
}
if
(
connection
!=
null
)
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
7d115949
...
...
@@ -103,7 +103,7 @@ namespace Titanium.Web.Proxy
if
(
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
Contains
(
";"
))
{
response
.
Response
.
ContentType
=
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
Split
(
';'
)[
0
].
Trim
();
response
.
Response
.
CharacterSet
=
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
Split
(
';'
)[
1
].
ToLower
().
Replace
(
"charset="
,
string
.
Empty
).
Trim
();
response
.
Response
.
CharacterSet
=
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
Split
(
';'
)[
1
].
Substring
(
9
).
Trim
();
}
else
response
.
Response
.
ContentType
=
response
.
Response
.
ResponseHeaders
[
i
].
Value
.
ToLower
().
Trim
();
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
7d115949
...
...
@@ -33,7 +33,7 @@
<PropertyGroup
Condition=
"'$(Configuration)|$(Platform)' == 'Debug-Net45|AnyCPU'"
>
<DebugSymbols>
true
</DebugSymbols>
<OutputPath>
bin\Debug-Net45\
</OutputPath>
<DefineConstants>
DEBUG
</DefineConstants>
<DefineConstants>
DEBUG
;NET45
</DefineConstants>
<AllowUnsafeBlocks>
true
</AllowUnsafeBlocks>
<PlatformTarget>
AnyCPU
</PlatformTarget>
<CodeAnalysisRuleSet>
MinimumRecommendedRules.ruleset
</CodeAnalysisRuleSet>
...
...
@@ -44,6 +44,7 @@
<PlatformTarget>
AnyCPU
</PlatformTarget>
<CodeAnalysisRuleSet>
MinimumRecommendedRules.ruleset
</CodeAnalysisRuleSet>
<TargetFrameworkVersion>
v4.5
</TargetFrameworkVersion>
<DefineConstants>
NET45
</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference
Include=
"Ionic.Zip, Version=1.9.7.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL"
>
...
...
@@ -85,6 +86,7 @@
<Compile
Include=
"Helpers\CertificateManager.cs"
/>
<Compile
Include=
"Helpers\Firefox.cs"
/>
<Compile
Include=
"Helpers\SystemProxy.cs"
/>
<Compile
Include=
"Models\EndPoint.cs"
/>
<Compile
Include=
"Network\TcpExtensions.cs"
/>
<Compile
Include=
"Network\TcpConnectionManager.cs"
/>
<Compile
Include=
"Models\HttpHeader.cs"
/>
...
...
appveyor.yml
View file @
7d115949
...
...
@@ -7,7 +7,7 @@
# - Section names should be unique on each level.
# version format
version
:
1
.1.{build}
version
:
2
.1.{build}
shallow_clone
:
true
...
...
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