Перейти к содержанию
Fire Monkey от А до Я
  • 0

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


Volt-

Вопрос

Добрый день.

Кинул на форму 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-
Ссылка на комментарий

Рекомендуемые сообщения

  • 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

Теперь проблема в следующем. Получив запрос 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

Пример приложил.
Запускаете его, заходите в командную строку и набираете 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
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
9 минут назад, Евгений Корепов сказал:

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

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

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

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