Проверка на утечку локального IP

Нашел интересный тест, позволяющий проверить, не «сливает» ли браузер локальный IP через WebRTC В принципе, в этой дыре ничего особо страшного нет. У меня браузер слил локальный IP, но это, как и ожидалось, был частный IP-адрес. Даже не частный IP-адрес локальной сети провайдера, а частный IP-адрес за роутером, сервером, и виртуальной машиной, т.е. что-то вида 172.16.5.100. Ничего, без глубокого анализа и совсем уж целенаправленной атаки не дающий. Нет, он может дать злоумышленнику ваш реальный IP, если у вас «белый» IP, сетевой кабель от провайдера воткнут прямо в сетевую карту, и у провайдера кривые настройки его локальной сети. Но, как говорится, ложечки целы, а осадочек остался. Так что если кому попараноить — тому сюда. Там и инструкция есть, как задушить гадину, если кому надо.

Да, без включенного жабаскрипта оно не работает, так что NoScript наш первый друг, товарищ и самый человечный человек!

И главное — лучше перебдеть, чем недобдеть! (L) КГБ/ВЧК/МГБ/ФСБ/ЦРУ/SCP/НЛО

С уважением, Курильщик, специально для Tolik-punkoff.com

C#, динамическая NotifyIcon, иконка в области уведомления

Давно посматривал на всякие приложения типа Process Explorer или Aida, которые могли создавать в трее иконки, что-нибудь динамически отображающие. Например, Process Explorer может показывать график загрузки ЦП:

Решил попробовать сделать что-то подобное. Оказывается, ничего сверхъестественного не было. Не стал пытаться изобразить график, сделал динамическое отображение заданного текста на иконке.

1. В приложение Windows Forms надо добавить, собственно, NotifyIcon. Пусть будет с именем niMain.

2. Иконка в трее должна быть размером 16×16, заведем соответствующие переменные:

int iwidth = 16; int iheight = 16;

3. Потребуется строковая переменная, хранящая отрисовываемый текст, объект Font и объект Bitmap, который будет хранить динамически отрисовываемое изображение

string DSt = "";
Font fnt = null;
Bitmap bitm = null;

4. В MSDN настоятельно рекомендуют после программного создания иконки, удалять ее с помощью функции DestroyIcon из user32.dll, для предотвращения утечки памяти. Не буду отступать от рекомендаций MSDN, и функцию экспортирую:

[System.Runtime.InteropServices.DllImport("user32.dll", 
            CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        extern static bool DestroyIcon(IntPtr handle);

5. Создаем нужный Font и пустой Bitmap необходимого размера:

private void frmTest_Load(object sender, EventArgs e)
{
    fnt = new Font("Courier new", 8, FontStyle.Bold);
    bitm = new Bitmap(iwidth, iheight);        
}

6. Отрисовываем изображение:

— Создаем объект Graphics, который будет заниматься отрисовкой. Объект Graphics можно получить для определенного ранее Bitmap'а:

Graphics graph = Graphics.FromImage(bitm);

— Рисуем фон (черный квадрат):

graph.FillRectangle(Brushes.Black, 0, 0, iwidth, iheight);

— И текст:

graph.DrawString(DSt,fnt,Brushes.Lime, new Point(0,2));

7. Осталось сделать из объекта Bitmap объект Icon и отдать его контролу NotifyIcon

— Получаем handle иконки:

IntPtr hIcon = bitm.GetHicon();

— Получаем иконку, и отдаем ее NotifyIcon:

System.Drawing.Icon niicon = System.Drawing.Icon.FromHandle(hIcon);
niTest.Icon = niicon;

— Теперь можно уничтожить иконку, т.к в объекте NotifyIcon будет отдельная копия иконки:

DestroyIcon(niicon.Handle);

ФАНФАРЫ!

Пример на GitHub

Источники

Bitmap.GetHicon()
Create Graphics from an Image Object

C#, проверить соединение с Интернетом.

Похоже, самый надежный способ проверить соединение с Интернетом, это сделать запрос к какому-нибудь редко падающему сайту, например google.com или microsoft.com. Хотя в ГОРФ хрен знает, что завтра заблокируют :).
Как я понимаю, седьмая и десятая винда примерно так и поступают, периодически обращаясь к каким-то майкрософтовским серверам.
В сети рекомендуют способ с NetworkInterface.GetIsNetworkAvailable() или экспортировать функцию InternetGetConnectedState из wininet.dll, однако у меня оба способа нагло врали, показывая наличие интернета при его отсутствии, но при наличии подключения к локальной сети или VPN. Сделать Ping тоже не всегда возможно, ICMP могут быть вырублены на стороне провайдера (или сервера). Так что пока способа лучше, чем сообразить запрос с помощью HttpWebRequest не нашел.

При этом способе, правда, есть два небольших подводных камня. Первый ВНЕЗАПНЫЙ, оказывается, ответ на запрос все-таки надо прочесть, хотя сам ответ в данном случае и не особо интересен, для проверки достаточно отловить код ошибки в try/catch примерно так:

request = (HttpWebRequest)HttpWebRequest.Create(URL);

//[...]

try
{
    resp = (HttpWebResponse)request.GetResponse();
    //не вывалились в ошибку, значит все OK

    Stream temp = resp.GetResponseStream(); //если не прочитать поток ответа
    //случается потеря соединения при повторном запросе (сам в шоке)
    StreamReader sr = new StreamReader(temp);
    sr.ReadToEnd();
	
	//Обрабатываем случай когда все ОК
}
catch (WebException ex)
{
	//Обрабатываем ошибку соединения
}

Ну и второй подводный камень довольно очевидный — операция запроса к сетевому ресурсу довольно долгая, так что желательно делать все это в отдельном потоке, дабы не грузить основной поток, в котором обычно интерфейс своими делами занимается, а то программа будет выглядеть «зависшей».

Пример на GitHub

Программист биокибернетических автономных модулей.

Есть у меня постоянная клиентша, скажем, Юля, которой периодически надо восстанавливать систему на ноуте, тому ще также периодически ее грохает мелкий Юлин сын. У Юли есть еще и гражданский муж, скажем Вова, работающий прорабом на стройке.

Сыну, пусть будет Леша, около 5 лет, такой шустрый почемучка с шилом в пигидии, от которого прячутся коты, программисты и любая другая живность, попавшая в зону поражения. Детей я терпеть не могу, но зато очень люблю виски и коньяк, которым меня Юля с Вовой усердно потчуют, так что я к ним всегда лечу, аки муха на мед, и даже денег беру только на такси.

Для них, как и почти для любых юзверей, я «программист» и даже «хакер» (могу сломать пароль на винде, значит хакер). И сыну Юля всегда говорит, что вот, дядя Панкарь программист, сейчас все починит, и Леша опять будет смотреть своих смешариков. Единственное мое достижение в этой семье — я их подсадил на великолепного Глебыча и на «Магазинчик Бо». Ну вот, дело не в этом.

Сижу я после очередного восстановления системы, употребляю армянский коньяк. Тут в кухню заходит мелкий:

— Дядя Панкарь, а папа Вова тоже программист, как и ты!

От неожиданности я подавился коньяком, и вся жизнь, буквально, пронеслась перед глазами. Уж чего только не подумалось, от «если коровы будут летать, то нам в космосе делать нечего», до того, какой чудовищный размер взятки должен быть, чтобы Вова получил диплом, и что Вова скурил, чтобы переквалифицироваться из прорабов в программисты.

Пока я сползал под стол, Вова и Юля ржали в голос. Отсмеявшись, привели меня в чувство и объяснили. Оказывается, мелкий сходил на стройку с папой, увидел, как тот командует бригадой, и расшифровал папину должность ПРОРАБ, как ПРОграммист РАБочих!

Так и живем.

C#, о конфигах и сохранении/загрузке свойств объекта.

Итак, есть у нас некий набор параметров программы, который надо сохранить при задании его пользователем, и восстановить при запросе из основной программы, т.е. файл конфигурации.
Обычно под управление конфигурацией делается отдельный класс, задача которого сохранить/загрузить конфиг и в нужный момент выдать запрашиваемый параметр. В качестве хранилища данных можно использовать DataSet. Во-первых, потому что все параметры можно представить в удобном виде типа таблицы базы данных, а во-вторых, DataSet умеет сохранять свое содержимое в XML и загружать его в автоматическом режиме. Но вот с заполнением DataSet возникают некоторые проблемы. Обычно я заполнял его почти вручную, что приводило к появлению некрасивых простыней кода, в которых, к тому же, легко допустить опечатку. А добавление нового параметра, приводило к необходимости добавлять его в несколько мест в коде.

Как оказалось, можно все сделать гораздо проще — обойти в автоматическом режиме все поля класса, собрать или загрузить в них все нужные значения, а также построить таблицу в DataSet, содержащую все необходимые поля нужного типа.

Что потребуется

Надо подключить пространства имен System.Data и System.Reflection

using System.Data;
using System.Reflection;

и завести приватные переменные, собственно DataSet, переменную под имя конфиг-файла и переменную под имя таблицы:

private string configFile = "";
private string TableName = "";
private DataSet dsNetConfig = new DataSet();

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

public NetSettings(string filename)
{            
    configFile = filename;
    TableName = this.GetType().Name;
    CreateDataSet();
}

Создание таблицы DataSet

private void CreateDataSet()
{             
    dsNetConfig.Tables.Add(TableName);
    
    PropertyInfo[] properties = this.GetType().GetProperties();

    foreach (PropertyInfo pr in properties)
    {
        dsNetConfig.Tables[TableName].Columns.Add(pr.Name,
        pr.PropertyType);
    }
}

— Добавляем в DataSet таблицу
— Получаем список свойств класса в виде массива PropertyInfo:

PropertyInfo[] properties = this.GetType().GetProperties();

— В цикле foreach создаем колонки в таблице DataSet, задавая имя и тип данных:

dsNetConfig.Tables[TableName].Columns.Add(pr.Name, pr.PropertyType);

Сохранение данных

public bool SaveConfig()
{
    // [...]
    
	
    ConfigError = null;
    dsNetConfig.Tables[TableName].Rows.Clear();
    DataRow dr = dsNetConfig.Tables[TableName].NewRow();
    
    
    PropertyInfo[] properties = this.GetType().GetProperties();
    foreach (PropertyInfo pr in properties)
    {
        string propName = pr.Name;
        object propValue = pr.GetValue(this,null);
        dr[propName] = propValue;
    }

    dsNetConfig.Tables[TableName].Rows.Add(dr);

    try
    {
        dsNetConfig.WriteXml(configFile);
    }
    catch (Exception ex)
    {
        ConfigError = ex.Message;
        return false;
    }
    
    return true;
}

— Добавляем в таблицу новый DataRow (у меня строка должна быть всего одна, потому для начала очищаю содержимое таблицы на всякий случай)

dsNetConfig.Tables[TableName].Rows.Clear();
DataRow dr = dsNetConfig.Tables[TableName].NewRow();

— Далее опять же получаю массив PropertyInfo и обрабатываю его в цикле foreach
— Получаю имя поля:

string propName = pr.Name;

— И его значение:
object propValue = pr.GetValue(this,null);

Второй параметр в функции GetValue — индекс для свойств, имеющих индексацию. Например, если свойство является массивом, то нужно будет задавать индекс элемента для получения конкретного значения. В данном случае таких свойств в классе нет, посему в качестве второго параметра указывается null.

— Записываю значение на свое место в DataSet:

dr[propName] = propValue;

— Добавляю в таблицу сформированную строку:

dsNetConfig.Tables[TableName].Rows.Add(dr);

— Сохраняю содержимое DataSet в XML:

dsNetConfig.WriteXml(configFile);

Что делать с ненужными в конфиге полями класса

В разбираемом примере есть такое свойство public string ConfigError, хранящее сообщение об ошибке при загрузке/сохранении конфига, но в самом конфигурационном файле не нужное.

Тут три пути:

1. Самый простой. Забить и плюнуть, ненужное свойство будет сохраняться в конфиге, загружаться из него, да и пусть.
2. Компромиссный. Обнулить свойство перед сохранением. Тогда оно будет как поле в таблице DataSet, но в конфиге его не будет. Так сделано в разбираемом классе Способ хорош, если таких ненужных свойств мало. И место в файле оно занимать не будет, и не нужны дополнительные проверки.
3. Составить список, хоть в виде строковой переменной, где перечислить «лишние» поля, и проверять список перед сохранением и созданием таблицы.

Загрузка данных из конфига

public NetConfigStatus LoadConfig()
{
	//[...]
    try
    {
        dsNetConfig.ReadXml(configFile);
    }
    catch (Exception ex)
    {
        ConfigError = ex.Message;
        return NetConfigStatus.Error;
    }

    //загрузка свойств класса из DataSet
    if (dsNetConfig.Tables[TableName].Rows.Count > 0)
    {
        PropertyInfo[] properties = this.GetType().GetProperties();
        foreach (PropertyInfo pr in properties)
        {
            string propName = pr.Name;
            object propValue = dsNetConfig.Tables[TableName].Rows[0][propName];
            if (propValue.GetType() != typeof(System.DBNull))
            {
                pr.SetValue(this, propValue, null);
            }
        }
		
    //[...]    
    }

    return NetConfigStatus.OK;
}

Все делается точно также, только в обратном порядке.
— Загружаем XML
— Получаем список свойств
— Устанавливаем значения в цикле с помощью SetValue

Необходимы только две проверки — на количество записей в таблице DataSet и на то, не является ли значение ячейки DBNull

Весь код класса на PasteBin

Источники

Киберфорум
MSDN