Сегодня, помимо моего любимого занятия (возиться с Arduino в моем кружке детского творчества), решил я поставить себе сервер (Windows 2012 r2) и использовать его для различных манипуляций. Изучив тонну информации, всё прошло гладко.
Когда, закончил экспериментировать в локальной сети, у меня появился вопрос: «Как можно увидеть свой сервер из внешней сети, если у меня динамический IP». Снова помогла всемирная книга знаний и были найдены такие сервисы, как DynDNS, no-ip и т.п.
После регистрации увидел, что нужно качать прогу (в роутере настроек под dyndns нет), а как добросовестный параноик, я не люблю ставить сторонний софт. Вспомнив, что имею при себе домен второго уровня делегированный на Яндексе, принялся изучать сторону вопроса, для написания своего софта на C#.
За основу я взял статью «Самодельный Dynamic DNS». Для отправки запросов к API был написан следующий метод:
Теперь нужно было как-то получить внешний IP, а так, как я решил напрочь не пользоваться DynDNS, то и к страничке checkip.dyndns.org решил не обращаться. Начал искать у того же Яндекса. Отправив гет-запрос на страничку yandex.com/internet, нашёл интересную строчку ipv4.internet.yandex.net/internet/api/v0/ip в ответ на такой запрос, мне выдало красивейший IP в чистом виде.
Для понимания откуда взят токен и id, пожалуйста, обратитесь к статье, которую я взял за основу. Таким образом сложились следующие строчки:
Наконец т.к. всё это дело должно работать на сервере, я решил пересоздать консольное приложение в службу. Были добавлены таймеры и проверка на изменение ip относительно предыдущего.
В данный момент при записи нового ip очень много грязнит в лог — можно либо после отладки закомментировать вовсе, либо можно парсить по тегу Error error, тогда можно будет получать чистый ответ от API. Я это не делал, т.к. IP меняется очень редко, а когда всё отлажено, то и ошибки API будут редко.
Таким образом, берём внешний ip мы уже не с постороннего ресурса, а с того-же, где пользуемся доменом, так же код можно запустить на любой windows-машине, вплоть до домашнего компьютера. Но советую тогда переделать проверку IP, так, как сделал автор, на которого я ссылался: ему посоветовали сохранять ip в отдельный файл и брать из него последний, сравнивать с нынешним. Я не делал это потому, что у моего сервера аптайм довольно высокий и перезапуск службы не будет особо часто зачищать переменную outIP.
На этом всё, надеюсь кому-нибудь пригодится сие решение. Жду ваших комментариев и критики.
Когда, закончил экспериментировать в локальной сети, у меня появился вопрос: «Как можно увидеть свой сервер из внешней сети, если у меня динамический IP». Снова помогла всемирная книга знаний и были найдены такие сервисы, как DynDNS, no-ip и т.п.
После регистрации увидел, что нужно качать прогу (в роутере настроек под dyndns нет), а как добросовестный параноик, я не люблю ставить сторонний софт. Вспомнив, что имею при себе домен второго уровня делегированный на Яндексе, принялся изучать сторону вопроса, для написания своего софта на C#.
За основу я взял статью «Самодельный Dynamic DNS». Для отправки запросов к API был написан следующий метод:
static string GET(String getString) { HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(getString); request.Method = "GET"; String test = String.Empty; using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { Stream dataStream = response.GetResponseStream(); StreamReader reader = new StreamReader(dataStream); test = reader.ReadToEnd(); reader.Close(); dataStream.Close(); } return test; }
Теперь нужно было как-то получить внешний IP, а так, как я решил напрочь не пользоваться DynDNS, то и к страничке checkip.dyndns.org решил не обращаться. Начал искать у того же Яндекса. Отправив гет-запрос на страничку yandex.com/internet, нашёл интересную строчку ipv4.internet.yandex.net/internet/api/v0/ip в ответ на такой запрос, мне выдало красивейший IP в чистом виде.
Для понимания откуда взят токен и id, пожалуйста, обратитесь к статье, которую я взял за основу. Таким образом сложились следующие строчки:
string ip = GET("http://ipv4.internet.yandex.net/internet/api/v0/ip").Trim('"'); string respons = GET("https://pddimp.yandex.ru/nsapi/edit_a_record.xml?token=" + token + "&domain=" + domain + " &subdomain=" + subdomain + "&record_id=" + id + "&content=" + ip);
Наконец т.к. всё это дело должно работать на сервере, я решил пересоздать консольное приложение в службу. Были добавлены таймеры и проверка на изменение ip относительно предыдущего.
using System; using System.ServiceProcess; using System.IO; using System.Net; using System.Timers; namespace DDNSyapi { public partial class Service1 : ServiceBase { String outIp = ""; Timer timer1; public const string token = "YOURTOKEN"; public const string domain = "YOURDOMAIN"; public const string subdomain ="UPDATINGSUBDOMAIN"; public const string id = "id"; //take token on pddimp.yandex.ru/get_token.xml?domain_name=YOURDOMAIN //take id on pddimp.yandex.ru/nsapi/get_domain_records.xml?token=YOURTOKEN&domain=YOURDOMAIN public Service1() { InitializeComponent(); } public static void Logs(string err) { StreamWriter txtIst = new StreamWriter(System.IO.Path.GetDirectoryName( System.Environment.GetCommandLineArgs()[0]) + "//IpServerLog_" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + ".txt", true); txtIst.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " : " + err); txtIst.Close(); } protected override void OnStart(string[] args) { timer1 = new System.Timers.Timer(30 * 60 * 1000); timer1.Elapsed += timer1_Tick; timer1.Start(); timer1.Enabled = true; Logs("Запуск службы"); } private void timer1_Tick(object sender, EventArgs e) { timer1.Enabled = false; try { string ip = GET("http://ipv4.internet.yandex.net/internet/api/v0/ip").Trim('"'); if (!ip.Equals(outIp)) { outIp = ip; string respons = GET("https://pddimp.yandex.ru/nsapi/edit_a_record.xml?token=" + token + "&domain=" + domain + " &subdomain=" + subdomain + "&record_id=" + id + "&content=" + ip); Logs(respons); } } catch { Logs("проблемы с интернетом.."); } timer1.Enabled = true; } static string GET(String getString) { HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(getString); request.Method = "GET"; String test = String.Empty; using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { Stream dataStream = response.GetResponseStream(); StreamReader reader = new StreamReader(dataStream); test = reader.ReadToEnd(); reader.Close(); dataStream.Close(); } return test; } protected override void OnStop() { timer1.Enabled = false; timer1.Stop(); timer1 = null; Logs(DateTime.Now.ToString("HH:mm:ss") + " - " + "Остановка службы"); } } }
В данный момент при записи нового ip очень много грязнит в лог — можно либо после отладки закомментировать вовсе, либо можно парсить по тегу Error error, тогда можно будет получать чистый ответ от API. Я это не делал, т.к. IP меняется очень редко, а когда всё отлажено, то и ошибки API будут редко.
Таким образом, берём внешний ip мы уже не с постороннего ресурса, а с того-же, где пользуемся доменом, так же код можно запустить на любой windows-машине, вплоть до домашнего компьютера. Но советую тогда переделать проверку IP, так, как сделал автор, на которого я ссылался: ему посоветовали сохранять ip в отдельный файл и брать из него последний, сравнивать с нынешним. Я не делал это потому, что у моего сервера аптайм довольно высокий и перезапуск службы не будет особо часто зачищать переменную outIP.
На этом всё, надеюсь кому-нибудь пригодится сие решение. Жду ваших комментариев и критики.