mirror of
https://github.com/RaySollium99/MSNPSharp.git
synced 2025-09-03 21:57:44 -04:00
488 lines
19 KiB
C#
488 lines
19 KiB
C#
/*
|
|
Copyright ?2002, The KPD-Team
|
|
All rights reserved.
|
|
http://www.mentalis.org/
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
- Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
- Neither the name of the KPD-Team, nor the names of its contributors
|
|
may be used to endorse or promote products derived from this
|
|
software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Xml;
|
|
using System.Text;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.Security.Cryptography;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using System.Net;
|
|
using Org.Mentalis.Proxy;
|
|
using Org.Mentalis.Proxy.Socks.Authentication;
|
|
using System.Globalization;
|
|
|
|
namespace Org.Mentalis.Proxy {
|
|
/// <summary>
|
|
/// Stores the configuration settings of this proxy server.
|
|
/// </summary>
|
|
public sealed class ProxyConfig {
|
|
/// <summary>
|
|
/// Initializes a new ProxyConfig instance.
|
|
/// </summary>
|
|
/// <param name="parent">The parent of this ProxyCondif instance.</param>
|
|
/// <param name="file">The XML file to read data from and store data to.</param>
|
|
/// <exception cref="ArgumentNullException"><c>file</c> is null -or- <c>parent</c> is null.</exception>
|
|
public ProxyConfig(Proxy parent, string file) {
|
|
if (file == null || parent == null)
|
|
throw new ArgumentNullException();
|
|
m_File = file;
|
|
m_Parent = parent;
|
|
}
|
|
/// <summary>
|
|
/// Reads a string from the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key to read from.</param>
|
|
/// <returns>The string value that corresponds with the specified key, or an empty string if the specified key was not found in the collection.</returns>
|
|
public string ReadString(string name) {
|
|
return ReadString(name, "");
|
|
}
|
|
/// <summary>
|
|
/// Reads a string from the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key to read from.</param>
|
|
/// <param name="def">The default string to return.</param>
|
|
/// <returns>The string value that corresponds with the specified key, or <c>def</c> if the specified key was not found in the collection.</returns>
|
|
public string ReadString(string name, string def) {
|
|
if (name == null)
|
|
return def;
|
|
if (!Settings.ContainsKey(name))
|
|
return def;
|
|
return Settings[name];
|
|
}
|
|
/// <summary>
|
|
/// Reads a byte array from the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key to read from.</param>
|
|
/// <returns>The array of bytes that corresponds with the specified key, or <c>null</c> if the specified key was not found in the collection.</returns>
|
|
public byte[] ReadBytes(string name) {
|
|
string ret = ReadString(name, null);
|
|
if (ret == null)
|
|
return null;
|
|
return Convert.FromBase64String(ret);
|
|
}
|
|
/// <summary>
|
|
/// Reads an integer from the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key to read from.</param>
|
|
/// <returns>The integer that corresponds with the specified key, or 0 if the specified key was not found in the collection.</returns>
|
|
public int ReadInt(string name) {
|
|
return ReadInt(name, 0);
|
|
}
|
|
/// <summary>
|
|
/// Reads an integer from the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key to read from.</param>
|
|
/// <param name="def">The default integer to return.</param>
|
|
/// <returns>The integer that corresponds with the specified key, or <c>def</c> if the specified key was not found in the collection.</returns>
|
|
public int ReadInt(string name, int def) {
|
|
if (name == null)
|
|
return def;
|
|
if (!Settings.ContainsKey(name))
|
|
return def;
|
|
return int.Parse(Settings[name]);
|
|
}
|
|
/// <summary>
|
|
/// Saves a string to the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key of the setting.</param>
|
|
/// <param name="data">The string data of the setting.</param>
|
|
public void SaveSetting(string name, string data) {
|
|
SaveSetting(name, data, true);
|
|
}
|
|
/// <summary>
|
|
/// Saves a string to the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key of the setting.</param>
|
|
/// <param name="data">The string data of the setting.</param>
|
|
/// <param name="saveData">True if the data has to be written to the XML file, false otherwise.</param>
|
|
public void SaveSetting(string name, string data, bool saveData) {
|
|
if (name == null || data == null)
|
|
throw new ArgumentNullException();
|
|
if (Settings.ContainsKey(name))
|
|
Settings[name] = data;
|
|
else
|
|
Settings.Add(name, data);
|
|
if (saveData)
|
|
SaveData();
|
|
}
|
|
/// <summary>
|
|
/// Saves an integer to the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key of the setting.</param>
|
|
/// <param name="data">The integer data of the setting.</param>
|
|
public void SaveSetting(string name, int data) {
|
|
SaveSetting(name, data, true);
|
|
}
|
|
/// <summary>
|
|
/// Saves an integer to the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key of the setting.</param>
|
|
/// <param name="data">The integer data of the setting.</param>
|
|
/// <param name="saveData">True if the data has to be written to the XML file, false otherwise.</param>
|
|
public void SaveSetting(string name, int data, bool saveData) {
|
|
SaveSetting(name, data.ToString(), saveData);
|
|
}
|
|
/// <summary>
|
|
/// Saves an array of bytes to the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key of the setting.</param>
|
|
/// <param name="data">The byte data of the setting.</param>
|
|
public void SaveSetting(string name, byte [] data) {
|
|
SaveSetting(name, data, true);
|
|
}
|
|
/// <summary>
|
|
/// Saves an array of bytes to the settings section.
|
|
/// </summary>
|
|
/// <param name="name">The key of the setting.</param>
|
|
/// <param name="data">The byte data of the setting.</param>
|
|
/// <param name="saveData">True if the data has to be written to the XML file, false otherwise.</param>
|
|
public void SaveSetting(string name, byte [] data, bool saveData) {
|
|
if (data == null)
|
|
throw new ArgumentNullException();
|
|
SaveSetting(name, Convert.ToBase64String(data), saveData);
|
|
}
|
|
/// <summary>
|
|
/// Saves a username and password combination to the authentication list.
|
|
/// </summary>
|
|
/// <param name="username">The username to add.</param>
|
|
/// <param name="password">The password to add.</param>
|
|
/// <exception cref="ArgumentNullException"><c>username</c> is null -or- <c>password</c> is null.</exception>
|
|
/// <exception cref="ArgumentException">The specified username is invalid.</exception>
|
|
/// <remarks><p>If the user already exists in the collection, the old password will be changed to the new one.</p><p>The username 'users' is invalid because it is used internally to store the usernames.</p></remarks>
|
|
public void SaveUserPass(string username, string password) {
|
|
SaveUserPass(username, password, true);
|
|
}
|
|
/// <summary>
|
|
/// Saves a username and password combination to the authentication list.
|
|
/// </summary>
|
|
/// <param name="username">The username to add.</param>
|
|
/// <param name="password">The password to add.</param>
|
|
/// <param name="saveData">True if the data has to be written to the XML file, false otherwise.</param>
|
|
/// <exception cref="ArgumentNullException"><c>username</c> is null -or- <c>password</c> is null.</exception>
|
|
/// <exception cref="ArgumentException">The specified username is invalid.</exception>
|
|
/// <remarks><p>If the user already exists in the collection, the old password will be changed to the new one.</p><p>The username 'users' is invalid because it is used internally to store the usernames.</p><p>The password will be hashed before it is stored in the authentication list.</p></remarks>
|
|
public void SaveUserPass(string username, string password, bool saveData) {
|
|
if (username == null || password == null)
|
|
throw new ArgumentNullException();
|
|
if (username.ToLower(CultureInfo.InvariantCulture) == "users" || username == "")
|
|
throw new ArgumentException();
|
|
if (UserList.IsUserPresent(username))
|
|
UserList.RemoveItem(username);
|
|
UserList.AddItem(username, password);
|
|
if (saveData)
|
|
SaveData();
|
|
}
|
|
/// <summary>
|
|
/// Saves a username and password hash combination to the authentication list.
|
|
/// </summary>
|
|
/// <param name="username">The username to add.</param>
|
|
/// <param name="passHash">The password hash to add.</param>
|
|
/// <exception cref="ArgumentNullException"><c>username</c> is null -or- <c>passHash</c> is null.</exception>
|
|
/// <exception cref="ArgumentException">The specified username is invalid.</exception>
|
|
/// <remarks><p>If the user already exists in the collection, the old password hash will be changed to the new one.</p><p>The username 'users' is invalid because it is used internally to store the usernames.</p><p>The password will <em>not</em> be hashed before it is stored in the authentication list. The user must make sure it is a valid MD5 hash.</p></remarks>
|
|
public void SaveUserHash(string username, string passHash) {
|
|
SaveUserHash(username, passHash, true);
|
|
}
|
|
/// <summary>
|
|
/// Saves a username and password hash combination to the authentication list.
|
|
/// </summary>
|
|
/// <param name="username">The username to add.</param>
|
|
/// <param name="passHash">The password hash to add.</param>
|
|
/// <param name="saveData">True if the data has to be written to the XML file, false otherwise.</param>
|
|
/// <exception cref="ArgumentNullException"><c>username</c> is null -or- <c>passHash</c> is null.</exception>
|
|
/// <exception cref="ArgumentException">The specified username is invalid.</exception>
|
|
/// <remarks><p>If the user already exists in the collection, the old password hash will be changed to the new one.</p><p>The username 'users' is invalid because it is used internally to store the usernames.</p><p>The password will <em>not</em> be hashed before it is stored in the authentication list. The user must make sure it is a valid MD5 hash.</p></remarks>
|
|
public void SaveUserHash(string username, string passHash, bool saveData) {
|
|
if (username == null || passHash == null)
|
|
throw new ArgumentNullException();
|
|
if (username.ToLower(CultureInfo.InvariantCulture) == "users" || username == "")
|
|
throw new ArgumentException();
|
|
UserList.AddHash(username, passHash);
|
|
if (saveData)
|
|
SaveData();
|
|
}
|
|
/// <summary>
|
|
/// Removes a user from the authentication list.
|
|
/// </summary>
|
|
/// <param name="user">The user to remove.</param>
|
|
public void RemoveUser(string user) {
|
|
RemoveUser(user, true);
|
|
}
|
|
/// <summary>
|
|
/// Removes a user from the authentication list.
|
|
/// </summary>
|
|
/// <param name="user">The user to remove.</param>
|
|
/// <param name="save">True if the data has to be written to the XML file, false otherwise.</param>
|
|
public void RemoveUser(string user, bool save) {
|
|
if (user == null)
|
|
throw new ArgumentNullException();
|
|
UserList.RemoveItem(user);
|
|
if (save)
|
|
SaveData();
|
|
}
|
|
/// <summary>
|
|
/// Saves the data in this class to an XML file.
|
|
/// </summary>
|
|
public void SaveData() {
|
|
XmlTextWriter writer = null;
|
|
try {
|
|
writer = new XmlTextWriter(File, Encoding.ASCII);
|
|
writer.Indentation = 2;
|
|
writer.Formatting = Formatting.Indented;
|
|
writer.WriteStartElement("MentalisProxy");
|
|
// Write the version
|
|
writer.WriteStartElement("Version");
|
|
writer.WriteStartAttribute("", "value", "");
|
|
writer.WriteString(Assembly.GetCallingAssembly().GetName().Version.ToString(2));
|
|
writer.WriteEndAttribute();
|
|
writer.WriteEndElement();
|
|
// Write the settings
|
|
SaveSettings(writer);
|
|
// Write the Authentication list to the file
|
|
SaveUsers(writer);
|
|
// Write the Listeners list to the file
|
|
SaveListeners(writer);
|
|
// Clean up
|
|
writer.WriteEndElement();
|
|
} catch {
|
|
} finally {
|
|
if (writer != null)
|
|
writer.Close();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Saves the settings in this class to an XML writer.
|
|
/// </summary>
|
|
/// <param name="writer">The XML writer to save the data to.</param>
|
|
private void SaveSettings(XmlTextWriter writer) {
|
|
writer.WriteStartElement("Settings");
|
|
string [] keys = new string[Settings.Count];
|
|
Settings.Keys.CopyTo(keys, 0);
|
|
for (int i = 0; i < keys.Length; i++) {
|
|
writer.WriteStartElement(keys[i]);
|
|
writer.WriteStartAttribute("", "value", "");
|
|
writer.WriteString(Settings[keys[i]]);
|
|
writer.WriteEndAttribute();
|
|
writer.WriteEndElement();
|
|
}
|
|
writer.WriteEndElement();
|
|
}
|
|
/// <summary>
|
|
/// Saves the authentication list to an XML writer.
|
|
/// </summary>
|
|
/// <param name="writer">The XML writer to save the users to.</param>
|
|
private void SaveUsers(XmlTextWriter writer) {
|
|
writer.WriteStartElement("Users");
|
|
string [] keys = UserList.Keys;
|
|
string [] hashes = UserList.Hashes;
|
|
for (int i = 0; i < keys.Length; i++) {
|
|
writer.WriteStartElement(keys[i]);
|
|
writer.WriteStartAttribute("", "value", "");
|
|
writer.WriteString(hashes[i]);
|
|
writer.WriteEndAttribute();
|
|
writer.WriteEndElement();
|
|
}
|
|
writer.WriteEndElement();
|
|
}
|
|
/// <summary>
|
|
/// Saves the listeners to an XML writer.
|
|
/// </summary>
|
|
/// <param name="writer">The XML writer to save the users to.</param>
|
|
private void SaveListeners(XmlTextWriter writer) {
|
|
writer.WriteStartElement("Listeners");
|
|
lock (Parent) {
|
|
for (int i = 0; i < Parent.ListenerCount; i++) {
|
|
writer.WriteStartElement("listener");
|
|
// Write the type, eg 'Org.Mentalis.Proxy.Http.HttpListener'
|
|
writer.WriteStartAttribute("", "type", "");
|
|
writer.WriteString(Parent[i].GetType().FullName);
|
|
writer.WriteEndAttribute();
|
|
// Write the construction string
|
|
writer.WriteStartAttribute("", "value", "");
|
|
writer.WriteString(Parent[i].ConstructString);
|
|
writer.WriteEndAttribute();
|
|
writer.WriteEndElement();
|
|
}
|
|
}
|
|
writer.WriteEndElement();
|
|
}
|
|
/// <summary>
|
|
/// Loads the data from an XML file.
|
|
/// </summary>
|
|
public void LoadData() {
|
|
if (!System.IO.File.Exists(File))
|
|
throw new FileNotFoundException();
|
|
XmlTextReader reader = null;
|
|
try {
|
|
reader = new XmlTextReader(File);
|
|
// Read until we reach the MentalisProxy element
|
|
while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "mentalisproxy") {}
|
|
// Read until we reach the MentalisProxy element again (the end tag)
|
|
while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "mentalisproxy") {
|
|
if (!reader.IsEmptyElement) {
|
|
switch(reader.Name.ToLower(CultureInfo.InvariantCulture)) {
|
|
case "settings":
|
|
Settings.Clear();
|
|
LoadSettings(reader);
|
|
break;
|
|
case "users":
|
|
UserList.Clear();
|
|
LoadUsers(reader);
|
|
break;
|
|
case "listeners":
|
|
LoadListeners(reader);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} catch {
|
|
throw new XmlException ("Malformed XML initialisation file.", null);
|
|
} finally {
|
|
if (reader != null)
|
|
reader.Close();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Loads the settings from an XML file.
|
|
/// </summary>
|
|
/// <param name="reader">The XML reader to read the settings from.</param>
|
|
private void LoadSettings(XmlTextReader reader) {
|
|
// Read until we reach the Settings element end tag
|
|
while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "settings") {
|
|
if (reader.Name != null && reader["value"] != null)
|
|
SaveSetting(reader.Name, reader["value"], false);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Loads the userlist from an XML file.
|
|
/// </summary>
|
|
/// <param name="reader">The XML reader to read the users from.</param>
|
|
private void LoadUsers(XmlTextReader reader) {
|
|
// Read until we reach the Settings element end tag
|
|
while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "users") {
|
|
if (reader.Name != null && reader["value"] != null)
|
|
SaveUserHash(reader.Name, reader["value"], false);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Loads the listeners list from an XML file.
|
|
/// </summary>
|
|
/// <param name="reader">The XML reader to read the users from.</param>
|
|
private void LoadListeners(XmlTextReader reader) {
|
|
// Read until we reach the Listeners element end tag
|
|
Listener listener = null;
|
|
while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "listeners") {
|
|
if (reader.Name != null && reader["value"] != null && reader["type"] != null) {
|
|
listener = Parent.CreateListener(reader["type"], reader["value"]);
|
|
if (listener != null) {
|
|
try {
|
|
listener.Start();
|
|
} catch {}
|
|
Parent.AddListener(listener);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Gets the full path to the XML data file.
|
|
/// </summary>
|
|
/// <value>A String that holds the full path to the XML data file.</value>
|
|
public string File {
|
|
get {
|
|
return m_File;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Gets the parent object of this ProxyConfig class.
|
|
/// </summary>
|
|
/// <value>An instance of the Proxy class.</value>
|
|
public Proxy Parent {
|
|
get {
|
|
return m_Parent;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Gets the dictionary that holds the settings.
|
|
/// </summary>
|
|
/// <value>An instance of the StringDictionary class that holds the settings.</value>
|
|
private StringDictionary Settings {
|
|
get {
|
|
return m_Settings;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Gets the userlist.
|
|
/// </summary>
|
|
/// <value>An instance of the AuthenticationList class that holds all the users and their corresponding password hashes.</value>
|
|
internal AuthenticationList UserList {
|
|
get {
|
|
return m_UserList;
|
|
}
|
|
}
|
|
// private variables
|
|
/// <summary>Holds the value of the File property.</summary>
|
|
private string m_File;
|
|
/// <summary>Holds the value of the Settings property.</summary>
|
|
private StringDictionary m_Settings = new StringDictionary();
|
|
/// <summary>Holds the value of the UserList property.</summary>
|
|
private AuthenticationList m_UserList = new AuthenticationList();
|
|
/// <summary>Holds the value of the Parent property.</summary>
|
|
private Proxy m_Parent;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
<MentalisProxy>
|
|
<Version value="1.0" />
|
|
<Settings>
|
|
<authorize value="never" />
|
|
<admin_hash value="Gh3JHJBzJcaScd3wyUS8cg==" />
|
|
<config_ip value="localhost" />
|
|
<config_port value="4" />
|
|
<errorlog value="errors.log" />
|
|
</Settings>
|
|
<Users>
|
|
<user value="myhash" />
|
|
<pieter value="WhBei51A4TKXgNYuoiZdig==" />
|
|
<kris value="X03MO1qnZdYdgyfeuILPmQ==" />
|
|
</Users>
|
|
<Listeners>
|
|
<listener type="Org.Mentalis.Proxy.Http.HttpListener" value="host:0.0.0.0;int:100" />
|
|
<listener type="Org.Mentalis.Proxy.Ftp.FtpListener" value="host:0.0.0.0;int:21" />
|
|
<listener type="Org.Mentalis.Proxy.Socks.SocksListener" value="host:0.0.0.0;int:1080;authlist" />
|
|
<listener type="Org.Mentalis.Proxy.PortMap.PortMapListener" value="host:0.0.0.0;int:12345;host:msnews.microsoft.com;int:119" />
|
|
</Listeners>
|
|
</MentalisProxy>
|
|
*/
|