Как подружить питон с Невидимым Интернетом? Основы разработки I2P приложений на Python и asyncio

в 9:51, , рубрики: asyncio, i2p, p2p, python, vpn, анонимность, децентрализованные сети, информационная безопасность, приватность, Программирование, файлообмен

Как подружить питон с Невидимым Интернетом? Основы разработки I2P приложений на Python и asyncio - 1

Проект Невидимый Интернет (далее просто I2P) представляет разработчикам платформу для разработки приложений с усиленными требованиями по приватности пользователей. Это виртуальная сеть поверх обычного Интернета, в которой узлы могут обмениваться данными и при этом не раскрывать свой настоящий IP адрес. Вместо IP адресов внутри Невидимого Интернета соединения происходят между виртуальными адресами, которые называются I2P Destination. Можно иметь сколько угодно таких адресов и менять их хоть для каждого соединения, они не предоставляют другой стороне никакой информации о настоящем IP адресе клиента.

В этой статье описаны базовые вещи, которые нужно знать для написания I2P приложений. Примеры кода приведены на Python с использованием встроенного асинхронного фреймворка asyncio.

Включение SAM API и установка i2plib

I2P предлагает несколько API для взаимодействия с клиентскими приложениями. Для приложений на Java используется I2CP, для обычных client-server приложений можно использовать I2PTunnel, HTTP и Socks прокси. Мы же будем делать приложение на Python, поэтому выбираем SAM. По-умолчанию, в оригинальном Java клиенте SAM API выключен, так что нужно его включить. Зайдите в веб-консоль I2P роутера, страница "I2P internals" -> "Clients". Поставьте галочку "Run at Startup" и нажмите "Start", затем "Save Client Configuration".

Как подружить питон с Невидимым Интернетом? Основы разработки I2P приложений на Python и asyncio - 2

В C++ клиенте i2pd SAM уже включен по-умолчанию.

Для простоты использования SAM API мною была написана Python библиотека i2plib. Установить ее можно через pip или скачать исходный код с GitHub.

pip install i2plib

Так как эта библиотека работает со встроенным асинхронным фреймворком asyncio, имейте в виду, что примеры кода тоже взяты из асинхронных функций (coroutines), которые работают в event loop'е. Дополнительные примеры использования есть в репозитории.

Destination и создание сессии

По своей сути, I2P Destination это связка ключей шифрования и подписи данных. Публичные ключи из этой связки публикуются в сети I2P и используются вместо IP адреса для создания соединений.

Сгенерируем i2plib.Destination, который мы будем использовать в дальнейшем:

dest = await i2plib.new_destination()
print(dest.base32 + ".b32.i2p") # вывод base32 адреса

base32 адрес это хэш, по которому другие пиры могут найти ваш Destination в сети. Если вы планируете использовать этот Destination в своей программе на постоянной основе, сохраните содержимое dest.private_key.data в локальный файл.

Теперь можно создать SAM сессию, что буквально значит сделать этот Destination онлайн в сети:

    session_nickname = "test-i2p" # каждая сессия должна иметь уникальный nickname
    _, session_writer = await i2plib.create_session(session_nickname, destination=dest)

Тут важно отметить, что Destination будет онлайн до тех пор, пока открыт сокет session_writer. Если захотите "выключить" данный Destination из сети, вызывайте session_writer.close().

Делаем исходящие соединения

Теперь, когда Destination вышел в онлайн, мы можем использовать его для связи с другими узлами. Для примера, подключаемся к узлу "udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p", отправляем HTTP GET запрос и читаем ответ (там находится веб-сервер "i2p-projekt.i2p"):

remote_host = "udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p"
reader, writer = await i2plib.stream_connect(session_nickname, remote_host)

writer.write("GET /en/ HTTP/1.0nHost: {}rnrn".format(remote_host).encode())

buflen, resp = 4096, b""
while 1:
    data = await reader.read(buflen)
    if len(data) > 0:
        resp += data
    else:
        break

writer.close()
print(resp.decode())

Принимаем входящие соединения

При подключении к другому хосту, как видите, все просто, но с принятием входящих есть один ньюанс. Когда к вам подключается новый клиент, SAM отправляет в сокет ASCII строку с Destination этого клиента. Так как Destination и данные могут прийти одим куском, нужно это учитывать.

Вот так выглядит простой PING-PONG сервер, который принимает входящее соединение, сохраняет Destination клиента в rеременную remote_destination, и отправляет обратно PONG:

async def handle_client(incoming, reader, writer):
    """Обработка клиентского соединения"""
    dest, data = incoming.split(b"n", 1)
    remote_destination = i2plib.Destination(dest.decode())
    if not data:
        data = await reader.read(BUFFER_SIZE)
    if data == b"PING":
        writer.write(b"PONG")
    writer.close()

# Вечный цикл, который принимает клиентские соединения и запускает обработчик
while True:
    reader, writer = await i2plib.stream_accept(session_nickname)
    incoming = await reader.read(BUFFER_SIZE)
    asyncio.ensure_future(handle_client(incoming, reader, writer))

Больше информации

Тут описано использование Streaming протокола, который выполняет функции TCP/IP в сети I2P. SAM API так же предоставляет возможность посылать и принимать анонимные датаграмы, на подобие UDP протокола. Этот функционал в i2plib пока отсутствует и будет добавлен позже.

Это только самая базовая информация, но ее уже вполне достаточно, чтобы начать свой проект в I2P. Невидимый Интернет подходит для написания различных приложений, в которых в первую очередь важно сохранять приватность пользователей. Никаких ограничений на разработчиков сеть не накладывает, это могут быть как client-server, так и P2P приложения.

Автор: supervillain

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js