home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 November / Chip_2002-11_cd1.bin / zkuste / delphi / kompon / d3456 / SYNAPSE.ZIP / source / lib / DNSsend.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-07-07  |  11.7 KB  |  384 lines

  1. {==============================================================================|
  2. | Project : Delphree - Synapse                                   | 001.002.000 |
  3. |==============================================================================|
  4. | Content: DNS client                                                          |
  5. |==============================================================================|
  6. | Copyright (c)1999-2002, Lukas Gebauer                                        |
  7. | All rights reserved.                                                         |
  8. |                                                                              |
  9. | Redistribution and use in source and binary forms, with or without           |
  10. | modification, are permitted provided that the following conditions are met:  |
  11. |                                                                              |
  12. | Redistributions of source code must retain the above copyright notice, this  |
  13. | list of conditions and the following disclaimer.                             |
  14. |                                                                              |
  15. | Redistributions in binary form must reproduce the above copyright notice,    |
  16. | this list of conditions and the following disclaimer in the documentation    |
  17. | and/or other materials provided with the distribution.                       |
  18. |                                                                              |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may      |
  20. | be used to endorse or promote products derived from this software without    |
  21. | specific prior written permission.                                           |
  22. |                                                                              |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE    |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE   |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR  |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL       |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR   |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER   |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT           |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY    |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH  |
  33. | DAMAGE.                                                                      |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c)2000,2001.                |
  37. | All Rights Reserved.                                                         |
  38. |==============================================================================|
  39. | Contributor(s):                                                              |
  40. |==============================================================================|
  41. | History: see HISTORY.HTM from distribution package                           |
  42. |          (Found at URL: http://www.ararat.cz/synapse/)                       |
  43. |==============================================================================}
  44.  
  45. // RFC-1035, RFC-1183, RFC1706, RFC1712, RFC2163, RFC2230
  46.  
  47. {$Q-}
  48. {$WEAKPACKAGEUNIT ON}
  49.  
  50. unit DNSsend;
  51.  
  52. interface
  53.  
  54. uses
  55.   SysUtils, Classes,
  56.   blcksock, SynaUtil;
  57.  
  58. const
  59.   cDnsProtocol = 'domain';
  60.  
  61.   QTYPE_A = 1;
  62.   QTYPE_NS = 2;
  63.   QTYPE_MD = 3;
  64.   QTYPE_MF = 4;
  65.   QTYPE_CNAME = 5;
  66.   QTYPE_SOA = 6;
  67.   QTYPE_MB = 7;
  68.   QTYPE_MG = 8;
  69.   QTYPE_MR = 9;
  70.   QTYPE_NULL = 10;
  71.   QTYPE_WKS = 11; //
  72.   QTYPE_PTR = 12;
  73.   QTYPE_HINFO = 13;
  74.   QTYPE_MINFO = 14;
  75.   QTYPE_MX = 15;
  76.   QTYPE_TXT = 16;
  77.  
  78.   QTYPE_RP = 17;
  79.   QTYPE_AFSDB = 18;
  80.   QTYPE_X25 = 19;
  81.   QTYPE_ISDN = 20;
  82.   QTYPE_RT = 21;
  83.   QTYPE_NSAP = 22;
  84.   QTYPE_NSAPPTR = 23;
  85.   QTYPE_SIG = 24; // RFC-2065
  86.   QTYPE_KEY = 25; // RFC-2065
  87.   QTYPE_PX = 26;
  88.   QTYPE_GPOS = 27;
  89.   QTYPE_AAAA = 28; // IP6 Address  [Susan Thomson]
  90.   QTYPE_LOC = 29; // RFC-1876
  91.   QTYPE_NXT = 30; // RFC-2065
  92.  
  93.   QTYPE_SRV = 33; // RFC-2052
  94.   QTYPE_NAPTR = 35; // RFC-2168
  95.   QTYPE_KX = 36;
  96.  
  97.   QTYPE_AXFR = 252; //
  98.   QTYPE_MAILB = 253; //
  99.   QTYPE_MAILA = 254; //
  100.   QTYPE_ALL = 255; //
  101.  
  102. type
  103.   TDNSSend = class(TSynaClient)
  104.   private
  105.     FRCode: Integer;
  106.     FBuffer: string;
  107.     FSock: TUDPBlockSocket;
  108.     function CompressName(const Value: string): string;
  109.     function CodeHeader: string;
  110.     function CodeQuery(const Name: string; QType: Integer): string;
  111.     function DecodeLabels(var From: Integer): string;
  112.     function DecodeResource(var i: Integer; const Name: string;
  113.       QType: Integer): string;
  114.   public
  115.     constructor Create;
  116.     destructor Destroy; override;
  117.     function DNSQuery(Name: string; QType: Integer;
  118.       const Reply: TStrings): Boolean;
  119.   published
  120.     property RCode: Integer read FRCode;
  121.     property Sock: TUDPBlockSocket read FSock;
  122.   end;
  123.  
  124. function GetMailServers(const DNSHost, Domain: string;
  125.   const Servers: TStrings): Boolean;
  126.  
  127. implementation
  128.  
  129. constructor TDNSSend.Create;
  130. begin
  131.   inherited Create;
  132.   FSock := TUDPBlockSocket.Create;
  133.   FSock.CreateSocket;
  134.   FTimeout := 5000;
  135.   FTargetPort := cDnsProtocol;
  136. end;
  137.  
  138. destructor TDNSSend.Destroy;
  139. begin
  140.   FSock.Free;
  141.   inherited Destroy;
  142. end;
  143.  
  144. function TDNSSend.CompressName(const Value: string): string;
  145. var
  146.   n: Integer;
  147.   s: string;
  148. begin
  149.   Result := '';
  150.   if Value = '' then
  151.     Result := #0
  152.   else
  153.   begin
  154.     s := '';
  155.     for n := 1 to Length(Value) do
  156.       if Value[n] = '.' then
  157.       begin
  158.         Result := Result + Char(Length(s)) + s;
  159.         s := '';
  160.       end
  161.       else
  162.         s := s + Value[n];
  163.     if s <> '' then
  164.       Result := Result + Char(Length(s)) + s;
  165.     Result := Result + #0;
  166.   end;
  167. end;
  168.  
  169. function TDNSSend.CodeHeader: string;
  170. begin
  171.   Randomize;
  172.   Result := CodeInt(Random(32767)); // ID
  173.   Result := Result + CodeInt($0100); // flags
  174.   Result := Result + CodeInt(1); // QDCount
  175.   Result := Result + CodeInt(0); // ANCount
  176.   Result := Result + CodeInt(0); // NSCount
  177.   Result := Result + CodeInt(0); // ARCount
  178. end;
  179.  
  180. function TDNSSend.CodeQuery(const Name: string; QType: Integer): string;
  181. begin
  182.   Result := CompressName(Name);
  183.   Result := Result + CodeInt(QType);
  184.   Result := Result + CodeInt(1); // Type INTERNET
  185. end;
  186.  
  187. function TDNSSend.DecodeLabels(var From: Integer): string;
  188. var
  189.   l, f: Integer;
  190. begin
  191.   Result := '';
  192.   while True do
  193.   begin
  194.     l := Ord(FBuffer[From]);
  195.     Inc(From);
  196.     if l = 0 then
  197.       Break;
  198.     if Result <> '' then
  199.       Result := Result + '.';
  200.     if (l and $C0) = $C0 then
  201.     begin
  202.       f := l and $3F;
  203.       f := f * 256 + Ord(FBuffer[From]) + 1;
  204.       Inc(From);
  205.       Result := Result + DecodeLabels(f);
  206.       Break;
  207.     end
  208.     else
  209.     begin
  210.       Result := Result + Copy(FBuffer, From, l);
  211.       Inc(From, l);
  212.     end;
  213.   end;
  214. end;
  215.  
  216. function TDNSSend.DecodeResource(var i: Integer; const Name: string;
  217.   QType: Integer): string;
  218. var
  219.   Rname: string;
  220.   RType, Len, j, x, n: Integer;
  221. begin
  222.   Result := '';
  223.   Rname := DecodeLabels(i);
  224.   RType := DecodeInt(FBuffer, i);
  225.   Inc(i, 8);
  226.   Len := DecodeInt(FBuffer, i);
  227.   Inc(i, 2); // i point to begin of data
  228.   j := i;
  229.   i := i + len; // i point to next record
  230.   if (Name = Rname) and (QType = RType) then
  231.   begin
  232.     case RType of
  233.       QTYPE_A:
  234.         begin
  235.           Result := IntToStr(Ord(FBuffer[j]));
  236.           Inc(j);
  237.           Result := Result + '.' + IntToStr(Ord(FBuffer[j]));
  238.           Inc(j);
  239.           Result := Result + '.' + IntToStr(Ord(FBuffer[j]));
  240.           Inc(j);
  241.           Result := Result + '.' + IntToStr(Ord(FBuffer[j]));
  242.         end;
  243.       QTYPE_NS, QTYPE_MD, QTYPE_MF, QTYPE_CNAME, QTYPE_MB,
  244.         QTYPE_MG, QTYPE_MR, QTYPE_PTR, QTYPE_X25, QTYPE_NSAP,
  245.         QTYPE_NSAPPTR:
  246.         Result := DecodeLabels(j);
  247.       QTYPE_SOA:
  248.         begin
  249.           Result := DecodeLabels(j);
  250.           Result := Result + ',' + DecodeLabels(j);
  251.           for n := 1 to 5 do
  252.           begin
  253.             x := DecodeInt(FBuffer, j) * 65536 + DecodeInt(FBuffer, j + 2);
  254.             Inc(j, 4);
  255.             Result := Result + ',' + IntToStr(x);
  256.           end;
  257.         end;
  258.       QTYPE_NULL:
  259.         begin
  260.         end;
  261.       QTYPE_WKS:
  262.         begin
  263.         end;
  264.       QTYPE_HINFO, QTYPE_MINFO, QTYPE_RP, QTYPE_ISDN:
  265.         begin
  266.           Result := DecodeLabels(j);
  267.           Result := Result + ',' + DecodeLabels(j);
  268.         end;
  269.       QTYPE_MX, QTYPE_AFSDB, QTYPE_RT, QTYPE_KX:
  270.         begin
  271.           x := DecodeInt(FBuffer, j);
  272.           Inc(j, 2);
  273.           Result := IntToStr(x);
  274.           Result := Result + ',' + DecodeLabels(j);
  275.         end;
  276.       QTYPE_TXT:
  277.         Result := DecodeLabels(j);
  278.       QTYPE_GPOS:
  279.         begin
  280.           Result := DecodeLabels(j);
  281.           Result := Result + ',' + DecodeLabels(j);
  282.           Result := Result + ',' + DecodeLabels(j);
  283.         end;
  284.       QTYPE_PX:
  285.         begin
  286.           x := DecodeInt(FBuffer, j);
  287.           Inc(j, 2);
  288.           Result := IntToStr(x);
  289.           Result := Result + ',' + DecodeLabels(j);
  290.           Result := Result + ',' + DecodeLabels(j);
  291.         end;
  292.     end;
  293.   end;
  294. end;
  295.  
  296. function TDNSSend.DNSQuery(Name: string; QType: Integer;
  297.   const Reply: TStrings): Boolean;
  298. var
  299.   n, i: Integer;
  300.   flag, qdcount, ancount, nscount, arcount: Integer;
  301.   s: string;
  302. begin
  303.   Result := False;
  304.   Reply.Clear;
  305.   if IsIP(Name) then
  306.     Name := ReverseIP(Name) + '.in-addr.arpa';
  307.   FBuffer := CodeHeader + CodeQuery(Name, QType);
  308.   FSock.Bind(FIPInterface, cAnyPort);
  309.   FSock.Connect(FTargetHost, FTargetPort);
  310.   FSock.SendString(FBuffer);
  311.   FBuffer := FSock.RecvPacket(FTimeout);
  312.   if (FSock.LastError = 0) and (Length(FBuffer) > 13) then
  313.   begin
  314.     flag := DecodeInt(FBuffer, 3);
  315.     FRCode := Flag and $000F;
  316.     if FRCode = 0 then
  317.     begin
  318.       qdcount := DecodeInt(FBuffer, 5);
  319.       ancount := DecodeInt(FBuffer, 7);
  320.       nscount := DecodeInt(FBuffer, 9);
  321.       arcount := DecodeInt(FBuffer, 11);
  322.       i := 13; //begin of body
  323.       if qdcount > 0 then //skip questions
  324.         for n := 1 to qdcount do
  325.         begin
  326.           while (FBuffer[i] <> #0) and ((Ord(FBuffer[i]) and $C0) <> $C0) do
  327.             Inc(i);
  328.           Inc(i, 5);
  329.         end;
  330.       if ancount > 0 then
  331.         for n := 1 to ancount do
  332.         begin
  333.           s := DecodeResource(i, Name, QType);
  334.           if s <> '' then
  335.             Reply.Add(s);
  336.         end;
  337.       Result := True;
  338.     end;
  339.   end;
  340. end;
  341.  
  342. {==============================================================================}
  343.  
  344. function GetMailServers(const DNSHost, Domain: string;
  345.   const Servers: TStrings): Boolean;
  346. var
  347.   DNS: TDNSSend;
  348.   t: TStringList;
  349.   n, m, x: Integer;
  350. begin
  351.   Result := False;
  352.   Servers.Clear;
  353.   t := TStringList.Create;
  354.   DNS := TDNSSend.Create;
  355.   try
  356.     DNS.TargetHost := DNSHost;
  357.     if DNS.DNSQuery(Domain, QType_MX, t) then
  358.     begin
  359.       { normalize preference number to 5 digits }
  360.       for n := 0 to t.Count - 1 do
  361.       begin
  362.         x := Pos(',', t[n]);
  363.         if x > 0 then
  364.           for m := 1 to 6 - x do
  365.             t[n] := '0' + t[n];
  366.       end;
  367.       { sort server list }
  368.       t.Sorted := True;
  369.       { result is sorted list without preference numbers }
  370.       for n := 0 to t.Count - 1 do
  371.       begin
  372.         x := Pos(',', t[n]);
  373.         Servers.Add(Copy(t[n], x + 1, Length(t[n]) - x));
  374.       end;
  375.       Result := True;
  376.     end;
  377.   finally
  378.     DNS.Free;
  379.     t.Free;
  380.   end;
  381. end;
  382.  
  383. end.
  384.