Pull to refresh

Сервис DDNS от Яндекс

После того, как у перестал работать встроенный в мой роутер DDNS сервис от ASUS asuscomm.com, я стал искать другие варианты. В процессе обдумывания, я вспомнил о старой статье, в которой Melkij рассказывал как использовать DNS хостинг от Яндекса в качестве DDNS. Расскажу о своём решении, хотя оно очень-очень простое. Я решил о нём написать, так как API у Яндекса немного обновился, да и perl я плоховато воспринимаю, в отличие от python.

Легко программируемых роутеров у меня дома нет, но есть мелкий ноутбук Сompaq mini 110 с Ubuntu Server на борту. Его мне хватает в качестве домашнего медиа-сервера и http-сервера для домашней википедии и тестирования небольших проектов. Именно из-за него у меня есть потребность в DDNS сервисе, так что на нём скрипт и будет крутиться.

Задача состоит из двух частей:
  1. Узнать текущий IP
  2. Обновить IP на Yandex.DNS

Про Яндекс DNS
Чтобы Яндекс мог управлять вашим DNS нужно:
  1. Добавить ваш домен в систему ПДД (почта для домена)
  2. Делегировать домен Яндексу. Для этого нужно прописать у регистратора DNS сервера.
  3. Подтвердить, что домен ваш.


1. Узнаём текущий IP


Для этого можно открыть какой-нибудь сайт, где отображается ваш текущий IP. Мне понравился https://myexternalip.com/raw. Чуть позже, из соображений безопасности, я закинул простой php-скрипт на один из своих серверов:
<?php
echo $_SERVER['REMOTE_ADDR'];

Рабочий скрипт будет обращаться к этой странице и хватать оттуда свой IP-адрес.

2. Записываем IP в DNS


А-запись в DNS я изначально создал в ручном режиме. TTL указал минимально возможным, то есть 900. Теперь скриптом мне надо будет только изменять значение IP адреса.

Судя по документации, надо выполнить простой POST-запрос. Но кроме собственно IP адреса мне необходимо знать ещё две вещи: токен и ID записи.

Токен получаем здесь.

ID записи можно было получить скриптом, но я просто посмотрел исходный код возле нужно кнопочки «настроить» на странице записей.


Финальный скрипт


Всё доступно на github. Код всё скажет сам за себя.
from urllib.parse import urlencode
from urllib.request import Request, urlopen
import json
import datetime

LAST_IP_FILE = 'ip.txt' #Файл, в котором храниться последний прописанный IP
LOG_FILE = 'ddns.log'  # Лог
GET_IP_URL = 'https://myexternalip.com/raw' # адрес, сообщающий нам IP
DOMAIN = 'myowndomain.xyz' # Домен, записи DNS которого я редактирую 
RECORD_ID = '0000000' # Номер записи
TOKEN = 'AAAAAAAAAABBBBBB' # Токен от яндекса


# Считываем текущий IP адрес
# Можно добавить ещё проверку, что мы получили именно IP, а не что-то ещё.
ip = urlopen(GET_IP_URL).read().decode()

# Считываем из файла IP, который был записан в DNS последний раз.
try:
    last_ip = open(LAST_IP_FILE, mode='tr').read()
except FileNotFoundError:
    last_ip = ""

# Если старый IP и текущий не совпадают, будем обновлять запись
if last_ip != ip:

    # Готовим POST-запрос
    url = 'https://pddimp.yandex.ru/api2/admin/dns/edit'
    post_fields = {
        'domain': DOMAIN,      
        'record_id': RECORD_ID, 
        'content': ip,
        'token': TOKEN
        }    

    request = Request(url, urlencode(post_fields).encode())
    data = urlopen(request).read().decode()
    json = json.loads(data)

    # Ожидаем, что всё в порядке
    assert json['success']=='ok', json

    # Сохраняем IP в файл
    print(ip, file=open(LAST_IP_FILE, mode='tw'))

    # Пишем об изменении в лог
    d=datetime.datetime.now()
    print(d.strftime("%Y-%m-%d %H:%M:%S"), ip, file=open(LOG_FILE, mode='ta'))


Этот скрипт я поставил на домашнем сервере на выполнение каждые 10 минут с помощью crontab.

Как улучшить скрипт


  • Проверять получаемый от стороннего сервера IP. В идеале получать IP с пары независимых сервисов и сравнивать их. Можно обратиться к самому себе по полученному IP адресу, чтобы проверить, что это именно вы.
  • Получать список всех записей автоматически и обновлять записи со старым IP
  • Сообщать об ошибках администратору (у меня просто stderr пишется в файл)
  • Для небольшого снижения нагрузки можно перенести импорты в те блоки, где они используются


Рад, если решение кому-то пригодится.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.