Куем RDP и VNC клиентов



На моей основной работе мне приходится заниматься администрированием серверов и рабочих станцией, работающих под управлением Windows/Linux. К серверам я привык подключаться через стандартный RDP, а для соединения с рабочими местами пользователей больше предпочитаю использовать одну из модификаций VNC.

Функциональность RDP и VNC меня полностью удовлетворяют, за исключением одного НО. При интенсивной работе мой рабочий стал захламляется копиями приложений TightVNC и mstsc. Бывает работаешь с тремя серверами, а тут тебе звонит пользователь и слезно просит помочь. Хочется иль не хочется, а приходится сворачивать окна mstsc и запускать консоль TightVNC. В результате такой работы рабочий стол быстро превращается в хаос, состоящий из открытых окон mstsc и TightVNC. Найти в таком бардаке окно с нужным сеансом крайне проблематично.

Однажды меня все это окончательно достало и я решил во что бы то не стало исправить положение дел. Что из этого получилось, ты узнаешь по ходу чтения этой статьи.

Путь смертного

Пожалуй, самым простым способом решения выше озвученной проблемы будет поиск и внедрение готового клиента-комбайна, поддерживающего протоколы RDP и VNC. Способ, несомненно, хорош, а главное времени на его реализацию практически не надо. Таких утилит пруд пруди, успевай только выбирать. Но, отдавая предпочтение готовому софту, ты автоматически становишься обладателем всех его плюсов и минусов. Среди основных минусов обычно выступает - цена. Продвинутый софт стоит денег, а бесплатный редко попадается со всеми необходимыми функциями. Оба эти минуса меня в свое время не устроили и я решил пойти по нетоптаной тропинке.

Путь Джедая

Насупившись и сжав в руки в кулаки, я решил во что бы то не стало написать своего мегапродвинутого клиента. По задумке он должен был бы уметь поддерживать подключения по протоколам RDP и VNC.

Решить проблему открытых окон я хотел с помощью уже хорошо проверенного метода - использования вкладок. А что? Уже все WEB-браузеры, в том числе и хромой ослик ИА, открывают новые страницы в отдельном табе. Юзеры от такой фишки довольны и уже ни одного из них не заставишь отказаться от этой фичи. Я подумал, а почему бы интерфейс моего приложения не сделать в таком же духе? Было бы супер, когда каждый удаленный рабочий стол располагался бы в отдельной вкладке. В заголовке таба можно было прописывать название сервера и уже по нему ориентироваться. Думаю, мою идею ты уловил.

На чем лучше писать

Перед разработкой своего приложения я долго мучился в выборе языка. Сначала я было хотел написать все на Delphi. Скажу даже больше, я уже реализовал поддержку RDP и VNC, но потом некоторые ограничения дельфина мне надоели и я решил сделать выбор в пользу C# и платформы .NET. Выбирая технологии от Microsoft, ты получаешь кучу готовых шаблонов и для достижения нирваны остается приложить совсем чуть-чуть усилий.

RDP

Итак, для организации поддержки протокола RDP мы обратимся за помощью к Com-компоненту - Microsoft RDP Client. Пользоваться этим компонентом чрезвычайно просто и что немаловажно - удобно. К тому же компонент установлен в каждой системе, поэтому заботиться о его поставке не придется.

Чтобы воспользоваться возможностями этого компонента, тебе необходимо добавить его на панель выбора элементов. Делается это через окно «Выбор элементов панели инструментов» -> COM-компоненты». В представленном списке компонент, отметь флажком Microsoft RDP Client Control. Проделав это не хитрое действие, на панели выбора элементов, как и следовало ожидать, появится новый компонент.

Теперь попрактикуемся в боевом применении. Знакомиться лучше сразу начинать с практики. Для демонстрации возможностей компонента я накидал простенький демонстрационный пример. Форма моего проекта как обычно красуется на одном из рисунков. Нарисуй что-то подобное или придумай неповторимый дизайн.

Перед тем как начать шкрябать кодерские каракули, поглядим на методы и свойства недавно установленного компонента. Начнем наше знакомство со свойств:

Connected - если соединение с удаленным рабочим столом установлено, то здесь будет 1.
ColorDepth - палитра цветов. Может принимать следующие значения: 8, 15, 16, 24, 32;
Server - адрес удаленного сервера. Одинаково воспринимает как символьные имена, так и IP адрес!
UserName - Имя пользователя;
AdvancedSettings2.ClearTextPassword - Пароль; AdvancedSettings2.RDPPort - Номер порта;
DesktopWidth - Ширина удаленного рабочего стола; DesktopHeight - Высота удаленного рабочего стола;
FullScreen - Полноэкранный режим;
RedirectPrinters - Переопределять принтеры. Если true, то при отправке документа на печать с удаленной машины, он будет печататься на твоем принтере. RedirectSmartCards - Переопределять смарт-карты. RedirectPorts - Переопределять порты.

Со свойствами разобрались. Перейдем к методам. Из всех имеющихся, нас интересуют лишь два: Connect() и Disconnect(). Я полагаю, что пояснять для чего они нужны необходимости нет.

Помимо свойств и методов, как и у любого другого компонента, у MS RDP Client Control имеется целая пачка событий. Здесь их рассматривать не буду. Об их предназначении не трудно догадаться по названию. Так что проблемы возникнуть не должны.


Куем RDP клиент

Теорией мы заправились, а раз так, то самое время переходить к практике. Хотя, особо тут практиковаться негде - все и так достаточно просто. Не веришь? Тогда взгляни в первый листинг, и ты в этом убедишься.

RdpClient.Server =
textBox1.Text.Trim();
RdpClient.AdvancedSettings2.ClearTextPassword =
textBox3.Text.Trim();
RdpClient.UserName =
textBox2.Text;
//RdpClient.Domain = “Домен”;
//RdpClient.FullScreen = true;
switch (comboBox1.SelectedIndex)
{
case 0: RdpClient.ColorDepth = 15;
break;
case 1: RdpClient.ColorDepth = 16;
break;
case 2: RdpClient.ColorDepth = 24;
break;
case 3: RdpClient.ColorDepth = 32;
break;
}
switch (comboBox2.SelectedIndex)
{
case 0:
RdpClient.DesktopWidth = 640;
RdpClient.DesktopHeight = 480;
break;
case 1:
RdpClient.DesktopWidth = 800;
RdpClient.DesktopHeight = 600;
break;
case 2:
RdpClient.DesktopWidth = 1024;
RdpClient.DesktopHeight = 768;
break;
case 3:
RdpClient.DesktopWidth = 1120;
RdpClient.DesktopHeight = 700;
break;
case 4:
RdpClient.DesktopWidth = 1280;
RdpClient.DesktopHeight = 1024;
break;
}
RdpClient.Connect();

Весь процесс установки связи с удаленным хостом сводится к заполнению свойств компонента RdpClient и вызову метода Connect(). В случае, если вся введенная инфа корректная, то подключение будет установлено, а если нет, то вылетит эксепшн.

Сразу хочу заметить. В своем коде я не делал обработку ошибок. В реальном приложении они необходимы. Попробуй реализовать их самостоятельно, а если не получится, то не отчаивайся. После того как мы разберем по косточкам работу с VNC ты сможешь сделать обработку эксепшнов по аналогии.

Разбор практики использования RDP можно считать оконченным. В принципе, уже можно переходить к рассмотрению VNC, но сначала мне бы хотелось рассказать еще об одном около rdp’шном нюансе.

Те кто юзает стандартный RDP клиент наверняка привыкли создавать ярлыки (правильней сказать файлы настроек) для быстрого подключения к нужному серверу. У меня например таких ярлыков примерно штук 13. Пользоваться ими удобно - кликнул и подключился к нужному серверу. Но вот при переходе на своего собственного клиента я испытал реальные трудности.

Я буквально сам себя поставил перед фактом - либо вбивать в свою прогу параметры подключения для всех этих 13 машин самостоятельно, либо предусмотреть возможность импорта настроек из сохраненных файлов. Первый вариант меня не особо привлекал, поэтому я сразу решил заняться реализацией второго. Сначала я думал, что тут будет много сложностей, но как оказалось в дальнейшем, любители C# уже проделали эту работу вместо меня и запечатлили свои труды в классе RDPFileReader.

Данный класс позволяет как читать файлы настроек, так и создавать новые. Воспользовавшись им, ты сделаешь свою программу универсальной. Все старые файлы настроек можно будет импортировать, а при необходимости передачи параметров соединения кому-либо из пользователей, предусмотреть экспорт. Причем производить экспорт именно в стандартный файл настроек, который без проблем поймет встроенный в Windows rdp клиент. Все, не буду тебя томить, взгляни лучше на пример чтения произвольного файла настроек:

OpenFileDialog myOpenFileDialog;
myOpenFileDialog = new OpenFileDialog();
myOpenFileDialog.Filter = "RDP File|*.rdp";
myOpenFileDialog.Title = "Выбор файла с настройками RDP";
myOpenFileDialog.ShowDialog();
if (myOpenFileDialog.FileNames.Count() > 0)
{
RDPFile MyRdpFile = new RDPFile();
MyRdpFile.Read(myOpenFileDialog.FileName);
//Обработка свойств объекта MyRdpFile
}

В этом небольшом куске кода, я вызываю стандартный диалог открытия файлов. Если пользователь выбрал файл, то тогда, мне ничего не остается как создать экземпляр объекта типа RDPFile и выполнить его метод Read(). В качестве параметра этому методу нужно передать путь к файлу, который и нужно читать. Завершив чтение, поля объекта MyRdpFile будут заполнены данными из файла. Например:

- AudioMode - режим аудио
- Domain - домен
- FullAddress - адрес сервера
- Password - пароль
- RedirectComPorts - переопределять Com порты
- Username - имя пользователя.
- DesktopHeight - высота рабочего стола.
- DesktopWidth - ширина рабочего стола.
- и т.д.


Разработка в самом разгаре

VNC

Сделать поддержку VNC несколько сложнее. Этот протокол создан не в недрах MS, а следовательно весь кодинг ложиться сугубо на твои плечи. Не стоит раньше времени переживать и думать, что весь протокол придется описывать с нуля. Уже создано не мало различных клиентов (в том числе и OpenSource), в которых можно подсмотреть код и перенести его на нужный нам язык программирования.

Стой! Не торопись запрягать любимый гугл! Мы не станем искать сишные клиенты, и разбираться в десятках килобайт чужого кода. Уже нашлись умельцы и энтузиасты, которые проделали всю черную работу за нас и оформили результат в виде компонента для моего любимого C#. Все, что от нас требуется – подключить его к Visual Studio и написать несколько нехитрых строчек кода.

Итак, отправляйся на ]]>http://cdot.senecac.on.ca/projects/vncsharp]]> и сливай последнюю версию компонента. Он доступен как в исходных текстах, так и уже в виде готовой библиотеки dll. Мне больше нравится работать с иходникам, т.к. при необходимости, у тебя всегда есть возможность внести изменения. Поэтому мой выбор – это архив с исходником и самостоятельная компиляция.

Если ты как и я, отдал предпочтению архиву с исходными текстами, то открывай сорцы в Visual Studio и приступай к компиляции. У меня она прошла без ошибок. Искать дополнительных библиотек не пришлось. Если у тебя также все прошло Ok, то на выходе, ты должен получить библиотеку с именем VncSharp.dll.

Закрывай в студии открытые ранее сорцы компоненты VncSharp и создавай новый проект типа Windows Forms Application. Сейчас мы подключим скомпилированный ранее компонент. Для этого выполни несколько простых шагов:

1. Открой панель элементов и кликни на ней правой кнопкой мыши.
2. В контекстном меню выбери пункт «Выбрать элементы/choose elements».
3. В появившемся окне клацни по кнопке «Обзор» и выбери получившуюся в результате компиляции библиотеку.
4. Кликай Ok, а затем найди на панели элементов новый компонент RemoteDesktop и кинь его на форму.


Компонент RemoteDesktop готов к использованию

Считай, что после установки компонента на форму пол дела уже сделано. Остается лишь заполнить пару полей и выполнить несколько методов. Для лучшей демонстрации работы с VNC я опять таки набросал небольшой проект. Его форму ты можешь увидеть на соответствующем рисунке.


Проект для демонстрации работы с VNC

Для установки соединения с серверной частью VNC, тебе необходимо выполнить метод Connect компонента RemoteDesktop. Метод описан так:

Void Connect(string host, bool ViewOnly, bool scaled);

Метод принимает целых три параметра:

- host – адрес удаленного хоста. Можешь указывать здесь либо ip адрес, либо символьное имя.
- viewOnly – режим отображения удаленного рабочего стола. Если передать в этом параметре true, то, удаленный десктоп будет доступен лишь для просмотра. Все клики мышкой, или нажатия клавиш на клавиатуре будут игнорироваться
- scaled – масштабирование. Передаем true – получаем масшабированное изображение.

Код установки соединения из моего примера ты можешь увидеть в листинге 2.

Листинг 2. Установка соединения с сервером VNC

string remoteHost = TextBox1.Text;
int remotePort = Convert.ToInt32(TextBox2.Text);
try
{
remoteDesktop1.VncPort = remotePort;
remoteDesktop1.Connect(remoteHost, false, true);
}
catch (VncProtocolException vex)
{
MessageBox.Show(string.Format("Невозможно установить соединение:{0}", vex.Message));
}

Код второго листинга прост до безобразия и вряд ли требует детальных пояснений. Все что в нем происходит - заполнение необходимых полей и вызов метода Connect, а также обработка эксепшн типа VncProtocolException.

При удачном раскладе, в компоненте RemoteDesktop отобразится содержимое удаленного рабочего стола. Внимательно посмотрев на листинг, ты наверняка заметил, что в коде негде не видно передачи пароля. А ведь известно, что на подключение к серверной части может требоваться пасс. Тогда почему, мы нигде не обрабатываем эту ситуацию? Дело в том, что компонент берет эту обязанность на себя. В случае, если требуется ввод пароля, то он автоматически сгенерирует окно запроса пароля. Не устраивает такой подход? Не проблема! Объяви функцию, которая будет возвращать пароль (можешь даже организовать хранилище паролей в базе данных) и передавать его в свойство GetPassword объекта RemoteDesktop (см., исходник).

Так, подключаться мы научились. Теперь рассмотрим самый последний момент работы с VNC и двинемся дальше. При администрировании удаленных систем, всегда требуется послать сочетание нескольких клавиш. Типичный пример - Ctrl + Alt + Del. Если попробовать их тупо нажать, то хорошего ничего не произойдет. Все что ты увидишь - запуск на локальном компьютере таск менеджера. Исправить положение дел, поможет метод SendSpecialKeys(). Его описание выглядет так:

void SendSpecialKeys(SpecialKeys keys, bool release);

Метод принимает аж два параметра:

- keys – значение из перечисления типа SpecialKeys (по сути это спец клавиши). В качестве значений могут быть:
- Alt
- AltF4
- Ctrl
- CtrlAltDel
- CtrlEsc

- realese – освобождать клавишу или нет

Получается, что для отправки сочетания трех клавиш от всех бед, тебе требуется выполнить всего одну строчку кода:

RemoteDesctop1.SendSpecialKeys(SpecialKeys.CtrlAltDel);

На этом знакомство с компонентом для работы с VNC можно считать оконченным. Хочу обратить твое внимание, на то, что я рассмотрел не все методы компонента RemoteDesktop. Те, что остались за кадром – доступны во врезке.

Делаем закладки

Работать с обоими протоколами мы научились как в теории, так и на практике. Теперь остается лишь посмотреть на процесс создания табов для каждого удаленного рабочего стола.

Как ты наверное уже догадался, все новые табы, должны создаваться во время работы приложения (RunTime). Код создания очередной вкладки будет выглядеть примерно так:

TabPage NewPage = new TabPage();
NewPage.Text = "Новая вкладка";
RemoteDesktop NewRemoteDesctop = new RemoteDesktop();
NewPage.Controls.Add(NewRemoteDesctop);
tabControl1.TabPages.Add(NewPage);

Для большего удобства, лучше сохранять ссылку на вновь созданную вкладку в каком-нибудь контейнере. Потом намного будет удобней работать с большим количеством табов (например, выполнять поиск, сортировку и т.д.).

Заключение

Написать можно все что угодно, главное поставить себе цель и не в коем случае не сворачивать с пути. А еще важнее, не идти на поводке моды, а писать на том языке, на котором быстрее удастся достигнуть результата. Чем меньше затратишь времени, тем больше сможешь оставить его для более приятных вещей. Для сегодняшнего примера мы выбрали C#, хотя могли писать и на Java, или на приплюснутом Си, но в этом случае, так быстро создать рабочее приложение нам бы не удалось. Удачи тебе в кодинге, возникнут вопросы - пиши на мыло, постараюсь помочь!

Нерассмотренные методы RemoteDesktop

- IsConnected – возвращает true, если соединение с удаленным компьютером установлено.
- Disconnect – выполняет отключение от удаленной машины
- SetScalingMode (bool scaled) – если в качестве единственного параметра передаем true, то будет установлен режим масштабирования.
- FullScreenUpdate() – полноэкранный режим
- FillServerClipboard() – перенос содержимого буфера обмена с локальной машины на удаленную.

Совет

На основе полученных из статьи знаний ты без проблем сможешь написать полезные в хакерском деле утилиты - брутфорсы. Например, совсем недавно в нашем журнале был рассказ об утилите, которая подбирает пароль к RDP. В ее основе как раз лежала технология, которую мы сегодня разобрали. Так что мотай на ус и не расслабляйся.

Written by Игорь Антонов aka Spider_NET
E-mail:

Комментарии

6 комментария(ев)
аватар: wwwnet
wwwnet
Дата: Втр, 30/03/2010 - 16:29
Звание: Посвященный
Сообщений: 416

Название такое... куем... лучше руками Smile
Статься понравилась, Игорь молодец.

аватар: AltaVista
AltaVista
Дата: СБ, 19/11/2011 - 19:31
Звание: Мастер
Сообщений: 1150

Цитировать
Название такое... куем... лучше руками

О том же подумал и я! У великих мысли сходятся! ))) Oo

аватар: Spider_NET
Spider_NET
Дата: СР, 31/03/2010 - 08:36
Звание: Мастер
Сообщений: 2049

Эту статью я изначально писал для журнала "Хакер". Если мне не изменяет память, то такое название статье дал редактор. Так оно и осталось Smile

аватар: DredWill
DredWill
Дата: СБ, 19/11/2011 - 06:12
Звание: Наблюдатель
Сообщений: 2

У Вас исходников на Delphi не осталось случайно???
Очень нужны!!!
Диплом пишу, а знания слабоватые(((

аватар: AltaVista
AltaVista
Дата: СБ, 19/11/2011 - 19:28
Звание: Мастер
Сообщений: 1150

отличная статья! +5 баллов.
А вот исходники на Делфи были бы кстати. А то как тока я сажусь потренироваться и поизучать С#, сразу какой то катаклизм происходит! Боюсь что если я еще раз начну читать учебник по С меня в армию призовут родину защищать от вторжения инопланетян! Shock

аватар: DredWill
DredWill
Дата: ВС, 20/11/2011 - 05:42
Звание: Наблюдатель
Сообщений: 2

)) Самого Си воротит !!!Wink