• 0
Volt-

Прочитать DNS запрос в idUDPServer

Вопрос

Добрый день.

Кинул на форму idUDPServer1 и Memo1
В событии idUDPServer1.OnUDPRead написал:

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
begin
Memo1.Lines.Add(BytesToString(AData,13));
end;

в событии Form1.OnCreate написал:


procedure TForm1.FormCreate(Sender: TObject);
begin
 idUDPServer1.DefaultPort:=53;
 idUDPServer1.Active:=True;
end;  

Запускаю проект.
Захожу в командную строку Windows и набираю команду:
nslookup google.ru 127.0.0.1

В Memo1 появляется DNS запрос, но что то не так с кодировкой.

Первая строчка должна выглядеть так "1.0.0.127.in-addr.arpa" а вторая и последующие так "google.ru"

Безымянный1111.jpg

Как поправить?
 

Изменено пользователем Volt-

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

16 ответов на этот вопрос

  • 0
1 час назад, Volt- сказал:

В Memo1 появляется DNS запрос, но что то не так с кодировкой.

Первая строчка должна выглядеть так "1.0.0.127.in-addr.arpa" а вторая и последующие так "google.ru"

Как поправить?
 

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

Не понятно, что у Вас за проект, VCL/FMX?

Скорее всего, данные приходят в UTF8, а в TMemo пишутся строки ANSI (может наоборот). В любом случае необходимо делать приведение входящих данных к родной кодировке String.

 

Изменено пользователем Pax Beach

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 1

Все правильно получаете, кодировка тут не при чем. Согласно спецификации "DNS Packet Structure", вы получаете не строку, а пакет который нужно разобрать. К примеру если запрос будет "nslookup www.google.ru 127.0.0.1", то там где вы получаете имя хоста будет строка "''#3'www'#6'google'#2'ru'#0#0#1#0#1".

Парсинг простейший:

#3 - означает что далее идут 3 символа хоста
'www' - вот ожидаемые 3 символа
#6 - далее идут еще 6 символов хоста
'google' - ага, вот они
#2 - ну и еще 2 символа
'ru' - ура, они здесь
#0 - конец имени хоста, складываем в кучу, перемежая точками и получаем www.google.ru
#0 - дальше у нас служебная информация...
#1
#0
#1

Вот как то так.

P.S. А зачем вам на таком низком уровне работать? Может использовать IdDNSServer : TIdDNSServer ?

P.P.S. Правильно Memo1.Lines.Add(BytesToString(AData,12)); //(12, а не 13)

Изменено пользователем Евгений Корепов
Pax Beach, Kitty, Rusland и 3 другим понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Евгений Корепов

Спасибо за наглядное разъяснение.
С парсингом разобрался. Сейчас запрос приходит как нужно.

Изменено пользователем Volt-

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Теперь проблема в следующем. Получив запрос DNS я его отправляю через idDNSResolve и ответ отправить обратно в командную строку.

procedure TForm1.UDPBeforeQuery(ABinding: TIdSocketHandle;
  ADNSHeader: TDNSHeader; var ADNSQuery: TIdBytes);
begin
form1.IdDNSResolver1.Resolve('google.ru');

form1.IdDNSResolver1.DNSHeader.AA:=ADNSHeader.AA;
form1.IdDNSResolver1.DNSHeader.ANCount:=ADNSHeader.ANCount;
form1.IdDNSResolver1.DNSHeader.ARCount:=ADNSHeader.ARCount;
form1.IdDNSResolver1.DNSHeader.BitCode:=ADNSHeader.BitCode;
form1.IdDNSResolver1.DNSHeader.ID:=ADNSHeader.ID;
form1.IdDNSResolver1.DNSHeader.NSCount:=ADNSHeader.NSCount;
form1.IdDNSResolver1.DNSHeader.Qr:=1;
form1.IdDNSResolver1.DNSHeader.OpCode:=ADNSHeader.OpCode;
form1.IdDNSResolver1.DNSHeader.QDCount:=ADNSHeader.QDCount;
form1.IdDNSResolver1.DNSHeader.RA:=ADNSHeader.RA;
form1.IdDNSResolver1.DNSHeader.RCode:=ADNSHeader.RCode;
form1.IdDNSResolver1.DNSHeader.RD:=ADNSHeader.RD;
form1.IdDNSResolver1.DNSHeader.TC:=ADNSHeader.TC;

ABinding.SendTo(ABinding.PeerIP,ABinding.PeerPort,form1.IdDNSResolver1.DNSHeader.GenerateBinaryHeader);
end;

Но в командной строке ответ не отображается. Как правильно его отправить?

Изменено пользователем Volt-

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Отправлять ответ вы должны там же где получаете запрос

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
begin
  ..
  ..
  ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, Ваши данные...);
end;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

А как сформировать эти данные для отправки в IdDNSResolver1?
Уже всю голову сломал. =(
 

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
begin
form1.IdDNSResolver1.Resolve('google.ru');
 
ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort,form1.IdDNSResolver1.ГдеХранитсяОтветВФорматеTBytes);
end;

Я не могу понять как мне сделать пакет для отправки ответа. Как TBytes сформировать.
Или я чего то не так понимаю?

Изменено пользователем Volt-

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Не понял ваш вопрос. Приложите ваш проект (или полный листинг), трудно понимать вырванные из контекста вопросы и куски кода.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Пример приложил.
Запускаете его, заходите в командную строку и набираете nslookup google.ru 127.0.0.1 и увидите что в неё (командную строку) не придет ответ от нашего сервера DNS.
Вопрос в том, как правильно сформировать ответ что бы он дошел до командной строки.

DNS.rar

Изменено пользователем Volt-

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Volt-, на строке MainForm.IdDNSResolver.Resolve(S); ругается:

Цитата

Project DNS.exe raised exception class EIdDnsResolverError with message 'DNS Server Reports Query Name Error'.


До ABinding.SendTo не доходит управление

 

Изменено пользователем Rusland

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Странно, у меня на Delphi XE7 на эту строчку не ругается.
Попробуйте для теста в ручную забить.
MainForm.IdDNSResolver.Resolve('google.ru')

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Попробовал, теперь это место проходит...  

Может ответ кодировать надо?

Изменено пользователем Rusland

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Rusland
При всем уважении к сообществу, я не знаю как нужно формировать ответ. Прошу помощи у гуру.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
2 часа назад, Volt- сказал:

Пример приложил.
Запускаете его, заходите в командную строку и набираете nslookup google.ru 127.0.0.1 и увидите что в неё (командную строку) не придет ответ от нашего сервера DNS.
Вопрос в том, как правильно сформировать ответ что бы он дошел до командной строки.

DNS.rar

Для начал у вас не правильно работает function ReplaceSpecSymbol, она оставляет спецсимволы в конце строки. Вот накидал правильно работающую:

function ReplaceSpecSymbol(S: String): String;
var Count : Integer;
begin
  Count:=0;
  Result:='';
  while True do
  begin
    Count:=Ord(S.Chars[0]);
    Result:=Result+S.Substring(1,Count)+'.';
    S:=S.Remove(0,Count+1);
    if Ord(S.Chars[0])=0 Then
      break;
  end;
  Result:=Result.TrimRight(['.']);
end;

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

Вот код процедуры, но надо разобраться что слать:

procedure TMainForm.IdUDPServerUDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var S, Domain: String;
    I : Integer;
    ABuffer : TIdBytes;
begin
  S:=ReplaceSpecSymbol(BytesToString(AData,12));
  Memo_Log.Lines.Add(S);
  if Pos('in-addr.arpa',S)=0 then
  begin
    IdDNSResolver.Resolve(S);
    for I := 0 to IdDNSResolver.QueryResult.Count-1 do
      if IdDNSResolver.QueryResult[I].RecType = qtA then
      begin
        S:=TARecord(IdDNSResolver.QueryResult[I]).IPAddress;
        Memo_Log.Lines.Add('IdDNSResolver: '+S);
      end;
// Вот дальше не знаю что именно пересылать
//   ABuffer:=DNSHeader.GenerateBinaryHeader;
//   ABuffer:=IdDNSResolver.PlainTextResult;
//   ABuffer:=ABuffer+IdDNSResolver.InternalQuery;
//   ABuffer:=IdDNSResolver.InternalQuery;
    ABinding.Send(ABuffer);
  end;

Вы можете поразбираться с помощью простейшего DNS прокси, по крайней мере будете видеть что идет в запросе и что в ответе. Код ниже, только пропишите глобальную переменную ALocalPort : Integer, для запоминания забинденного порта на 127.0.0.1

procedure TMainForm.IdUDPServerUDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
Const ExternalDNSHost = '8.8.8.8';
      LocalHost = '127.0.0.1';
begin
  if ABinding.PeerIP.Equals(LocalHost) then // если запрос с локального, пересылаем на внешний dns
  begin
    ALocalPort:=ABinding.PeerPort;
    IdUDPServer.SendBuffer(ExternalDNSHost,53,AData);
  end;
  if ABinding.PeerIP.Equals(ExternalDNSHost) then // если с внешнего, пересылаем на локальный
    IdUDPServer.SendBuffer(LocalHost,ALocalPort,AData);
  exit;
end;

в коммандной строке используйте "nslookup -retry=1 -timeout=30 google.ru 127.0.0.1 " (один повтор запроса, чтоб не засирать отладку и таймаут сколько нужно секунд, что не отвалился запрос пока будете разбираться)

Rusland и Volt- понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Попробовал сделать через idDNSServer, но ответ так и не приходит в командную строку.
Выкладываю исходник. DNS2.rar
Запускаете его, заходите в командную строку и набираете nslookup google.ru 127.0.0.1 и увидите что в неё (командную строку) не придет ответ от нашего сервера DNS.
Вопрос в том, как правильно сформировать ответ что бы он дошел до командной строки.
Если у кого получиться добиться получения ответа в командно строке, напиши пожалуйста. Очень хочется разобраться в вопросе.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Вот посмотрите, просто и красиво TSimpleDNSServer    http://www.delphipraxis.net/87433-dns-server-mit-indys-tiddnsserver-%3D-verwirrung.html

Rusland понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
9 минут назад, Евгений Корепов сказал:

Вот посмотрите, просто и красиво TSimpleDNSServer    http://www.delphipraxis.net/87433-dns-server-mit-indys-tiddnsserver-%3D-verwirrung.html

Спасибо, я раньше находил эту статью, но по ней ещё больше вопросов.
Пытался воспроизвести у себя, но ругается на WriteToBytes, WordToBytes, LongWordToBytes, ToBytes, BitsToByte, BytesToWord, ReadFromBytes, ByteToBits.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!


Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.


Войти сейчас

  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу