Могу ли я выполнить поиск в DNS (от имени хоста до IP-адреса) с помощью клиентского Javascript?

92

Я хотел бы использовать Javascript на стороне клиента для выполнения поиска DNS (имя хоста по IP-адресу), как видно с клиентского компьютера. Это возможно?

Ной Джейкобсон
источник
5
Многие ответы на этот вопрос, похоже, рекомендуют использовать сервер разрешения. В зависимости от варианта использования этого может быть недостаточно. Например, если служба, которую вы ищете, использует GSLB, она может вернуть другой IP-адрес в зависимости от того, где находится пользователь; в результате ответ, который получает код на стороне сервера, скорее всего, будет отличаться от того, который получил бы браузер. При этом у меня пока нет альтернативного решения для тех, кому важна эта разница.
Илан Рабинович

Ответы:

35

В стандартной библиотеке javascript нет понятия хостов или IP-адресов. Таким образом, вам придется получить доступ к какой-либо внешней службе, чтобы найти для вас имена хостов.

Я рекомендую разместить cgi-bin, который ищет IP-адрес имени хоста и получает доступ к нему через javascript.

Ханс Сюннессон
источник
26
cgi-bin? Это старая школа. Мне это нравится!
Эндрю Хеджес,
10
Это было правдой на момент написания (2008 г.). Это неправда, 6 лет спустя: см. Мой комментарий о WebRTC на этой же странице. (К сожалению, Google по-прежнему указывает на эту ветку при поиске решения проблемы с IP-адресом, и это может сбить людей с пути).
эризон
1
@earizon - ваш ответ на другой вопрос - как узнать свой собственный IP-адрес.
Джин Вайнгриб
Проблема через CGI из облака заключается в обнаружении IP-адресов хоста интрасети, что невозможно извне. Вам придется использовать локальную службу на машине или в интрасети.
Tzahi Fadida
Предлагается новый Интернет-стандарт, который позволяет отправлять DNS-запросы по HTTPS (см. Этот ответ stackoverflow.com/a/58299823/9638991 ). На самом деле, он в основном работает так же, как скрипт cgi-bin :) (за исключением того, что он стандартизирован IETF, и его поддерживают множество крупных компаний)
kimbo
83

Изменить : этот вопрос вызвал у меня зуд, поэтому я разместил веб-сервис JSONP в Google App Engine, который возвращает IP-адрес клиентов. Применение:

<script type="application/javascript">
function getip(json){
  alert(json.ip); // alerts the ip address
}
</script>

<script type="application/javascript" src="http://jsonip.appspot.com/?callback=getip"> </script>

Ура, прокси сервера не нужны.


Чистый JS не может. Если у вас есть серверный скрипт в том же домене, который его распечатывает, вы можете отправить XMLHttpRequest для его чтения.

Зак
источник
4
Не могли бы вы опубликовать исходный код в своем веб-сервисе? Было бы неплохо запустить экземпляр.
Will
18
Извините, но мне пришлось проголосовать против, так как я не думаю, что он действительно отвечает на исходный вопрос. Им просто нужен стандартный поиск в DNS, а не публичный IP-адрес пользователя.
Саймон Ист
30

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

https://hacking.ventures/local-ip-discovery-with-html5-webrtc-security-and-privacy-risk/

Следующий код - это копия и вставка с http://net.ipcalf.com/

// NOTE: window.RTCPeerConnection is "not a constructor" in FF22/23
var RTCPeerConnection = /*window.RTCPeerConnection ||*/ window.webkitRTCPeerConnection || window.mozRTCPeerConnection;

if (RTCPeerConnection) (function () {
    var rtc = new RTCPeerConnection({iceServers:[]});
    if (window.mozRTCPeerConnection) {      // FF needs a channel/stream to proceed
        rtc.createDataChannel('', {reliable:false});
    };  

    rtc.onicecandidate = function (evt) {
        if (evt.candidate) grepSDP(evt.candidate.candidate);
    };  
    rtc.createOffer(function (offerDesc) {
        grepSDP(offerDesc.sdp);
        rtc.setLocalDescription(offerDesc);
    }, function (e) { console.warn("offer failed", e); }); 


    var addrs = Object.create(null);
    addrs["0.0.0.0"] = false;
    function updateDisplay(newAddr) {
        if (newAddr in addrs) return;
        else addrs[newAddr] = true;
        var displayAddrs = Object.keys(addrs).filter(function (k) { return addrs[k]; }); 
        document.getElementById('list').textContent = displayAddrs.join(" or perhaps ") || "n/a";
    }   

    function grepSDP(sdp) {
        var hosts = []; 
        sdp.split('\r\n').forEach(function (line) { // c.f. http://tools.ietf.org/html/rfc4566#page-39
            if (~line.indexOf("a=candidate")) {     // http://tools.ietf.org/html/rfc4566#section-5.13
                var parts = line.split(' '),        // http://tools.ietf.org/html/rfc5245#section-15.1
                    addr = parts[4],
                    type = parts[7];
                if (type === 'host') updateDisplay(addr);
            } else if (~line.indexOf("c=")) {       // http://tools.ietf.org/html/rfc4566#section-5.7
                var parts = line.split(' '), 
                    addr = parts[2];
                updateDisplay(addr);
            }   
        }); 
    }   
})(); else {
    document.getElementById('list').innerHTML = "<code>ifconfig | grep inet | grep -v inet6 | cut -d\" \" -f2 | tail -n1</code>";
    document.getElementById('list').nextSibling.textContent = "In Chrome and Firefox your IP should display automatically, by the power of WebRTCskull.";
}   
Earizon
источник
19
это действительно новая возможность, которой не было до WebRTC - обнаружение вашего собственного IP-адреса. Но @noahjacobson задал другой вопрос - DNS-поиск IP по имени хоста из javascript.
Джин Вайнгриб
2
Очень, очень интересно, это ошибка или недоработка дизайна, в любом случае, в какой-то момент она будет исправлена, так что не годится для долгосрочных проектов
e-info128
16

Я знаю, что этот вопрос задавали очень давно, но я решил, что предлагаю более свежий ответ.

DNS через HTTPS (DoH)

Вы можете отправлять DNS-запросы через HTTPS на DNS-преобразователи, которые его поддерживают. Стандарт для DOH описан в RFC 8484 .

Это похоже на то, что предлагают все другие ответы, только DoH на самом деле является протоколом DNS через HTTPS. Это также «предлагаемый» Интернет-стандарт, и он становится довольно популярным. Например, некоторые основные браузеры либо поддерживают его, либо планируют поддерживать его (Chrome, Edge, Firefox), а Microsoft в настоящее время встраивает его в свою операционную систему.

Одна из целей DoH:

позволяя веб-приложениям получать доступ к информации DNS через существующие API-интерфейсы браузера безопасным способом в соответствии с Cross Origin Resource Sharing (CORS)

Существует инструмент с открытым исходным кодом, созданный специально для поиска DNS из веб-приложений, который называется dohjs . Он выполняет запросы формата DNS через HTTPS (DoH), как описано в RFC 8484 . Он поддерживает методы GET и POST.

Полное раскрытие информации: я - участник dohjs.

DNS через HTTPS JSON API

Если вы не хотите возиться с форматом проводов DNS, и Google, и Cloudflare предлагают JSON API для DNS через HTTPS.

Пример кода Javascript для поиска example.com с помощью Google JSON DOH API:

var response = await fetch('https://dns.google/resolve?name=example.com');
var json = await response.json();
console.log(json);

Примеры из RFC для DOH GET и POST с wireformat

Вот примеры RFC для GET и POST (см. Https://tools.ietf.org/html/rfc8484#section-4.1.1 ):

ПОЛУЧИТЬ пример:

В первом примере запроса GET используется для запроса «www.example.com».

: method = GET
: scheme = https
: author = dnsserver.example.net
: path = / dns-query? dns = AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB
accept = application / dns-message

Пример POST:

Тот же DNS-запрос для "www.example.com" с использованием метода POST будет:

: method = POST
: scheme = https
: author = dnsserver.example.net
: path = / dns-query
accept = application / dns-message
content-type = application / dns-message
content-length = 33

<33 байта, представленных следующей шестнадцатеричной кодировкой> 00 00 01 00 00 01 00 00 00 00 00 00 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01

Другие места для отправки запросов DOH

Вы можете найти список некоторых общедоступных DNS-преобразователей, поддерживающих DNS через HTTPS, в нескольких местах:

Из вышеперечисленных ресурсов я бы сказал, что список вики Curl и список DNSCrypt, вероятно, являются наиболее полными и наиболее часто обновляемыми. Страница Curl также включает список инструментов с открытым исходным кодом для DoH (серверы, прокси, клиентские библиотеки и т. Д.).

кимбо
источник
14

Размещенная версия JSONP работает как шарм, но кажется, что она использует свои ресурсы в ночное время в большинстве дней (по восточному времени), поэтому мне пришлось создать свою собственную версию.

Вот как я добился этого с помощью PHP:

<?php
header('content-type: application/json; charset=utf-8');

$data = json_encode($_SERVER['REMOTE_ADDR']);
echo $_GET['callback'] . '(' . $data . ');';
?>

Тогда Javascript будет таким же, как и раньше, только не массивом:

<script type="application/javascript">
function getip(ip){
    alert('IP Address: ' + ip);
}
</script>

<script type="application/javascript" src="http://www.anotherdomain.com/file.php?callback=getip"> </script>

Просто как тот!

Боковое примечание: обязательно очистите свой $ _GET, если вы используете его в любой общедоступной среде!

tcole
источник
Спасибо, tcole! Именно то, что я искал :)
jClark
Погодите, зачем вообще использовать $ _GET? как вы сказали, это уязвимость. Нельзя просто использовать: echo 'getip ('. $ Data. ');';
deweydb
7
Извините, но мне пришлось проголосовать против, так как я не думаю, что он действительно отвечает на исходный вопрос. Им просто нужен стандартный поиск в DNS, а не публичный IP-адрес пользователя.
Саймон Ист,
2
@SimonEast Хе. Вы изменили вопрос семилетней давности. Делайте все, что вам нужно, чтобы удовлетворить себя ;-)
tcole 08
2
Я просто отредактировал исходный вопрос, чтобы сделать его более ясным, поскольку недавно я исследовал тот же вопрос, но по какой-то причине большинство ответов здесь на самом деле не то, что просил исходный плакат, и их следует опубликовать под другим вопросом.
Саймон Ист
3

Я понимаю, что это старый вопрос, но мое решение может помочь другим.

Я считаю, что сервисы JSON (P), которые упрощают эту задачу, не работают вечно, но следующий JavaScript работает для меня хорошо на момент написания.

<script type="text/javascript">function z (x){ document.getElementById('y').innerHTML=x.query }</script>
<script type='text/javascript' src='http://ip-api.com/json/zero.eu.org?callback=z'></script>

Вышеупомянутое записывает IP-адрес моего сервера на странице, на которой он расположен, но сценарий можно изменить, чтобы найти любой IP-адрес, изменив «zero.eu.org» на другое доменное имя. Это можно увидеть в действии на моей странице по адресу: http://meon.zero.eu.org/

Невилл Хиллер
источник
Я не могу понять, как найти свой собственный IP-адрес, используя это: <! - # echo var = "REMOTE_ADDR" -> согласно вашему веб-сайту.
Джордж Карлин
Это стандартное средство «эхо», доступное на большинстве веб-серверов. См .: google.co.uk/…
Невилл Хиллиер
1
Возможно, это единственный ответ, который на самом деле правильно решает исходный вопрос, хорошо сделанный. К сожалению, он не соответствует тому, что видно со стороны клиентского компьютера , что может быть (а может и не быть) важным требованием.
Саймон Ист,
@Simon - Где написано «как видно с компьютера клиента» и почему мой ответ не соответствует этому?
Невилл Хиллиер
1
@Simon - Хороший момент, но поскольку обычно клиентский JS предоставляется сервером, есть большая вероятность, что автор / владелец сервера будет знать об этом ограничении DNS - это может быть проблемой для авторов, использующих сторонние серверы. Как указано в сообщениях здесь, существующие технологии изо всех сил пытаются удовлетворить все ограничения этого. Мой вклад был направлен на то, чтобы передать решение, которое я нашел наиболее практичным на своем сервере.
Невилл Хиллер
3

Существует сторонняя служба, которая предоставляет CORS-дружественный REST API для выполнения поиска DNS из браузера - https://exana.io/tools/dns/

user670908
источник
1

Как говорили многие, вам нужно воспользоваться внешней службой и позвонить ей. И это даст вам разрешение DNS только с точки зрения сервера.

Если этого достаточно и если вам просто нужно разрешение DNS, вы можете использовать следующий контейнер Docker:

https://github.com/kuralabs/docker-webaiodns

Конечные точки:

[GET] /ipv6/[domain]: Выполнить разрешение DNS для данного домена и вернуть связанные адреса IPv6.

 {
     "addresses": [
         "2a01:91ff::f03c:7e01:51bd:fe1f"
     ]
 }

[GET] /ipv4/[domain]: Выполнить разрешение DNS для данного домена и вернуть связанные адреса IPv4.

 {
     "addresses": [
         "139.180.232.162"
     ]
 }

Я рекомендую вам настроить свой веб-сервер на обратный прокси-сервер к контейнеру на определенной конечной точке на вашем сервере, обслуживающем ваш Javascript, и вызвать его с помощью стандартных функций Javascript Ajax.

Havok
источник
1

Для этого существует библиотека javascript DNS-JS.com .

DNS.Query("dns-js.com",
    DNS.QueryType.A,
    function(data) {
        console.log(data);
});
Фиах Рид
источник
1
По-прежнему не с точки зрения клиента. Эта библиотека делает запрос к dns-js.com/api.aspx для получения IP-адреса, который затем разрешает DNS-сервер.
wp-overwatch.com
0

Для этого потребуется сломать песочницу браузера. Попробуйте разрешить вашему серверу выполнять поиск и запрашивать его со стороны клиента через XmlHttp.

Томалак
источник
-1

В Firefox с версии 60 для этого есть встроенный API для WebExtensions:

https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/dns/resolve

Сатурн
источник
По какой-то причине browserего нет в бета-версии Firefox 64, поэтому мне интересно, было ли это удалено.
Кевин Гадьяни
3
@Sawtaytoes: доступен только для WebExtensions . Также обратите внимание, что для этого требуется dnsразрешение, и сценарий не должен запускаться как сценарий содержимого (опять же, browser.dnsон не будет там отображаться)
Saturnus
@Saturnus, это отлично работает для расширений Firefox. Есть ли шанс сделать то же самое с расширениями Chrome?
drk
-1

конечно, вы можете сделать это без использования каких-либо дополнений, только чистый javascript, используя этот метод DNS, browser.dns.resolve("example.com"); но он совместим только с FIREFOX 60, вы можете увидеть больше информации на MDN https://developer.mozilla.org/en-US/docs / Mozilla / Надстройки / WebExtensions / API / dns / resolve

Ясин Фарруд
источник
4
Этот метод доступен только в контексте WebExtension. Его нельзя использовать на веб-странице.
duskwuff -inactive-
-2

Я не думаю, что это разрешено большинством браузеров по соображениям безопасности в контексте чистого JavaScript, как задается вопрос.

Ник Крейвер
источник
5
Это не ответ. Это должен быть комментарий!
Trejder
-3

Возможно, я упустил суть, но в ответ парню из NAVY вот как браузер может сообщить вам IP-адрес «запрашивающего» (хотя, возможно, только его поставщика услуг).

Поместите тег script на страницу, которая будет отображаться клиентом, который вызывает (имеет src, указывающий на) другой сервер, который не загружен сбалансировано (я понимаю, что это означает, что вам нужен доступ ко второму серверу, но в наши дни хостинг дешев, и вы можете настроить это легко и дешево).

Вот какой код нужно добавить на страницу клиента:

На другом сервере someServerIown вам потребуется страница ASP, ASPX или PHP, которая;

----- содержит такой код сервера:

"<% Response.Write (" var clientipaddress = '"& Request.ServerVariables (" REMOTE_ADDR ") &"'; ")%>" (без внешних кавычек dbl :-))

---- и записывает этот код обратно в тег скрипта:

   var clientipaddress = '178.32.21.45';

Это эффективно создает переменную Javascript, к которой вы можете получить доступ с помощью Javascript на странице не меньше.

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

Когда пользователь отправляет или получает следующий запрос, ваш Javascript и / или форма отправляет значение переменной, которую "otherServerIown" заполнил для вас, обратно на сервер, на котором вы хотите его использовать.

Вот как я обхожусь с глупым балансировщиком нагрузки, который у нас есть, который маскирует IP-адрес клиента и заставляет его выглядеть как балансировщик нагрузки .... тупой ... тупой тупой тупой!

Я не дал точного решения, потому что у всех ситуация немного разная. Однако концепция разумна. Также обратите внимание, что если вы делаете это на странице HTTPS, ваш «otherServerIOwn» также должен доставлять в этой безопасной форме, иначе Клиент будет предупрежден о смешанном содержимом. И если у вас есть https, убедитесь, что ВСЕ ваши сертификаты действительны, иначе клиент также получит предупреждение.

Надеюсь, это кому-то поможет! Извините, на то, чтобы ответить / внести свой вклад, потребовался год. :-)

Билл С
источник
3
Извините, но мне пришлось проголосовать против, так как я не думаю, что он действительно отвечает на исходный вопрос. Им просто нужен стандартный поиск в DNS, а не публичный IP-адрес пользователя.
Саймон Ист,
-4

Моя версия такая:

php на моем сервере:

<?php
    header('content-type: application/json; charset=utf-8');

    $data = json_encode($_SERVER['REMOTE_ADDR']);


    $callback = filter_input(INPUT_GET, 
                 'callback',
                 FILTER_SANITIZE_STRING, 
                 FILTER_FLAG_ENCODE_HIGH|FILTER_FLAG_ENCODE_LOW);
    echo $callback . '(' . $data . ');';
?>

jQuery на странице:

var self = this;
$.ajax({
    url: this.url + "getip.php",
    data: null,
    type: 'GET',
    crossDomain: true,
    dataType: 'jsonp'

}).done( function( json ) {

    self.ip = json;

});

Работает кросс-домен. Он может использовать проверку статуса. Работаем над этим.

Joeri
источник
2
Извините, но мне пришлось проголосовать против, так как я не думаю, что он действительно отвечает на исходный вопрос. Им просто нужен стандартный поиск в DNS, а не публичный IP-адрес пользователя. Ваш код также не очищает $ _GET, что является большой проблемой безопасности.
Саймон Ист
@ Саймон Ист, я думаю, это еще хуже. Похоже, они хотят найти любой IP-адрес по DNS.
Joeri
@SimonEast Вы не можете доказать, что это проблема безопасности, поскольку вы не знаете, как я скомпилировал свой php. Ваша строгость просто глупа.
Joeri
-10

Если у клиента установлена ​​Java, вы можете сделать что-то вроде этого:

ipAddress = java.net.InetAddress.getLocalHost().getHostAddress();

Помимо этого, вам, вероятно, придется использовать сценарий на стороне сервера.

Алекс Форт
источник
8
Почему кто-то голосует за это? java! = javascript, это НЕ ответ.
Sven Mawby
2
Тук-тук. Кто здесь? (... долгая пауза) Java-апплет
Майк