Делаем свое расширение для Firefox. Содержание.

Делаем свое расширение для Firefox. Часть I. В которой мы все подготавливаем.
Делаем свое расширение для Firefox. Часть II. В которой работаем с пользовательскими настройками аддона.
Делаем свое расширение для Firefox. Часть III. Работа с запросами.
Делаем свое расширение для Firefox. Часть IV. Background, сборка, публикация.

Копия на lj.rossia.org:

Делаем свое расширение для Firefox. Часть I. В которой мы все подготавливаем.
Делаем свое расширение для Firefox. Часть II. В которой работаем с пользовательскими настройками аддона.
Делаем свое расширение для Firefox. Часть III. Работа с запросами.
Делаем свое расширение для Firefox. Часть IV. Background, сборка, публикация.

Страничка расширения на tolik-punkoff.com
Страничка расширения на lj.rossia.org

Делаем свое расширение для Firefox. Часть IV. Background, сборка, публикация.

Делаем background

Теперь делаем специальный модуль ip_background.js, который будет выполнять всю работу нашего аддона, во время работы браузера.

Создаем файл ip_background.js и копируем из файла ip_popup.js все содержимое, кроме строк с addEventListener, т.к. слушатели событий в background будут другие. Функцию doRequest пока оставим в покое, ей займемся чуть позже.

Из функции onGot(item) удаляем строку document.getElementById("script").value = curAddr;, т.к. никаких текстовых полей в бэкграунде нет и не предвидится, менять элементы нам тут не надо.

Еще я переименовал функцию bodyLoad в listinerRun, она у нас будет одна, на все три обрабатываемых события.

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

Так, начало положена, у нас есть «болванка» нашего background-скрипта, сохраняем ее и модифицируем manifest.json

Модификация manifest.json

В manifest.json следует добавить секцию "background", где перечислить в массиве "scripts" скрипты, запускаемые браузером во время работы нашего расширения. Понадобятся два скрипта, собственно ip_background.js и библиотека JQuery jquery-3.4.1.min.js:

"background": {
    "scripts": [
      "jquery-3.4.1.min.js",
      "ip_background.js"
    ]
  }

Новый manifest.json на PasteBin

Далее под катом

Дополнительно

Внешний скрипт на PHP, который можно использовать, как замену api.myip.com (копия)
На GitHub

Скачать

Страница дополнения на mozilla.org
Исходники на GitHub
Скачать подписанный xpi с GitHub
Этот мануал в PDF + весь код в одном архиве:
С Mega.nz
С Google.Drive

Предыдущая часть
Содержание

Делаем свое расширение для Firefox. Часть III. Работа с запросами.

Работа с запросами

До того, как мы будем выполнять запросы к внешним ресурсам, надо внести изменения в manifest.json, дав соответствующее разрешение "<all_urls>" в permissions.
Все разрешения для нашего аддона:

"permissions": [
    "activeTab",
    "tabs",
    "storage",
    "<all_urls>"
  ]

Внимание! Если разрешение "<all_urls>" не дать, то при попытке обращения к внешнему ресурсу произойдет ошибка:

Запрос из постороннего источника заблокирован: Политика одного источника запрещает чтение удаленного ресурса на https://api.myip.com/. (Причина: отсутствует заголовок CORS «Access-Control-Allow-Origin»).

Почему-то ссылка на пояснение к ошибке на сайте Мозиллы ведет не совсем на то, что нужно, а в поиске, тоже неизвестно почему, информация о том, что нужно просто дать разрешение "<all_urls>" в manifest.json не всплывает. Сам еле догадался, практически методом научного тыка устранил данный глюк.

Небольшое отступление от программирования

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

Фактически, у запроса есть три состояния:

— запрос выполняется
— запрос выполнен успешно
— запрос завершен с ошибкой

Обо всем этом можно и нужно сообщать пользователю, и симпатичнее всего это сделать, меняя иконку. Нарисовал и сохранил в каталог flags.

— запрос выполняется (1working.png)

— запрос завершен с ошибкой (2error.png)

— если запрос выполнен успешно, то будем показывать флаг страны, как и планировалось изначально. Но, на всякий случай, можно предусмотреть ситуацию, когда страну определить не удалось (с api.myip.com это вряд ли случится, но с другим скриптом, выдающим данные в том же формате может быть).

— страна неизвестна (3unknow.png)

Подключение JQuery

GET-запрос к сайту оказалось проще всего сделать с помощью библиотеки JQuery.
Скачиваем библиотеку и сохраняем ее в каталог с ip_popup.html. В самом ip_popup.html подключаем ее (перед скриптом ip_popup.js):

<script src="jquery-3.4.1.min.js"></script>

Далее под катом

Предыдущая часть
Продолжение

Делаем свое расширение для Firefox. Часть II. В которой работаем с пользовательскими настройками аддона.

Сохранение настроек

function saveSettings()
{
	var scriptAddr = document.getElementById("script").value;
	scriptAddr = scriptAddr.trim();
	
	if (scriptAddr != "")
	{
		if (window.confirm('Save script address ' + 
                    scriptAddr + '? Are you sure?'))
		{
			browser.storage.local.set({
				server_settings: {script_addr: scriptAddr}
			});
			window.alert('Settings saved!');
		}
		else
		{
			document.getElementById("script").value = curAddr;
		}
	}
}

Что тут делается:

1. Сначала в переменную scriptAddr записывается значение текстового поля с id=script, т.е. того поля, куда можно ввести адрес скрипта.
2. Функцией trim() обрезаем начальные и конечные пробелы, вдруг их пользователь навводит.
3. Если scriptAddr не пустая строка, то запрашиваем у пользователя подтверждение сохранения функцией window.confirm() Функция выведет на экран окошко с текстом, заданным в качестве ее аргумента и кнопками «Да» и «Нет». Если нажата «Да», функция вернет true, если «Нет» — false.

Подробности: «Взаимодействие: alert, prompt, confirm»

4. Если отвечено да, то пользуемся API Firefox’а, а именно функцией browser.storage.local.set(object), которой, в данном случае, передается объект, содержащий объект server_settings, содержащий единственный параметр script_addr. Значение script_addr устанавливаем из переменной scriptAddr. Далее сообщаем пользователю, что настройки сохранены (window.alert('Settings saved!');)

Подробности и примеры работы с локальным хранилищем: StorageArea.get()

5. Если было отвечено «Нет», то восстанавливаем значение текстового поля:

document.getElementById("script").value = curAddr;

В конце js-файла, после всех функций, подключаем обработчик события (слушатель) для события «click» кнопки с id == save:

document.getElementById("save").addEventListener("click", saveSettings);

Внимание! Функции addEventListener имя функции-обработчика передается без круглых скобок

document.getElementById("save").addEventListener("click", saveSettings()); //неправильно

Если добавить скобки, то код функции saveSettings просто однократно выполнится, когда дойдет очередь до addEventListener

Да, ошибка детская, но искать потом концы довольно муторно.

Далее под катом

Начало
Продолжение

Делаем свое расширение для Firefox. Часть I. В которой мы все подготавливаем.

Преамбула

Решил я сделать одно небольшое расширение для Firefox, попутно описывая весь процесс разработки. Пишу больше для себя, чтоб легче было разобраться самому.
Что оно будет делать. Расширение будет присутствовать на панели Firefox в виде отдельной кнопки и отображать на этой кнопке флаг страны, в зависимости от того, какой у пользователя внешний IP. По нажатию на кнопку будет вываливаться всплывающее окно с опцией, которых будет одна — адрес скрипта, который выдаст нам нужные данные, и собственно, самим IP-адресом.

IP и страну будем получать с https://api.myip.com/, который выдает нужную информацию в виде JSON:

{"ip":"162.247.73.193","country":"United States","cc":"US"}

Подготовка структуры каталогов.

Создадим где-нибудь в удобном месте каталог, например, deoip, он будет корневым каталогом нашего плагина, а в нем 2 подкаталога icons и flags

Иконки и флаги стран.

Плагину требуется как минимум одна иконка 48×48 для отображения в менеджере дополнений, и желательна еще одна 96×96 пикселей. В Мозиловском примере говорится, что можно сделать иконку в формате SVG, но я не стал экспериментировать и сделал две PNG-шки.

Флаги стран, которые будут отображаться на кнопке панели, должны иметь размер 32×32 пикселя, а имена файлов соответствовать двухбуквенному ISO-коду страны. Я использовал готовые иконки из коллекций плюс еще одну иконку по умолчанию (0none.png).

manifest.json

manifest.json — это главный файл расширения, содержащий основные опции плагина.

Пока он выглядит так:

{
  "manifest_version": 2,
  "name": "External IP GeoIP",
  "description": "Display you external IP and IP country",
  "version": "0.0.1",
  "icons": {
    "48": "icons/48.png",
    "96": "icons/96.png"
  },
  "browser_action": {
    "default_icon": "flags/0none.png",
    "default_title": "External IP GeoIP"
  },
  "permissions": [
    "activeTab",
    "tabs",
    "storage"
  ]
}

Сначала идут обязательные опции manifest_version и name — имя расширения, далее дополнительные, но желательные description и version, соответственно, краткое описание и версия. В секции icons указываются пути к иконкам для менеджера дополнений (все пути должны быть относительными, относительно, собственно manifest.json). В секции browser_action описывается кнопка на панели браузера и привязанные к ней действия, пока действий у нас никаких (потом добавим выплывающее меню), а задача просто отобразить кнопку на панели. Поэтому добавляем опцию default_icon — путь к иконке по умолчанию, и всплывающую подсказку default_title (появится, если к кнопке подвести указатель мыши).
Далее интересная секция permissions. Это разрешения для нашего плагина. Я уже примерно прикинул какие разрешения нам понадобятся: доступ к вкладкам (tabs), к активной вкладке (activeTab) и хранилищу, которое используется для сохранения настроек плагина (storage).

Подготовка Firefox к тестированию плагина

Особая подготовка не требуется, но я рекомендую все-таки сделать отдельный пустой тестовый профиль. Набираем в адресной строке about:profiles, жмем Enter, попадаем на страницу профилей, создаем отдельный профиль test и жмем «Запустить еще один браузер с этим профилем»

Первый запуск

В браузере с новым профилем набираем в адресной строке about:debugging, слева выбираем «Этот Firefox«, и жмем кнопку «Загрузить временное дополнение» и выбираем наш manifest.json. Теперь идем в меню «Инструменты —> Дополнения» или набираем в адресной строке about:addons, и если все сделано правильно, то видим наше дополнение в списке дополнений, а если откроем просто пустую вкладку, то увидим и кнопку.


Делаем всплывающую панель

Продолжение

Скрипт, выдающий страну и внешний IP в JSON-формате

Скрипт выдает IP, страну и ISO-код страны в формате JSON, как https://api.myip.com.

Скрипту требуется два внешних файла (должны лежать в каталоге со скриптом): БД SxGeoCountry (SxGeo.dat) и iso.csv

Посмотреть, как работает
Исходники на GitHub

IPInformer v 0.2.0

Наконец-то руки дошли прикрутить инсталлер и выложить 🙂

Программа предназначена для отображения внешнего IP-адреса компьютера, определения географической принадлежности IP-адреса, а также того, не попадает ли IP-адрес в список «запрещенных» стран.

Программа получает IP-адрес, из поставляемого с ней PHP-скрипта, размещенного на Web-сервере в Интернете, и/или (в текущей версии) с сайтов, которые информируют пользователя о его внешнем IP. В текущей версии не все такие сайты подходят (сайт не должен быть заскриптован, не требовать обязательного использования cookie и не выдавать капчу), а оригинальный скрипт PHP предоставляет некоторые дополнительные возможности.

Далее, программа получает из базы данных SxGeo сведения о геопозиции, и, если настроено и IP-адрес попал в стоп-лист стран, выводит предупреждение о попадании в данный список.

Свежую версию БД SxGeo можно бесплатно скачать с сайта разработчиков базы данных: https://sypexgeo.net/ru/download/

Программа при запуске находится в системном трее, управление производится через контекстное меню.

Изначально писалась по заказу одного активиста, у которого была проблема с периодическим отключением от VPN, в связи с чем, случайно мог «засветиться» его IP, или VPN мог переключить его на нежелательную страну.

По умолчанию программа запускается в «портативном» режиме (все данные хранятся в подкаталоге data каталога с исполняемым файлом)

Системные требования

Microsoft Windows XP и выше (Vista/7/8/8.1/10), .NET Framework 2.0 и выше, 512 Мб оперативной памяти, 15 Мб на жестком диске.

Дополнительные компоненты

В качестве контрола для ввода IP-адреса мы использовали C# IP Address Control вот этого автора:

https://www.codeproject.com/Articles/9352/A-C-IP-Address-Control

База данных SypexGeo (SxGeo):
© 2006-2018 zapimir
© 2006-2018 BINOVATOR

https://sypexgeo.net

Скриншоты

Получение нового IP

Остальные под катом

История версий

0.0.1 b, 19/01/2010 — Первая версия, написанная для товарища OPPosition
0.1.2 08/08/2018 — Исправлен код запросов и конфигов, многое переделано
0.2.0 01/07/2019 — Программа «отвязана» от скрипта с SxGeo на сервере, интерфейс к БД SxGeo перенесен внутрь программы, запросы к БД обрабатываются локально, добавлена поддержка других источников IP-адресов. Первая публичная версия.

Скачать

Портабельная версия
Инсталлятор

Исходники

Репозиторий на GitHub

Небольшой обзор на сайты, отображающие IP и различную информацию про него.

Преамбула

Понадобилось тут для одного проекта получать внешний IP, да еще желательно и из нескольких источников.

Критерии были такие:

— сайт не должен быть заскриптован и засран капчей наглухо, в идеале, чтобы просто содержал страничку с внешним IP, а еще лучше, чтоб с IP, которые «протекают» через прокси, которую без бубна можно высосать хоть тем же wget’ом.
— чтоб не требовал куки и не пугался странных идентификаторов браузера (последнее, конечно, легко решается на уровне клиента, но ведь лень).
— более-менее стабильная работа
— анализ не должен требовать сложного парсинга, в идеале, IP вытаскиваются простой регуляркой.

Лучшие

https://api.myip.com/ — выдает IP и краткие данные в формате JSON. Бесплатный и стабильный (правда в прошлом месяце все-таки вышел из строя на два дня из-за каких-то технических проблем).
https://2ip.ru — наверное, самый известный сервис в рунете. Несмотря на требования включить javascript, информацию об IP отдает и просто так. Бесплатный, стабильный (вообще не видел, чтоб он когда-нибудь падал). IP на странице встречается несколько раз, посему, при составлении списка выкидываем одинаковые. Минус — русский сервис.
https://yandex.ru/internet/ — ВНЕЗАПНО, Яндекс. Плюсы и минусы такие же, как у предыдущего сайта.
https://hidemyna.me/ru/ip/ — Информация о IP на сайте VPN-сервиса HideMy.name. Сам сервис какой-то подозрительный, а страничка с информацией об IP вполне себе соответствует всем требованиям, правда, насчет надежности особо не тестировалась.
https://whatleaks.com/ru/ — в стабильности не уверен, в остальном, вполне соответствует.
http://whatismyip.host/my-ip-address-details — простой зарубежный сервис, отображающий IP и краткую информацию. Насчет надежности особо не тестировалось, остальное соответствует, плюс сервис не российский.

Чуть похуже

Похуже, в данном случае, значит, что требуют более продвинутого парсинга, а при простом выдирании со страницы всего, что похоже на IP, выдают паразитные данные.

https://2ip.ua/ua/ — на самом деле, я бы поставил этот сервис на второе место, после https://api.myip.com/, если бы не маленький минус — со странички выкачивается и адрес самого сервера.
http://www.findmyip.org/ — дает кучу паразитных IP

Совсем бяка.

Read more…

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

Отдельной категорией в список непопадают жадные буржуи, которые в 21 веке не могут себе позволить хостинг с безлимитным трафиком (даже я могу).

Альтернативный вариант

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

Репозиторий на GitHub

Узнать, как сделано, можно прочитать записи по тегу ip-detect копия озаглавленные «Определение IP и местоположения посетителя сайта».

DetecTOR v 0.3.0b.

Обновлена утилита DetecTOR, которая определяла, присутствует ли определенный IP в сети Tor.

По многочисленным просьбам зрителей добавлен:

— модуль SxGeoSharp, теперь, даже если IP отсутствует в сети Tor, программа возьмет информацию из базы SxGeo (если вы ее скачаете и подгрузите, она бесплатная), и выдаст вам страну (+город и регион, если есть) для конкретного IP-адреса.
— по умолчанию включен портабельный режим, все настройки программы хранятся в подкаталогах с исполняемым файлом.
— режим пакетной обработки. Если у вас есть огромный лог или просто список IPv4 адресов, (тестировалось на 1000 IP-адресов в специально нагенерированном текстовом файле, где IP были расположены в случайном порядке), то программа найдет все адреса, проверит их по БД SxGeo и БД адресов Tor и выдаст результат в виде файла CSV. Можно включить или отключить выдачу в отчет дополнительных данных Tor.
— добавлены дополнительные аргументы командной строки (см. readme.txt).
— проверено замечание пользователя [info]paperdaemon@ljr. Данная ошибка при работе в Windows 7 и более ранних версиях так и не была выявлена.

readme.txt

Основная статья о DetecTOR Копия
Скачать (портативная версия)
Исходники

C#, Регулярное выражение для IP-адреса (v4)

Искать айпишники, например, в логах.
Для десятичной (полной) записи:

(25[0-5]|2[0-4]\d|[01]?\d\d?)(\.(25[0-5]|2[0-4]\d|[01]?\d\d?)){3}

Второе, должно поддерживать восьмеричную, шестнадцатеричную, десятичную и смешанную запись:

(0[0-7]{10,11}|0(x|X)[0-9a-fA-F]{8}|(\b4\d{8}[0-5]\b|\b[1-3]?\d{8}\d?\b)|((2[0-5][0-5]|1\d{2}|[1-9]\d?)|(0(x|X)[0-9a-fA-F]{2})|(0[0-7]{3}))(\.((2[0-5][0-5]|1\d{2}|\d\d?)|(0(x|X)[0-9a-fA-F]{2})|(0[0-7]{3}))){3})

Второй мопед не мой, оставляю на всякий случай, чтоб два раза не вставать.

Протестировать можно здесь
Ну и тесты на C# (от Лехи)

SxGeoSharp. Интерфейс на C# для базы данных SypexGeo. Часть I — инициализация (и введение)

Преамбула

Проект SypexGeo это автономная файловая бинарная база данных, хранящая IPv4 адреса, и позволяющая определить их географическую привязку, а также, соответствующий PHP-скрипт, позволяющий использовать ее на своем сайте, для определения страны и города по IP.
Примеры использования в блоге уже неоднократно описывались.
Мне понадобилось ее использовать на машине без интернета, для того, чтобы анализировать некоторые логи, на PHP (консольном) получалось довольно неуклюже и неудобно, поставить web-сервер не было возможности, потому подумал и решил, почему бы не расковырять базу, благо формат открыт, и не прикрутить к своим программам интерфейс на C#.
Сразу говорю, текст будет довольно длинный и нудный, поскольку это еще и что-то типа технической документации в вольной форме, написанной по работе, вдруг кто-то косяки поправит или кому-то понадобится.
Написан этот интерфейс наверняка не оптимально, и наверняка требует доработки. Спецификация формата написана довольно скупо, так что о кое-каких вещах приходилось догадываться, где-то, правда в мелочах, было наврано, где-то приходилось подглядывать в исходник от создателей (на PHP), где-то даже расчехлить hiew, а где-то переделывать PHP алгоритмы под C#. Это собой отдельную трудность представляло, потому что в PHP вся работа с типами благополучно переложена на интерпретатор, и PHP легко может работать с числом или с массивом байт, как со строкой, и наоборот.

Спецификация формата доступна на официальном сайте

SxGeoSharp работает с бесплатными вариантами базы SxGeoCountry (SxGeo.dat) и SxGeoCity (SxGeoCity.dat) версии 2.2 (Unicode, Windows-1251 и теоретически Latin-1). Платных вариантов баз не было, кому надо чтобы было — пишите в комментарии, договоримся.
Read more…

C#, проверка попадания IP-адреса в зарезервированные диапазоны.

Про зарезервированные диапазоны и то, как проверить, попадает ли в них адрес IPv4, я уже писал и приводил решение данной задачи на PHP. Теперь вариант на C#.

Понадобится функция IPConverter.IPToInt32(IP), которую я описывал в прошлой заметке, аналог функции ip2long() PHP

В остальном все делается также, как и в PHP-примере.

1. Заводим двумерный массив, содержащий IP начала диапазона, конечный IP и описание диапазона:

string[,] SpecList = new string[,]  {
   {"0.0.0.0","0.255.255.255", "Current network"},
   {"255.255.255.255","255.255.255.255", "Broadcast"},
   {"255.0.0.0","255.255.255.255", "Reserved by the IETF, broadcast"},
   {"10.0.0.0","10.255.255.255", "Private network"},
   {"100.64.0.0","100.127.255.255", "Shared Address Space"},
   {"127.0.0.0","127.255.255.255", "Loopback"},
   {"169.254.0.0","169.254.255.255", "Link-local"},
   {"172.16.0.0","172.31.255.255", "Private network"},
   {"192.0.0.0","192.0.0.7", "DS-Lite"},
   {"192.0.0.170","192.0.0.170", "NAT64"},
   {"192.0.0.171","192.0.0.171", "DNS64"},
   {"192.0.2.0","192.0.2.255", "Documentation example"},
   {"192.0.0.0","192.0.0.255", "Reserved by the IETF"},
   {"192.88.99.1","192.88.99.1", "IPv6 to IPv4 Incapsulation"},
   {"192.88.99.0","192.88.99.255", "Anycast"},
   {"192.168.0.0","192.168.255.255", "Private network"},
   {"198.51.100.0","198.51.100.255", "Documentation example"},
   {"198.18.0.0","198.19.255.255", "Test IP"},
   {"203.0.113.0","203.0.113.255", "Documentation example"},
   {"224.0.0.0","224.255.255.255", "Multicast"},
   {"240.0.0.0","240.255.255.255", "Future reserved"}
};

2. Пишем функцию, которая перебирает массив, и проверяет, попал ли указанный IP в один из диапазонов. Если попал — возвращает описание диапазона, если нет — пустую строку. IP-адреса конвертируются функцией IPConverter.IPToInt32(IP) в целые числа и сравниваются:

string CheckSpecDiaps(string IP)
{
    int uip = IPConverter.IPToInt32(IP);

    for (int i = 0; i < SpecList.GetLength(0); i++)
    {
        int start = IPConverter.IPToInt32(SpecList[i, 0]);
        int end = IPConverter.IPToInt32(SpecList[i, 1]);
        string desr = SpecList[i, 2];

        if (uip >= start && uip <= end)
        {
            return desr;
        }
    }

    return string.Empty;
}

Пример на GitHub

C#, проверка корректности и преобразования IP-адреса, класс IPAddress

Для работы с IP-адресами в .NET Framework есть класс IPAddress из пространства имен System.Net

Проверка корректности IP-адреса

bool IsIP(string IP)
{
    try
    {
        IPAddress addr = IPAddress.Parse(IP);
    }
    catch
    {
        return false;
    }
    return true;
}

Преобразование IP-адреса в полную форму записи.

Класс IPAddress и его функция Parse распознает сокращенную форму записи IP-адреса, например, адрес 4.0.0.1 можно записать как 4.1, и он будет таки корректным. Функция ToString() класса IPAddress всегда возвращает строку IP-адреса в полном виде, т.е. n.n.n.n, это можно использовать для преобразования адреса в полную форму записи:

string ToStandForm(string IP)
{
    if (!IsIP(IP))
    {
        return string.Empty;
    }
    IPAddress addr = IPAddress.Parse(IP);
    return addr.ToString();
}

Получение IP-адреса в виде массива байт

byte[] GetBytesBE(string IP)
{
    IPAddress addr = IPAddress.Parse(IP);
    return addr.GetAddressBytes();
}

Примечание: GetAddressBytes() выдает байты IP-адреса всегда в сетевом порядке, т.е. big-endian, в таком же, в котором байты идут при обычной записи IP. Если вдруг понадобится little-endian порядок, например, для того, чтобы преобразовать IP-адрес в целое число на little-endian системе, то массив надо перевернуть.

byte[] GetBytesLE(string IP)
{
    IPAddress addr = IPAddress.Parse(IP);
    byte[] addrbytes = addr.GetAddressBytes();
    Array.Reverse(addrbytes);
    return addrbytes;
}

Преобразование IP-адреса в знаковое 32-битное целое

Аналог PHP-функции ip2long() или сишной inet_addr()

int IPToInt32(string IP)
{
    IPAddress addr = IPAddress.Parse(IP);
    //получаем байты адреса, они всегда в big-endian
    byte[] addrbytes = addr.GetAddressBytes();
    //IP в виде Int32 big-endian
    int n = BitConverter.ToInt32(addrbytes,0);
    //если в системе little-endian порядок
    if (BitConverter.IsLittleEndian)
    {
        n = IPAddress.NetworkToHostOrder(n); //надо перевернуть
    }
    return n;
}

Изменить порядок байт можно и без использования Array.Reverse(), если число типа short или int. Для этого в классе IPAddress присутствуют функции NetworkToHostOrder(), которая меняет порядок байт в переменной с сетевого (big-endian) на используемый на локальной машине, и функция HostToNetworkOrder(), которая делает обратную операцию.

Преобразование IP-адреса в беззнаковое 32-битное целое

Скорее, чтоб два раза не вставать, делается точно так же, как и преобразование в знаковый int, но функции NetworkToHostOrder() и HostToNetworkOrder() тут уже не помогут, так что придется переворачивать массив байт адреса с помощью Array.Reverse():

public static uint IPToUInt32(string IP)
{
    IPAddress addr = IPAddress.Parse(IP);
    byte[] addrbytes = addr.GetAddressBytes();
    if (BitConverter.IsLittleEndian)
    {
        Array.Reverse(addrbytes);
    }
    return BitConverter.ToUInt32(addrbytes, 0);
}

Навеяно вопросом на stackowerflow
Объединил все вышеуказанные функции в отдельный класс.

Исходник на GitHub

Определение IP и местоположения посетителя сайта 7.

Консольный вариант скрипта.

Т.е. это уже не совсем «определение местоположения посетителя сайта», это просто интерфейс к базе данных Sypex Geo, который можно использовать в консольных приложениях на PHP.

Что переделано:
Переделан изначальный скрипт, для работы под консоль, или, если хотите, а качестве stand-alone скрипта. Для консольного приложения очень важно вернуть код завершения, чтобы далее его могло обработать либо следующая программа в командном файле (BAT/CMD), либо вызвавшая скрипт, как внешний процесс, программа.

Таким же образом был немного подправлен SxGeo.php, распространяемый разработчиками Cypex Geo.

Исправления таковы:

— Везде, где скрипт завершает работу, была добавлена выдача кода завершения
— Таким же образом подправлен класс SxGeo, поставляемый разработчиками Cypex Geo.

Краткая справка скрипта:

Вызов скрипта:
consxgeo.php <ip-address> <database-path> [FIELD_NAME]
consxgeo.php --spec
consxgeo.php --help

--help - Помощь
--spec - Список зарезервированных диапазонов IP-адресов
<ip-address> - Адрес IPv4 (например, 8.8.8.8)
<database-path> - Путь к файлу SxGeoCity.dat
[FIELD_NAME] - Для включения в вывод результата работы скрипта источника IP-адреса. По умолчанию, это значение = MANUAL

Коды завершения:
0 - OK
1 - Предупреждение
3 - Вывод информационных сообщений
4 - Ошибка или неправильные параметры скрипта

Структура ответа:
IP|ISO_CODE|COUNTRY_NAME|CTNR_LAT|CTNR_LON|
REGION_ISO|REGION_NAME|CITY_NAME|CTY_LAT|CTY_LON
|FIELD|MESSAGE|

Пример вывода

Частный IP:


Просто адрес IP:

Сокращенный IP-адрес:

Скрипт на GitHub

Предыдущая часть Копия

PHP. Проверка корректности IP-адреса

Преамбула

[info]ketmar@ljr справедливо заметил, что наши скрипты принимают только IP-адреса в формате xxx.xxx.xxx.xxx, где xxx — десятеричное число от 0 до 255, а IP может быть записан и в виде шестнадцатеричных, и в виде восьмеричных чисел, и даже смешано. Также IP-адрес может быть неполным. Например, адрес 4.0.0.1 можно записать как 4.1
В наших скриптах корректность IP проверялась регулярным выражением, т.к. все равно им же производился поиск IP в полях HTTP_*, в которых IP может передаваться прокси-серверами.
Но валидацию IP можно провести и без использования регулярных выражений. Другое дело, поиск без него уже не произведешь, и это может создать определенные проблемы, если прокси-сервер, например, будет передавать IP в виде шестнадцатеричных чисел или преобразовывать, где возможно, полные адреса в неполные.

Не очень хороший способ валидации IP функцией filter_var()

В PHP 5.2.0 появилась функция filter_var(), которая позволяет проверять строки на соответствие разным форматам, не только IP, но и, например URL или e-mail.
Для проверки IP она вызывается так:

filter_var($ip,FILTER_VALIDATE_IP);
где:
$ip — строка, содержащая IP-адрес
FILTER_VALIDATE_IP — встроенный фильтр для IP-адреса
Функция возвращает TRUE, если строка прошла проверку, и FALSE если нет.

А не очень хорош способ тем, что валидацию проходят только IP, соответствующие формату «четыре десятеричных числа от 0 до 255, разделенных точкой», т.е. работает точно также, как и наша старая функция
Такое ощущение, что разработчики PHP пытаются избавить мир от зоопарка способов записи IP-адреса, и привести все, наконец, к единому знаменателю 🙂

Пример с использованием функции filter_var

Проверка корректности IP-адреса функцией ip2long()

[info]ketmar@ljr предлагал использовать сишную функцию inet_addr(), но где ж я ее возьму-то в PHP, подумал я, и зря подумал. 🙂 Функция ip2long($ip), которая использовалась для проверки попадания IP-адреса в определенный диапазон Копия ее аналог. Если переменная $ip содержит корректный IP-адрес, то функция вернет целое число, если в IP-адресе ошибка, то функция вернет FALSE или -1.

Примечание: Функция ip2long() возвратит FALSE для IP 255.255.255.255 в PHP 5 <= 5.0.2 и -1 в PHP 5 <=5.2.4 на 64-битных системах. Это было исправлено в PHP 5.2.5, теперь возвращается 4294967295. В 32-битных системах будет возвращено -1 из-за целочисленного переполнения.

Так что проверку на корректность IP можно делать в функции-обертке, добавив код-заглушку для IP 255.255.255.255:

function IsIP($ip)
{
	//преобразуем в нижний регистр, на случай шестнадцатиричных чисел
	$ip=strtoupper($ip);
	//ip2long в некоторых версиях php 
	//некорректно реагирует на адрес 255.255.255.255
	//делаем небольшую заглушку
	if ($ip == '255.255.255.255'||$ip == '0xff.0xff.0xff.0xff'||
	   $ip == '0377.0377.0377.0377')
	   {
		   return true;
	   }
	
	$tolong=ip2long($ip);
	
	if ($tolong == -1||$tolong===FALSE) return FALSE;
	else return TRUE;	
}

Преобразование неполных и прочих «необычных» IP-адресов в привычный вид.

В PHP есть функция long2ip(), которая делает обратное преобразование, т.е. преобразует целое число в IP-адрес в привычном виде. Если их совместить, то можно преобразовывать неполные адреса в полные:

function fulladdr($ip)
{
	//преобразует неполные адреса в полные
	//для информации
	$tolong=ip2long($ip);
	return long2ip ($tolong);
}


Пример работы скрипта:
isip.php?ip=4.1

Скрипт на GitHub

Внезапное дополнение

Внедрил последний метод в рабочие скрипты, залил на сервер, и оказалось, что метод не работает. Ну не то, чтобы не совсем не работает, а работает точно так же, как старая функция с регулярным выражением, т.е. возвращает TRUE только если IP-адрес записан в виде четырех десятеричных чисел от 0 до 255, разделенных точкой. Неполные адреса, или адреса в других системах счисления IP-адресами не считаются. Функция ip2long() возвращает FALSE, если ей скормить такой адрес. Уж не знаю, и сходу не нагуглил, отчего такая оказия, то ли такое поведение зависит от настроек PHP, то ли от сервера. На локальном сервере работало, а на том, который в интернете — перестало. Можно сказать, зря делал, но зато сделал валидацию IP без регулярного выражения.

Источники

1. ip2long
2. Ещё раз о filter_var

Определение IP и местоположения посетителя сайта 6.

Нифига не окончание, а второй сезон.

Пока исключительно небольшие исправления.

— Добавили зарезервированные диапазоны IPv4 адресов и соответствующую проверку Копия в скрипты для машинной обработки данных и в красивый скрипт с оформлением, таким образом немножко усовершенствовали скрипт из предыдущей серии.

— Сделали тестовый скрипт, который IP сам ничего не детектит, а просто обращается к SxGeo. Он все равно еще понадобится.

Использование:
onlysxgeo.php?ip=ip-address
Например:
onlysxgeo.php?ip=8.8.8.8
Или:
onlysxgeo.php?ip=ip-address&f=FIELD_NAME
для включения имя поля в ответ скрипта, по умолчанию имя поля MANUAL
Или
onlysxgeo.php?specdiap
Для вывода списка зарезервированных диапазонов адресов IPv4

— По многочисленным просьбам зрителей сделали самый простой скрипт, который просто выводит все IP из заголовков HTTP_* (например HTTP_VIA и/или HTTP_X_FORWARDED_FOR) и REMOTE_ADDR и источник адреса (имя поля HTTP_* или REMOTE_ADDR).

— Завели отдельный репозиторий на GitHub, куда выложили код из всех предыдущих и новых серий

Репозиторий

Зарезервированные диапазоны IP-адресов и проверка попадания в них адреса.

Преамбула

В IPv4 имеются зарезервированные диапазоны адресов, в некоторых случаях надо проверить, не попал ли адрес в один из них

Таблица зарезервированных адресов


См. в PDF
Или на PasteBin

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

Вспомогательные функции для проверки

Для порядку заведем регулярное выражение для проверки IP
$ip_pattern="#(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)#";

И функцию, которая проверяет, а IP ли вообще у нас на входе:

function isip($ip_str) //соответствие данных формату IP
{	
	global $ip_pattern;
	$ret=FALSE;
	if (preg_match($ip_pattern,$ip_str)) 
	{
		$ret=TRUE;
	}
	return $ret;
}

Теперь функцию, которая будет проверять, попал ли IP в нужный диапазон:

function chkdiapip ($user_ip, $ip_from, $ip_to) //попадает ли ip в нужный диапазон
{
	return ( ip2long($user_ip)>=ip2long($ip_from) &&
 ip2long($user_ip)<=ip2long($ip_to) );
}

Проверка

Создадим двумерный массив со списком диапазонов:

$spec_list = array(										
	array ("0.0.0.0","0.255.255.255", "Current network"),
	array ("255.255.255.255","255.255.255.255", "Broadcast"),
	array ("255.0.0.0","255.255.255.255", "Reserved by the IETF, broadcast"),
	array ("10.0.0.0","10.255.255.255", "Private network"),
	array ("100.64.0.0","100.127.255.255", "Shared Address Space"),
	array ("127.0.0.0","127.255.255.255", "Loopback"),
	array ("169.254.0.0","169.254.255.255", "Link-local"),
	array ("172.16.0.0","172.31.255.255", "Private network"),
	array ("192.0.0.0","192.0.0.7", "DS-Lite"),
	array ("192.0.0.170","192.0.0.170", "NAT64"),
	array ("192.0.0.171","192.0.0.171", "DNS64"),
	array ("192.0.2.0","192.0.2.255", "Documentation example"),
	array ("192.0.0.0","192.0.0.255", "Reserved by the IETF"),				
	array ("192.88.99.0","192.88.99.255", "Anycast"),
	array ("192.88.99.1","192.88.99.1", "IPv6 to IPv4 Incapsulation"),
	array ("192.168.0.0","192.168.255.255", "Private network"),
	array ("198.51.100.0","198.51.100.255", "Documentation example"),
	array ("198.18.0.0","198.19.255.255", "Test IP"),
	array ("203.0.113.0","203.0.113.255", "Documentation example"),
	array ("224.0.0.0","224.255.255.255", "Multicast"),
	array ("240.0.0.0","240.255.255.255", "Future reserved")					
	);

И функцию, которая будет все это безобразие в цикле перебирать, и если IP попадет в какой-то из диапазонов - выдаст диапазон и описание. Если не попадет - вернет -1.

function get_spec_diap ($user_ip, $listspec)
{
	for ($i=0;$i<sizeof($listspec);$i++)
	{
		$item = $listspec[$i];
		if (chkdiapip($user_ip, $item[0], $item[1]))
		{
			return $item[0]."\t".$item[1]."\t".$item[2]."\t\n";
		}
	}
	
	return -1;
}

Ну шоб два раза не вставать, сделаем еще и функцию, оглашающую весь список:

function printspecdiap ($listspec)
{
	for ($i=0;$i<sizeof($listspec);$i++)
	{
		$item = $listspec[$i];
		echo $item[0]."\t\t".$item[1]."\t\t\t".$item[2], "\t\t\t\n";
	}
}

Скрипт полностью на PasteBin
На GitHub

DetecTOR, утилита, определяющая, относится ли IP к сети TOR

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

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

Выглядит главное окно вот так:

readme.txt

Чтоб два раза не вставать.
readme.txt

Смотреть исходники (на GitHub)
Скачать программу (Win32) c GitHub

Определение IP и местоположения пользователя посетителя сайта 5.

Пришедшие вчера за помощью студенты натолкнули на мысль окончательно завершить данную тему.
Итак, чего не так в нашем скрипте для определения IP и местоположения пользователя?
А не так то, что мы анализируем лишь один содержащий IP параметр: REMOTE_ADDR. Т.е. на самом деле это правильно, как сказано в замечательной статье. Но всей информации мы можем не увидеть, и даже у пользователя из какой-нибудь Сызрани, сидящего через не анонимный прокси, вместо Сызрани будет гордо высвечиваться какой-нибудь Вашингтон. Исправим это, поступив точно так, как рекомендуют поступить в вышеозначенной статье. Поле REMOTE_ADDR будем анализировать в качестве первичного и основного источника информации, а потом пробежимся по всем заголовкам HTTP_ (VIA, X_FORWARDED_FOR, X_CLIENT_IP и т.д., сколько найдем), достанем из них все, что соответствует шаблону IP, скормим определялке географического положения и выдадим в качестве дополнительной информации.
Пользователь может сидеть не через единственный прокси, а через каскад (тоже не анонимный, хехе). В таком случае, в одном или нескольких заголовках HTTP_ могут быть перечислены несколько прокси, причем тут нет никаких стандартов. Вполне возможна ситуация «кто в лес, кто по дрова»: прокси будут перечислены через запятую, пробел, через знак |, двоеточие. Это тоже нужно учесть.
Read more…
Получился скрипт, выдающий данные об IP пользователя в виде, удобном для машинной обработки (например приложению или скрипту для ведения логов).


Каскад прокси

Анонимный прокси, заполняющий несколько заголовков HTTP_

Скачать. Посмотреть код на PasteBin Посмотреть в работе
Впрочем, совсем не составляет труда сделать ему вид, более радующий глаз человека:
1. В строке header('Content-type: text/plain; charset=utf8'); изменим text/plain на text/html
2. Модифицируем сообщения скрипта.
3. Добавим код, выводящий оформление HTML (2 и 3 см. в самом скрипте ниже)

Каскад прокси
Анонимный прокси, заполняющий несколько заголовков HTTP_

Скачать. Посмотреть код на PasteBin Посмотреть в работе
Предыдущая серия

Это перепост заметки из моего блога на LJ.ROSSIA.ORG
Оригинал находится здесь: http://lj.rossia.org/users/hex_laden/330304.html
Прокомментировать заметку можно по ссылке выше.

Определение IP и местоположения посетителя сайта 4.

Продолжаем модифицировать скрипт, точнее ответить на вопрос:
Q: Можно ли объединить первую и последнюю версию скрипта, чтоб без параметра скрипт проверял IP, передаваемый сервером, а если указан параметр GET — переданный в параметре IP?
A:
Да, и опять же довольно просто. Надо лишь условие проверки переменной модифицировать соответственно. Условие у нас было:

//проверка наличия переменной
if (!isset($_GET['ip'])) {
echo 'ERROR|NOT DATA';   //не нашли - вывели сообщение об ошибке и прекратили работу
die();
}


Модифицируем условие следующим образом:

$ip="";
//проверка наличия переменной
if (isset($_GET['ip']))
{
$ip=$_GET['ip'];
}
else
{
$ip = $_SERVER['REMOTE_ADDR'];
}


Сначала инициализируем переменную $ip, далее проверяем, если в запросе GET есть параметр ip, то его значение присваиваем переменной $ip, иначе берем ее значение из $_SERVER['REMOTE_ADDR'];
Далее, все как в 3 серии
Скачать можно здесь, Посмотреть как работает — здесь.
Картинки — такие же как и в предыдущих выпусках. Посему дублировать не буду.
Предыдущая серия Окончание

Это перепост заметки из моего блога на LJ.ROSSIA.ORG
Оригинал находится здесь: http://lj.rossia.org/users/hex_laden/269411.html
Прокомментировать заметку можно по ссылке выше.