Чи можу я виконати пошук 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-адресою, що може призвести людей до неправильного напрямку).
earizon

1
@earizon - ваша відповідь на інше питання - як знайти власну приватну IP-адресу.
Gene Vayngrib

Проблема через CGI із хмари полягала б у виявленні ips хостів інтрамережі, що неможливо зовні. Вам доведеться скористатися локальною службою на машині або в інтрамережі.
Tzahi Fadida

Існує новий запропонований стандарт Інтернету, який дозволяє надсилати запити DNS через HTTPS (див. Цю відповідь stackoverflow.com/a/58299823/9638991 ). Насправді він працює в основному так само, як і скрипт cgi-bin :) (за винятком того, що він був стандартизований IETF і безліч великих компаній його підтримують)
Кімбо,

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
Не могли б ви опублікувати джерело на своїй веб-службі? Було б непогано запустити екземпляр.
Буде

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.";
}   

19
це справді нова можливість, яка не існувала до WebRTC - виявити власну IP-адресу. Але @noahjacobson задав інше питання - пошук DNS IP за іменем хосту з javascript.
Gene Vayngrib

2
Дуже, дуже цікаво, це помилка або недолік дизайну, в будь-якому випадку це колись буде виправлено, тому не буде корисним для довгострокових проектів
e-info128

15

Я знаю, що це запитання було задано дуже давно, але я вирішив, що запропоную більш пізню відповідь.

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 за допомогою API JSON DOH від Google:

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

Приклади з RFC для DOH GET та POST із дротовим форматом

Ось приклади, які RFC дає як для GET, так і для POST (див. Https://tools.ietf.org/html/rfc8484#section-4.1.1 ):

Приклад GET:

Перший приклад запиту використовує GET для запиту "www.example.com".

: method = GET
: схема = https
: Authority = dnsserver.example.net
: path = / dns-query? dns = AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB
accept = application / dns-message

Приклад POST:

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

: method = POST
: схема = https
: Authority = 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 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! Саме те, що я шукав :)
jClark

Зачекайте хвилину, навіщо взагалі використовувати $ _GET? як ви сказали, це вразливість. Не можна було просто використовувати: echo 'getip ('. $ Data. ');';
deweydb

7
Вибачте, але довелося проголосувати проти, оскільки я не думаю, що це насправді відповідає на вихідне питання. Вони просто хочуть стандартний пошук DNS, а не загальнодоступний IP користувача.
Саймон Іст

2
@SimonEast Хе. Ви змінили питання 7-річного питання. Робіть все, що вам потрібно, щоб задовольнити себе ;-)
tcole

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 - Де написано "як видно з комп'ютера клієнта" і чому моя відповідь не відповідає цьому?
Neville Hillyer,

1
@Simon - Хороший момент, але оскільки зазвичай клієнтський JS постачається на сервері, існує велика ймовірність того, що автор / власник сервера буде знати про це обмеження DNS - це може бути проблемою для авторів, які використовують сторонні сервери. Як зазначено в публікаціях тут, існуюча технологія намагається задовольнити всі обмеження щодо цього. Мій внесок мав на меті передати рішення, яке я знайшов найбільш практичним на своєму сервері.
Невілл Хілліер,


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, і викликати його, використовуючи ваші стандартні функції Ajax Javascript.


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 має вбудований API для цього починаючи з v60, для WebExtensions:

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


З якихось причин browserу Firefox 64 beta не існує, тому мені цікаво, чи було це видалено.
Sawtaytoes

3
@Sawtaytoes: Він доступний лише для WebExtensions . Також зверніть увагу, що для цього потрібен dnsдозвіл, і сценарій не повинен працювати як сценарій змісту (як і знову, там browser.dnsне буде виставлено)
Сатурн,

@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 / resolution


4
Цей метод доступний лише в контексті розширення Web. Не може бути використана веб-сторінкою.
сутінки-неактивні-

-2

Я не думаю, що це дозволяється більшістю браузерів з міркувань безпеки, в чистому контексті JavaScript, як постає питання.


5
Це не відповідь. Це має бути коментар!
трейдер

-3

Можливо, я пропустив суть, але у відповідь хлопцеві NAVY ось як браузер може повідомити вам IP-адресу "запитувача" (хоча, можливо, лише їх постачальника послуг).

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

Це такий код, який потрібно додати на сторінку клієнта:

На іншому сервері "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;

});

Це працює міждоменне. Він може використовувати перевірку стану. Працюємо над цим.


2
Вибачте, але довелося проголосувати проти, оскільки я не думаю, що це насправді відповідає на вихідне питання. Вони просто хочуть стандартний пошук DNS, а не загальнодоступний IP користувача. Ваш код також не дезінфікує $ _GET, що є великою проблемою безпеки.
Саймон Іст

@Simon East Я думаю, що це ще гірше. Схоже, вони хочуть шукати будь-які IP за DNS.
Joeri

@SimonEast Ви не можете довести, що це проблема безпеки, оскільки ви не уявляєте, як я скомпілював свій php. Ваша строгість просто безглузда.
Joeri

-10

Якщо на клієнті встановлена ​​Java, ви можете зробити щось подібне:

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

Крім цього, вам, мабуть, доведеться використовувати сценарій на стороні сервера.


8
Чому хтось голосує за це? java! = javascript, це НЕ відповідь.
Свен Моубі,

2
Стук-стук. Хто там? (... довга пауза) Java-аплет
Майк Нельсон,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.