From 1432945d7380911983a4bbd7d85913b06aa9e75b Mon Sep 17 00:00:00 2001 From: savissimo Date: Thu, 8 Feb 2018 09:51:05 +0100 Subject: [PATCH] First import --- README.md | 26 +++- src/Desktop/App.config | 6 + src/Desktop/App.xaml | 8 ++ src/Desktop/App.xaml.cs | 35 +++++ .../Controls/PersistentOpenFileDialog.cs | 39 ++++++ src/Desktop/DebugConverter.cs | 22 +++ src/Desktop/Desktop.csproj | 130 ++++++++++++++++++ src/Desktop/Properties/AssemblyInfo.cs | 55 ++++++++ src/Desktop/Properties/Resources.Designer.cs | 71 ++++++++++ src/Desktop/Properties/Resources.resx | 117 ++++++++++++++++ src/Desktop/Properties/Settings.Designer.cs | 30 ++++ src/Desktop/Properties/Settings.settings | 7 + src/Desktop/ViewModel/ViewModelLocator.cs | 61 ++++++++ src/Desktop/ViewModels/MainViewModel.cs | 104 ++++++++++++++ .../ViewModels/ViewModelBaseExtensions.cs | 13 ++ src/Desktop/Views/MainWindow.xaml | 80 +++++++++++ src/Desktop/Views/MainWindow.xaml.cs | 15 ++ src/Desktop/app.manifest | 77 +++++++++++ src/Desktop/packages.config | 6 + src/Desktop/test/test.rtxml | 33 +++++ src/RoutingTableManager.sln | 28 ++++ src/RoutingTableManager/Host.cs | 125 +++++++++++++++++ src/RoutingTableManager/Interface.cs | 55 ++++++++ .../Properties/AssemblyInfo.cs | 36 +++++ src/RoutingTableManager/Route.cs | 94 +++++++++++++ src/RoutingTableManager/RoutingTable.cs | 73 ++++++++++ .../RoutingTableManager.csproj | 51 +++++++ src/RoutingTableManager/Shell.cs | 25 ++++ 28 files changed, 1421 insertions(+), 1 deletion(-) create mode 100644 src/Desktop/App.config create mode 100644 src/Desktop/App.xaml create mode 100644 src/Desktop/App.xaml.cs create mode 100644 src/Desktop/Controls/PersistentOpenFileDialog.cs create mode 100644 src/Desktop/DebugConverter.cs create mode 100644 src/Desktop/Desktop.csproj create mode 100644 src/Desktop/Properties/AssemblyInfo.cs create mode 100644 src/Desktop/Properties/Resources.Designer.cs create mode 100644 src/Desktop/Properties/Resources.resx create mode 100644 src/Desktop/Properties/Settings.Designer.cs create mode 100644 src/Desktop/Properties/Settings.settings create mode 100644 src/Desktop/ViewModel/ViewModelLocator.cs create mode 100644 src/Desktop/ViewModels/MainViewModel.cs create mode 100644 src/Desktop/ViewModels/ViewModelBaseExtensions.cs create mode 100644 src/Desktop/Views/MainWindow.xaml create mode 100644 src/Desktop/Views/MainWindow.xaml.cs create mode 100644 src/Desktop/app.manifest create mode 100644 src/Desktop/packages.config create mode 100644 src/Desktop/test/test.rtxml create mode 100644 src/RoutingTableManager.sln create mode 100644 src/RoutingTableManager/Host.cs create mode 100644 src/RoutingTableManager/Interface.cs create mode 100644 src/RoutingTableManager/Properties/AssemblyInfo.cs create mode 100644 src/RoutingTableManager/Route.cs create mode 100644 src/RoutingTableManager/RoutingTable.cs create mode 100644 src/RoutingTableManager/RoutingTableManager.csproj create mode 100644 src/RoutingTableManager/Shell.cs diff --git a/README.md b/README.md index 7a37280..907abdc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,26 @@ -# routingtablemanager +# Routing Table Manager + A tool to quickly add entries to the Windows routing table. Host names are resolved with DNS for user convenience. + +## Features + +* Routing entries may specify a destination and a gateway either as an IP address or as a host name, which will be resolved with DNS +* Routing entries can point to a specific network interface +* Projects contain multiple routing entries, so you can group them and enable them at once +* Command-line parameter allows to apply all the entries of a project without opening the UI +* It needs a Windows account with elevated privileges + +## Project status + +The tool is now functional, at least as to what I need it for. It was meant as a quick and convenient way to add entries to the system routing table, and that it does. + +**I don't plan to refine it any further**. I have no interest in new features or in a nicer UI, and I am caught in several other projects. + +### "Then why did you put it here?!" + +Because I'm a nice guy ;) + +Just because I have no plans for this project, it doesn't mean _you_ have none! I decided to open this project for three main reasons: +1. so that people can use it, if they need to. They can't if it sits on my hard drive; +2. so that people can point out problems. What works for me may not work for you; +3. so that people can pick up from here and improve it themselves :) diff --git a/src/Desktop/App.config b/src/Desktop/App.config new file mode 100644 index 0000000..d740e88 --- /dev/null +++ b/src/Desktop/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Desktop/App.xaml b/src/Desktop/App.xaml new file mode 100644 index 0000000..31016dc --- /dev/null +++ b/src/Desktop/App.xaml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Desktop/App.xaml.cs b/src/Desktop/App.xaml.cs new file mode 100644 index 0000000..bea0853 --- /dev/null +++ b/src/Desktop/App.xaml.cs @@ -0,0 +1,35 @@ +using Desktop.ViewModels; +using Desktop.Views; +using RoutingTableManager; +using System.IO; +using System.Windows; + +namespace Desktop +{ + /// + /// Logica di interazione per App.xaml + /// + public partial class App : Application + { + private void Application_Startup(object sender, StartupEventArgs e) + { + if (e.Args.Length > 0) + { + if (File.Exists(e.Args[0])) + { + RoutingTable routingTable = new RoutingTable(); + routingTable.LoadFromXml(e.Args[0]); + routingTable.ApplyToSystem(); + MessageBox.Show("All routes applied."); + } + + Application.Current.Shutdown(); + } + + MainViewModel mvm = new MainViewModel(); + MainWindow mv = new MainWindow(); + mvm.BindView(mv); + mv.Show(); + } + } +} diff --git a/src/Desktop/Controls/PersistentOpenFileDialog.cs b/src/Desktop/Controls/PersistentOpenFileDialog.cs new file mode 100644 index 0000000..1446016 --- /dev/null +++ b/src/Desktop/Controls/PersistentOpenFileDialog.cs @@ -0,0 +1,39 @@ +using Microsoft.Win32; +using System.IO; + +namespace Desktop.Controls +{ + public class PersistentOpenFileDialog + { + OpenFileDialog m_ofd = new OpenFileDialog(); + string m_persistentDirectory = null; + + public PersistentOpenFileDialog() + { + m_ofd.CheckFileExists = true; + m_ofd.CheckPathExists = true; + m_ofd.ReadOnlyChecked = true; + } + + public bool? ShowDialog() + { + if (m_persistentDirectory != null) + { + m_ofd.InitialDirectory = m_persistentDirectory; + } + bool? retval = m_ofd.ShowDialog(); + if (retval == true) + { + m_persistentDirectory = new FileInfo(FileName).DirectoryName; + } + + return retval; + } + + public string FileName + { + get { return m_ofd.FileName; } + set { m_ofd.FileName = value; } + } + } +} diff --git a/src/Desktop/DebugConverter.cs b/src/Desktop/DebugConverter.cs new file mode 100644 index 0000000..2c3e298 --- /dev/null +++ b/src/Desktop/DebugConverter.cs @@ -0,0 +1,22 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.Windows.Data; + +namespace Desktop +{ + class DebugConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + Debugger.Break(); + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + Debugger.Break(); + return value; + } + } +} diff --git a/src/Desktop/Desktop.csproj b/src/Desktop/Desktop.csproj new file mode 100644 index 0000000..52d5611 --- /dev/null +++ b/src/Desktop/Desktop.csproj @@ -0,0 +1,130 @@ + + + + + Debug + AnyCPU + {15569582-A792-40B2-84EE-44184B93EAF2} + WinExe + Desktop + RoutingTableManager + v4.5.2 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + app.manifest + + + + ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.dll + + + ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Extras.dll + + + ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Platform.dll + + + ..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll + + + + + ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\System.Windows.Interactivity.dll + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + + + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + Designer + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + {A6436D0A-491C-4D6F-82FA-8222CE3CD93B} + RoutingTableManager + + + + \ No newline at end of file diff --git a/src/Desktop/Properties/AssemblyInfo.cs b/src/Desktop/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..43d0e54 --- /dev/null +++ b/src/Desktop/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// Le informazioni generali relative a un assembly sono controllate dal seguente +// set di attributi. Modificare i valori di questi attributi per modificare le informazioni +// associate a un assembly. +[assembly: AssemblyTitle("Routing Table Manager")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Routing Table Manager")] +[assembly: AssemblyCopyright("Copyright © Simone Saviolo 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Se si imposta ComVisible su false, i tipi in questo assembly non saranno visibili +// ai componenti COM. Se è necessario accedere a un tipo in questo assembly da +// COM, impostare su true l'attributo ComVisible per tale tipo. +[assembly: ComVisible(false)] + +//Per iniziare a creare applicazioni localizzabili, impostare +//CultureYouAreCodingWith nel file .csproj +//all'interno di un . Ad esempio, se si utilizza l'inglese (Stati Uniti) +//nei file di origine, impostare su en-US. Rimuovere quindi il commento dall'attributo +//NeutralResourceLanguage riportato di seguito. Aggiornare "en-US" nella +//riga sottostante in modo che corrisponda all'impostazione UICulture nel file di progetto. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //dove si trovano i dizionari delle risorse specifiche del tema + //(da usare se nella pagina non viene trovata una risorsa, + // oppure nei dizionari delle risorse dell'applicazione) + ResourceDictionaryLocation.SourceAssembly //dove si trova il dizionario delle risorse generiche + //(da usare se nella pagina non viene trovata una risorsa, + // nell'applicazione o nei dizionari delle risorse specifiche del tema) +)] + + +// Le informazioni sulla versione di un assembly sono costituite dai seguenti quattro valori: +// +// Versione principale +// Versione secondaria +// Numero di build +// Revisione +// +// È possibile specificare tutti i valori oppure impostare valori predefiniti per i numeri relativi alla revisione e alla build +// usando l'asterisco '*' come illustrato di seguito: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Desktop/Properties/Resources.Designer.cs b/src/Desktop/Properties/Resources.Designer.cs new file mode 100644 index 0000000..d8e10b5 --- /dev/null +++ b/src/Desktop/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// Codice generato da uno strumento. +// Versione runtime:4.0.30319.42000 +// +// Le modifiche apportate a questo file possono causare un comportamento non corretto e andranno perse se +// il codice viene rigenerato. +// +//------------------------------------------------------------------------------ + +namespace Desktop.Properties +{ + + + /// + /// Classe di risorse fortemente tipizzata per la ricerca di stringhe localizzate e così via. + /// + // Questa classe è stata generata automaticamente dalla classe StronglyTypedResourceBuilder + // tramite uno strumento quale ResGen o Visual Studio. + // Per aggiungere o rimuovere un membro, modificare il file .ResX, quindi eseguire di nuovo ResGen + // con l'opzione /str oppure ricompilare il progetto VS. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Restituisce l'istanza di ResourceManager memorizzata nella cache e usata da questa classe. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Desktop.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Esegue l'override della proprietà CurrentUICulture del thread corrente per tutte + /// le ricerche di risorse che utilizzano questa classe di risorse fortemente tipizzata. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/src/Desktop/Properties/Resources.resx b/src/Desktop/Properties/Resources.resx new file mode 100644 index 0000000..ffecec8 --- /dev/null +++ b/src/Desktop/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Desktop/Properties/Settings.Designer.cs b/src/Desktop/Properties/Settings.Designer.cs new file mode 100644 index 0000000..aa5057f --- /dev/null +++ b/src/Desktop/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Desktop.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/src/Desktop/Properties/Settings.settings b/src/Desktop/Properties/Settings.settings new file mode 100644 index 0000000..8f2fd95 --- /dev/null +++ b/src/Desktop/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/Desktop/ViewModel/ViewModelLocator.cs b/src/Desktop/ViewModel/ViewModelLocator.cs new file mode 100644 index 0000000..03e5631 --- /dev/null +++ b/src/Desktop/ViewModel/ViewModelLocator.cs @@ -0,0 +1,61 @@ +/* + In App.xaml: + + + + + In the View: + DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelName}" + + You can also use Blend to do all this with the tool's support. + See http://www.galasoft.ch/mvvm +*/ + +using Desktop.ViewModels; +using GalaSoft.MvvmLight.Ioc; +using Microsoft.Practices.ServiceLocation; + +namespace Desktop.ViewModel +{ + /// + /// This class contains static references to all the view models in the + /// application and provides an entry point for the bindings. + /// + public class ViewModelLocator + { + /// + /// Initializes a new instance of the ViewModelLocator class. + /// + public ViewModelLocator() + { + ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); + + ////if (ViewModelBase.IsInDesignModeStatic) + ////{ + //// // Create design time view services and models + //// SimpleIoc.Default.Register(); + ////} + ////else + ////{ + //// // Create run time view services and models + //// SimpleIoc.Default.Register(); + ////} + + SimpleIoc.Default.Register(); + } + + public MainViewModel Main + { + get + { + return ServiceLocator.Current.GetInstance(); + } + } + + public static void Cleanup() + { + // TODO Clear the ViewModels + } + } +} \ No newline at end of file diff --git a/src/Desktop/ViewModels/MainViewModel.cs b/src/Desktop/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..f8263ed --- /dev/null +++ b/src/Desktop/ViewModels/MainViewModel.cs @@ -0,0 +1,104 @@ +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.Command; +using RoutingTableManager; +using System.Collections.ObjectModel; +using System.Net; +using System; +using Desktop.Controls; +using Microsoft.Win32; +using System.Windows; + +namespace Desktop.ViewModels +{ + public class MainViewModel : ViewModelBase + { + public ObservableCollection Routes { get { return m_routes; } } + public ObservableCollection AvailableInterfaces { get { return m_availableInterfaces; } } + + private RoutingTable m_routingTable = null; + private ObservableCollection m_routes = null; + + private ObservableCollection m_availableInterfaces = null; + + public RelayCommand LoadRoutingTableFromSystemCommand { get; set; } + public RelayCommand LoadRoutingTableFromFileCommand { get; set; } + public RelayCommand SaveRoutingTableToFileCommand { get; set; } + public RelayCommand UpdateDNSResolvedNamesCommand { get; set; } + public RelayCommand ApplyRoutingTableCommand { get; set; } + + private PersistentOpenFileDialog m_ofd = new PersistentOpenFileDialog(); + + public MainViewModel() + { + if (IsInDesignMode) + { + m_routingTable = new RoutingTable(); + m_routingTable.Routes.Add(new Route(IPAddress.Parse("1.2.3.4"))); + m_routingTable.Routes.Add(new Route(IPAddress.Parse("5.6.7.8"), "example.test")); + m_routingTable.Routes.Add(new Route()); + + m_availableInterfaces = new ObservableCollection(); + m_availableInterfaces.Add(new Interface { Index = 1, Metric = 10, Name = "Prima", Status = Interface.InterfaceStatus.Disconnected, MTU = 1500 }); + m_availableInterfaces.Add(new Interface { Index = 2, Metric = 20, Name = "Seconda", Status = Interface.InterfaceStatus.Connected, MTU = 1500 }); + m_availableInterfaces.Add(new Interface { Index = 3, Metric = 50, Name = "Terza", Status = Interface.InterfaceStatus.Disconnected, MTU = 1500 }); + } + else + { + m_routingTable = new RoutingTable(); + m_availableInterfaces = new ObservableCollection(Interface.GetAvailableInterfaces()); + } + + UpdateRoutes(); + + LoadRoutingTableFromFileCommand = new RelayCommand(LoadRoutingTableFromFile); + SaveRoutingTableToFileCommand = new RelayCommand(SaveRoutingTableToFile); + ApplyRoutingTableCommand = new RelayCommand(ApplyRoutingTable); + UpdateDNSResolvedNamesCommand = new RelayCommand(UpdateDNSResolvedNames); + } + + private void UpdateRoutes() + { + m_routes = new ObservableCollection(m_routingTable.Routes); + RaisePropertyChanged(nameof(Routes)); + } + + private void LoadRoutingTableFromFile() + { + if (m_ofd.ShowDialog() == true) + { + m_routingTable.LoadFromXml(m_ofd.FileName); + UpdateRoutes(); + } + } + + private void SaveRoutingTableToFile() + { + SaveFileDialog sfd = new SaveFileDialog(); + sfd.AddExtension = true; + sfd.DefaultExt = "rtxml"; + if (sfd.ShowDialog() == true) + { + m_routingTable.SaveToXml(sfd.FileName); + } + } + + private void ApplyRoutingTable() + { + if (m_routingTable != null) + { + m_routingTable.ApplyToSystem(); + MessageBox.Show("All routes applied."); + } + } + + private void UpdateDNSResolvedNames() + { + if (m_routingTable != null) + { + m_routingTable.UpdateDNSResolvedNames(); + UpdateRoutes(); + MessageBox.Show("All Host Names have been looked up."); + } + } + } +} diff --git a/src/Desktop/ViewModels/ViewModelBaseExtensions.cs b/src/Desktop/ViewModels/ViewModelBaseExtensions.cs new file mode 100644 index 0000000..b34eb1b --- /dev/null +++ b/src/Desktop/ViewModels/ViewModelBaseExtensions.cs @@ -0,0 +1,13 @@ +using GalaSoft.MvvmLight; +using System.Windows.Controls; + +namespace Desktop.ViewModels +{ + static class ViewModelBaseExtensions + { + public static void BindView(this ViewModelBase viewModel, Control i_control) + { + i_control.DataContext = viewModel; + } + } +} diff --git a/src/Desktop/Views/MainWindow.xaml b/src/Desktop/Views/MainWindow.xaml new file mode 100644 index 0000000..2c824b3 --- /dev/null +++ b/src/Desktop/Views/MainWindow.xaml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Destination + + + + + + Gateway + + + + + + Interface + + + + + + + + + + + + + + diff --git a/src/Desktop/Views/MainWindow.xaml.cs b/src/Desktop/Views/MainWindow.xaml.cs new file mode 100644 index 0000000..58562c6 --- /dev/null +++ b/src/Desktop/Views/MainWindow.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows; + +namespace Desktop.Views +{ + /// + /// Logica di interazione per MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} diff --git a/src/Desktop/app.manifest b/src/Desktop/app.manifest new file mode 100644 index 0000000..0d0d1b4 --- /dev/null +++ b/src/Desktop/app.manifest @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Desktop/packages.config b/src/Desktop/packages.config new file mode 100644 index 0000000..a0af628 --- /dev/null +++ b/src/Desktop/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Desktop/test/test.rtxml b/src/Desktop/test/test.rtxml new file mode 100644 index 0000000..abaa685 --- /dev/null +++ b/src/Desktop/test/test.rtxml @@ -0,0 +1,33 @@ + + + + + + 5 + + + + + 5 + + + + + 5 + + + + + 5 + + + + + 5 + + + + + 5 + + \ No newline at end of file diff --git a/src/RoutingTableManager.sln b/src/RoutingTableManager.sln new file mode 100644 index 0000000..b4b3bca --- /dev/null +++ b/src/RoutingTableManager.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoutingTableManager", "RoutingTableManager\RoutingTableManager.csproj", "{A6436D0A-491C-4D6F-82FA-8222CE3CD93B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Desktop", "Desktop\Desktop.csproj", "{15569582-A792-40B2-84EE-44184B93EAF2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A6436D0A-491C-4D6F-82FA-8222CE3CD93B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6436D0A-491C-4D6F-82FA-8222CE3CD93B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6436D0A-491C-4D6F-82FA-8222CE3CD93B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6436D0A-491C-4D6F-82FA-8222CE3CD93B}.Release|Any CPU.Build.0 = Release|Any CPU + {15569582-A792-40B2-84EE-44184B93EAF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15569582-A792-40B2-84EE-44184B93EAF2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15569582-A792-40B2-84EE-44184B93EAF2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15569582-A792-40B2-84EE-44184B93EAF2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/RoutingTableManager/Host.cs b/src/RoutingTableManager/Host.cs new file mode 100644 index 0000000..8e486b3 --- /dev/null +++ b/src/RoutingTableManager/Host.cs @@ -0,0 +1,125 @@ +using System; +using System.Net; +using System.Text.RegularExpressions; +using System.Xml.Serialization; + +namespace RoutingTableManager +{ + public class Host : IEquatable + { + [XmlIgnore] + public IPAddress IPAddress { get; set; } = null; + [XmlAttribute("hostname")] + public string HostName { get; set; } = null; + + [XmlAttribute("ipaddress")] + public string IPAddressForXml + { + get { return IPAddress != null ? IPAddress.ToString() : null; } + set + { + IPAddress = string.IsNullOrEmpty(value) ? null : IPAddress.Parse(value); + } + } + + [XmlIgnore] + public string Label + { + get + { + if (HostName != null) + { + if (IPAddress != null) + { + return string.Format("{0} [{1}]", HostName, IPAddress); + } + return HostName; + } + else if (IPAddress != null) + { + return IPAddress.ToString(); + } + return "---"; + } + } + + [XmlIgnore] + public string Value + { + get + { + if (HostName != null) + { + return HostName; + } + else if (IPAddress != null) + { + return IPAddress.ToString(); + } + return null; + } + set + { + IPAddress parsedIPAddress = null; + if (IPAddress.TryParse(value, out parsedIPAddress)) + { + IPAddress = parsedIPAddress; + HostName = null; + } + else + { + HostName = value; + IPAddress = null; + } + } + } + + public Host() + { + } + + public Host(IPAddress i_IPAddress = null, string i_hostName = null) + : this() + { + IPAddress = i_IPAddress; + HostName = i_hostName; + } + + public override string ToString() + { + return Label; + } + + public bool Equals(Host i_other) + { + if (HostName != null && i_other.HostName != null) + { + return HostName == i_other.HostName; + } + if (IPAddress != null && HostName != null) + { + return IPAddress == i_other.IPAddress; + } + return false; + } + + internal void ComputeIPAddress(bool i_mustRecompute = false) + { + if (IPAddress == null || i_mustRecompute) + { + if (HostName == null) + { + return; + } + + string cmdResult = Shell.RunCommand(string.Format("ping -a -n 1 {0}", HostName)); + Regex regex = new Regex(string.Format("(?{0})? \\[(?[0-9\\.]{{7,}})\\]", HostName)); + Match foundIP = regex.Match(cmdResult); + if (foundIP.Success) + { + IPAddress = IPAddress.Parse(foundIP.Groups["ip"].Value); + } + } + } + } +} diff --git a/src/RoutingTableManager/Interface.cs b/src/RoutingTableManager/Interface.cs new file mode 100644 index 0000000..93018a8 --- /dev/null +++ b/src/RoutingTableManager/Interface.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace RoutingTableManager +{ + public class Interface + { + public enum InterfaceStatus + { + Disconnected, + Connected + } + + public int Index { get; set; } + public int Metric { get; set; } + public long MTU { get; set; } + public InterfaceStatus Status { get; set; } + public string Name { get; set; } + + public override string ToString() + { + return Name; + } + + public static List GetAvailableInterfaces() + { + string output = Shell.RunCommand("netsh int ipv4 show interfaces", false); + + List interfaces = new List(); + + string[] lines = output.Split("\n".ToCharArray()); + Regex lineFormat = new Regex(@"\s*(?[0-9]+)\s+(?[0-9]+)\s+(?[0-9]+)\s+(?[a-z]+)\s+(?.+)\r"); + foreach (string line in lines) + { + Match match = lineFormat.Match(line); + if (match.Success) + { + Interface retval = new Interface(); + retval.Index = int.Parse(match.Groups["idx"].Value); + retval.Metric = int.Parse(match.Groups["metric"].Value); + retval.MTU = long.Parse(match.Groups["mtu"].Value); + switch(match.Groups["status"].Value) + { + case "disconnected": retval.Status = InterfaceStatus.Disconnected; break; + case "connected": retval.Status = InterfaceStatus.Connected; break; + } + retval.Name = match.Groups["name"].Value; + interfaces.Add(retval); + } + } + + return interfaces; + } + } +} diff --git a/src/RoutingTableManager/Properties/AssemblyInfo.cs b/src/RoutingTableManager/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8296a32 --- /dev/null +++ b/src/RoutingTableManager/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Le informazioni generali relative a un assembly sono controllate dal seguente +// set di attributi. Modificare i valori di questi attributi per modificare le informazioni +// associate a un assembly. +[assembly: AssemblyTitle("Routing Table Manager Core Library")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Routing Table Manager")] +[assembly: AssemblyCopyright("Copyright © Simone Saviolo 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Se si imposta ComVisible su false, i tipi in questo assembly non saranno visibili +// ai componenti COM. Se è necessario accedere a un tipo in questo assembly da +// COM, impostare su true l'attributo ComVisible per tale tipo. +[assembly: ComVisible(false)] + +// Se il progetto viene esposto a COM, il GUID seguente verrà utilizzato come ID della libreria dei tipi +[assembly: Guid("a6436d0a-491c-4d6f-82fa-8222ce3cd93b")] + +// Le informazioni sulla versione di un assembly sono costituite dai seguenti quattro valori: +// +// Versione principale +// Versione secondaria +// Numero di build +// Revisione +// +// È possibile specificare tutti i valori oppure impostare valori predefiniti per i numeri relativi alla revisione e alla build +// usando l'asterisco '*' come illustrato di seguito: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/RoutingTableManager/Route.cs b/src/RoutingTableManager/Route.cs new file mode 100644 index 0000000..1c8bedc --- /dev/null +++ b/src/RoutingTableManager/Route.cs @@ -0,0 +1,94 @@ +using System; +using System.Net; +using System.Xml.Serialization; + +namespace RoutingTableManager +{ + public class Route : IEquatable + { + [XmlElement] + public Host Destination { get; set; } = null; + [XmlElement] + public Host Gateway { get; set; } = null; + [XmlElement] + public int Interface { get; set; } = 0; + + private IPAddress m_mask = IPAddress.Parse("255.255.255.255"); + [XmlElement] + public string Mask + { + get { return m_mask.ToString(); } + set + { + m_mask = string.IsNullOrEmpty(value) ? null : IPAddress.Parse(value); + } + } + + public Route() + { + } + + public Route(IPAddress i_destinationIPAddress = null, string i_destinationHostName = null, + IPAddress i_gatewayIPAddress = null, string i_gatewayHostName = null, + int i_interface = 0) + : this() + { + Destination = new Host(i_destinationIPAddress, i_destinationHostName); + Gateway = new Host(i_gatewayIPAddress, i_gatewayHostName); + Interface = i_interface; + } + + internal void Merge(Route i_other, bool i_isAuthoritative) + { + if (i_other.Destination != Destination) + { + throw new InvalidOperationException("Cannot merge two Routes with different Desinations."); + } + + if (Gateway == null || i_isAuthoritative) + { + Gateway = i_other.Gateway; + } + if (Interface == 0 || i_isAuthoritative) + { + Interface = i_other.Interface; + } + } + + public bool Equals(Route i_other) + { + return i_other.Destination == Destination; + } + + private void ComputeIPAddress(bool i_mustRecompute = false) + { + Destination.ComputeIPAddress(i_mustRecompute); + Gateway.ComputeIPAddress(i_mustRecompute); + } + + internal void ApplyToSystem() + { + ComputeIPAddress(); + if (Destination.IPAddress != null && Gateway.IPAddress != null) + { + DeleteFromSystem(); + string command = string.Format("route add {0} {1} mask {3} if {2}", Destination.IPAddress, Gateway.IPAddress, Interface, Mask); + Shell.RunCommand(command, true); + } + } + + internal void DeleteFromSystem() + { + if (Destination.IPAddress != null && Gateway.IPAddress != null) + { + string command = string.Format("route delete {0}", Destination.IPAddress); + Shell.RunCommand(command, true); + } + } + + internal void UpdateDNSResolvedNames() + { + ComputeIPAddress(true); + } + } +} diff --git a/src/RoutingTableManager/RoutingTable.cs b/src/RoutingTableManager/RoutingTable.cs new file mode 100644 index 0000000..cdda003 --- /dev/null +++ b/src/RoutingTableManager/RoutingTable.cs @@ -0,0 +1,73 @@ +using Microsoft.Win32; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Serialization; + +namespace RoutingTableManager +{ + [XmlRoot] + public class RoutingTable + { + [XmlElement("Route")] + public List Routes { get; private set; } = new List(); + + public RoutingTable() + { + } + + private void Merge(RoutingTable i_other, bool i_isAuthoritative) + { + foreach (Route r in i_other.Routes) + { + Route mergeable = Routes.Where(route => route == r).SingleOrDefault(); + if (mergeable == null) + { + Routes.Add(r); + } + else + { + mergeable.Merge(r, i_isAuthoritative); + } + } + } + + public void LoadFromXml(string i_fileName) + { + XmlSerializer serializer = new XmlSerializer(typeof(RoutingTable)); + using (FileStream fs = new FileStream(i_fileName, FileMode.OpenOrCreate)) + { + RoutingTable result = serializer.Deserialize(fs) as RoutingTable; + Merge(result, true); + fs.Close(); + } + } + + public void SaveToXml(string i_fileName) + { + XmlSerializer serializer = new XmlSerializer(typeof(RoutingTable)); + using (FileStream fs = new FileStream(i_fileName, FileMode.OpenOrCreate)) + { + serializer.Serialize(fs, this); + fs.Close(); + } + } + + public void ApplyToSystem() + { + foreach (Route r in Routes) + { + r.ApplyToSystem(); + } + } + + public void UpdateDNSResolvedNames() + { + foreach (Route r in Routes) + { + r.UpdateDNSResolvedNames(); + } + } + } +} diff --git a/src/RoutingTableManager/RoutingTableManager.csproj b/src/RoutingTableManager/RoutingTableManager.csproj new file mode 100644 index 0000000..39b6521 --- /dev/null +++ b/src/RoutingTableManager/RoutingTableManager.csproj @@ -0,0 +1,51 @@ + + + + + Debug + AnyCPU + {A6436D0A-491C-4D6F-82FA-8222CE3CD93B} + Library + Properties + RoutingTableManager + RoutingTableManagerCore + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/RoutingTableManager/Shell.cs b/src/RoutingTableManager/Shell.cs new file mode 100644 index 0000000..01d997d --- /dev/null +++ b/src/RoutingTableManager/Shell.cs @@ -0,0 +1,25 @@ +using System.Diagnostics; + +namespace RoutingTableManager +{ + class Shell + { + public static string RunCommand(string i_command, bool i_runAsAdministrator = false) + { + Process p = new Process(); + p.StartInfo.UseShellExecute = false; + p.StartInfo.RedirectStandardOutput = true; + p.StartInfo.FileName = "cmd.exe"; + p.StartInfo.Arguments = "/c " + i_command; + p.StartInfo.CreateNoWindow = true; + if (i_runAsAdministrator) + { + p.StartInfo.Verb = "runas"; + } + p.Start(); + string output = p.StandardOutput.ReadToEnd(); + p.WaitForExit(); + return output; + } + } +}