• 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

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


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

Все правильно получаете, кодировка тут не при чем. Согласно спецификации "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)

Изменено пользователем Евгений Корепов

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


Ссылка на сообщение
Поделиться на другие сайты
  • 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 " (один повтор запроса, чтоб не засирать отладку и таймаут сколько нужно секунд, что не отвалился запрос пока будете разбираться)

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


Ссылка на сообщение
Поделиться на другие сайты
  • 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

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


Ссылка на сообщение
Поделиться на другие сайты
  • 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 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу