240 lines
8.8 KiB
C#
240 lines
8.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Net;
|
|
using System.Net.Security;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using Shadowsocks.Controller.Service;
|
|
using Shadowsocks.Model;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Serialization;
|
|
using Newtonsoft.Json.Converters;
|
|
|
|
|
|
namespace Shadowsocks.Controller
|
|
{
|
|
class OnlineConfigController
|
|
{
|
|
private string _cookie = null;
|
|
public string Url = "";
|
|
public string Type = "unknown";
|
|
public string LocalPublickey = "";
|
|
public string LocalPrivateKey = "";
|
|
public string RemotePubkey = "";
|
|
private KeyExchangeResponse KeyExchangeRes = null;
|
|
//public RSAHandler _rsa;
|
|
|
|
public OnlineConfigController(string Url)
|
|
{
|
|
this.Url = Url;
|
|
string[] Prefix = Url.Split(new char[3] { ':', '/', '/' });
|
|
switch (Prefix[0].ToLower())
|
|
{
|
|
case "http":
|
|
Type = "http";
|
|
break;
|
|
case "https":
|
|
Type = "https";
|
|
break;
|
|
default:
|
|
this.Url = "";
|
|
this.Type = "unknown";
|
|
break;
|
|
}
|
|
RSAHandler.GenerateKeyPair();
|
|
this.LocalPrivateKey = System.Environment.CurrentDirectory + "\\keys\\local.private.pem";
|
|
this.LocalPublickey = System.Environment.CurrentDirectory + "\\keys\\local.public.pem";
|
|
}
|
|
public Server[] GetOnlineConfig()
|
|
{
|
|
try
|
|
{
|
|
KeyExchangeResponse KeyExchangeResponse = this.KeyExchange(this.Url);
|
|
GetConfigResponse ConfigResponse = this.GetConfig();
|
|
return ConfigResponse.Config;
|
|
}
|
|
catch
|
|
{
|
|
throw;
|
|
}
|
|
|
|
}
|
|
private KeyExchangeResponse KeyExchange(string Url)
|
|
{
|
|
if(this.Url=="" || this.Type == "unknown")
|
|
{
|
|
throw new ArgumentException("Invalid Url");
|
|
}
|
|
StreamReader LocalPublicKeyStream = new StreamReader(this.LocalPublickey);
|
|
string LocalPublicKey = LocalPublicKeyStream.ReadToEnd();
|
|
LocalPublicKeyStream.Dispose();
|
|
HttpWebResponse res = CreatePostHttpResponse(this.Url, LocalPublicKey, _cookie);
|
|
if (res.StatusCode != HttpStatusCode.OK)
|
|
{
|
|
throw new ArgumentException("Invalid Status Code");
|
|
}
|
|
|
|
//string[] x = res.Headers.AllKeys;
|
|
|
|
string ResponseContent = "";
|
|
using (StreamReader sr = new StreamReader(res.GetResponseStream()))
|
|
{
|
|
ResponseContent = sr.ReadToEnd();
|
|
}
|
|
this._cookie = res.Headers.Get("Set-Cookie");
|
|
try
|
|
{
|
|
ResponseContent = RSAHandler.DecryptRSA(ResponseContent, this.LocalPrivateKey);
|
|
}
|
|
catch
|
|
{
|
|
throw;
|
|
}
|
|
StringReader reader = new StringReader(ResponseContent);
|
|
JsonSerializer serializer = new JsonSerializer();
|
|
KeyExchangeResponse response = (KeyExchangeResponse)serializer.Deserialize(new JsonTextReader(reader), typeof(KeyExchangeResponse));
|
|
this.KeyExchangeRes = response;
|
|
if(File.Exists(System.Environment.CurrentDirectory + "\\keys\\" + response.FingerPrint + ".pem"))
|
|
{
|
|
StreamReader stream = new StreamReader(System.Environment.CurrentDirectory + "\\keys\\" + response.FingerPrint + ".pem");
|
|
string LocalVersion = stream.ReadToEnd();
|
|
|
|
if (LocalVersion != response.ServerPublicKey)
|
|
{
|
|
throw new ArgumentException("Server Public Key Mismatch");
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
FileStream LocalVersion = File.Create(System.Environment.CurrentDirectory + "\\keys\\" + response.FingerPrint + ".pem");
|
|
LocalVersion.Write(System.Text.Encoding.Default.GetBytes(response.ServerPublicKey), 0, response.ServerPublicKey.Length);
|
|
LocalVersion.Close();
|
|
LocalVersion.Dispose();
|
|
}
|
|
this.RemotePubkey = System.Environment.CurrentDirectory + "\\keys\\" + response.FingerPrint + ".pem";
|
|
return response;
|
|
}
|
|
|
|
private GetConfigResponse GetConfig()
|
|
{
|
|
GetConfigRequest Request = new GetConfigRequest();
|
|
Request.decrypted_string = this.KeyExchangeRes.VerifyString;
|
|
char[] tempChr = new char[32];
|
|
Random rand = new Random();
|
|
for(int i = 0; i < 32; i++)
|
|
{
|
|
tempChr[i] = (char)rand.Next(61, 122);
|
|
}
|
|
Request.verify_string = new string(tempChr);
|
|
string RequestContent = JsonConvert.SerializeObject(Request);
|
|
string PostData = RSAHandler.EncryptRSA(RequestContent, this.RemotePubkey);
|
|
HttpWebResponse res;
|
|
string ResponseContent = "";
|
|
try
|
|
{
|
|
res = CreatePostHttpResponse(this.Url, PostData, this._cookie);
|
|
if (res.StatusCode != HttpStatusCode.OK)
|
|
{
|
|
throw new ArgumentException("Invalid Status Code");
|
|
}
|
|
|
|
using (StreamReader sr = new StreamReader(res.GetResponseStream()))
|
|
{
|
|
ResponseContent = sr.ReadToEnd();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
throw;
|
|
}
|
|
ResponseContent = RSAHandler.DecryptRSA(ResponseContent, this.LocalPrivateKey);
|
|
StringReader reader = new StringReader(ResponseContent);
|
|
JsonSerializer serializer = new JsonSerializer();
|
|
GetConfigResponse response = (GetConfigResponse)serializer.Deserialize(new JsonTextReader(reader), typeof(GetConfigResponse));
|
|
if (response.VerifyString != Request.verify_string)
|
|
{
|
|
throw new ArgumentException("Server Verify Fail");
|
|
}
|
|
for(int i = 0; i < response.Config.Length;i++)
|
|
{
|
|
response.Config[i].provider = response.Provider;
|
|
response.Config[i].fingerprint = this.KeyExchangeRes.FingerPrint;
|
|
}
|
|
return response;
|
|
}
|
|
|
|
public static HttpWebResponse CreatePostHttpResponse(string url, string postData,string cookies)
|
|
{
|
|
Encoding requestEncoding = Encoding.UTF8;
|
|
string UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36";
|
|
if (string.IsNullOrEmpty(url))
|
|
{
|
|
throw new ArgumentNullException("url");
|
|
}
|
|
if (requestEncoding == null)
|
|
{
|
|
throw new ArgumentNullException("requestEncoding");
|
|
}
|
|
HttpWebRequest request = null;
|
|
if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
|
|
request = WebRequest.Create(url) as HttpWebRequest;
|
|
request.ProtocolVersion = HttpVersion.Version10;
|
|
}
|
|
else
|
|
{
|
|
request = WebRequest.Create(url) as HttpWebRequest;
|
|
}
|
|
|
|
request.Method = "POST";
|
|
request.ContentType = "application/x-www-form-urlencoded";
|
|
|
|
|
|
request.UserAgent = UserAgent;
|
|
if (cookies != null)
|
|
{
|
|
request.Headers.Add(HttpRequestHeader.Cookie, cookies);
|
|
}
|
|
if (postData!="")
|
|
{
|
|
|
|
byte[] data = requestEncoding.GetBytes(postData);
|
|
try
|
|
{
|
|
using (Stream stream = request.GetRequestStream())
|
|
{
|
|
|
|
stream.Write(data, 0, data.Length);
|
|
}
|
|
|
|
}catch(Exception e)
|
|
{
|
|
throw new ArgumentException(e.Message);
|
|
}
|
|
|
|
}
|
|
HttpWebResponse res = null;
|
|
try
|
|
{
|
|
res = request.GetResponse() as HttpWebResponse;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new ArgumentException(e.Message);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|