home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 December / Chip_2001-12_cd1.bin / zkuste / delphi / unity / d23456 / SYNAPSE.ZIP / source / lib / DNSsend.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-09-23  |  10.3 KB  |  368 lines

  1. {==============================================================================|
  2. | Project : Delphree - Synapse                                   | 001.001.004 |
  3. |==============================================================================|
  4. | Content: DNS client                                                          |
  5. |==============================================================================|
  6. | The contents of this file are subject to the Mozilla Public License Ver. 1.1 |
  7. | (the "License"); you may not use this file except in compliance with the     |
  8. | License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ |
  9. |                                                                              |
  10. | Software distributed under the License is distributed on an "AS IS" basis,   |
  11. | WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for |
  12. | the specific language governing rights and limitations under the License.    |
  13. |==============================================================================|
  14. | The Original Code is Synapse Delphi Library.                                 |
  15. |==============================================================================|
  16. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  17. | Portions created by Lukas Gebauer are Copyright (c)2000,2001.                |
  18. | All Rights Reserved.                                                         |
  19. |==============================================================================|
  20. | Contributor(s):                                                              |
  21. |==============================================================================|
  22. | History: see HISTORY.HTM from distribution package                           |
  23. |          (Found at URL: http://www.ararat.cz/synapse/)                       |
  24. |==============================================================================}
  25.  
  26. // RFC-1035, RFC-1183, RFC1706, RFC1712, RFC2163, RFC2230
  27.  
  28. {$Q-}
  29. {$WEAKPACKAGEUNIT ON}
  30.  
  31. unit DNSsend;
  32.  
  33. interface
  34.  
  35. uses
  36.   SysUtils, Classes,
  37.   blcksock, SynaUtil;
  38.  
  39. const
  40.   cDnsProtocol = 'domain';
  41.  
  42.   QTYPE_A = 1;
  43.   QTYPE_NS = 2;
  44.   QTYPE_MD = 3;
  45.   QTYPE_MF = 4;
  46.   QTYPE_CNAME = 5;
  47.   QTYPE_SOA = 6;
  48.   QTYPE_MB = 7;
  49.   QTYPE_MG = 8;
  50.   QTYPE_MR = 9;
  51.   QTYPE_NULL = 10;
  52.   QTYPE_WKS = 11; //
  53.   QTYPE_PTR = 12;
  54.   QTYPE_HINFO = 13;
  55.   QTYPE_MINFO = 14;
  56.   QTYPE_MX = 15;
  57.   QTYPE_TXT = 16;
  58.  
  59.   QTYPE_RP = 17;
  60.   QTYPE_AFSDB = 18;
  61.   QTYPE_X25 = 19;
  62.   QTYPE_ISDN = 20;
  63.   QTYPE_RT = 21;
  64.   QTYPE_NSAP = 22;
  65.   QTYPE_NSAPPTR = 23;
  66.   QTYPE_SIG = 24; // RFC-2065
  67.   QTYPE_KEY = 25; // RFC-2065
  68.   QTYPE_PX = 26;
  69.   QTYPE_GPOS = 27;
  70.   QTYPE_AAAA = 28; // IP6 Address  [Susan Thomson]
  71.   QTYPE_LOC = 29; // RFC-1876
  72.   QTYPE_NXT = 30; // RFC-2065
  73.  
  74.   QTYPE_SRV = 33; // RFC-2052
  75.   QTYPE_NAPTR = 35; // RFC-2168
  76.   QTYPE_KX = 36;
  77.  
  78.   QTYPE_AXFR = 252; //
  79.   QTYPE_MAILB = 253; //
  80.   QTYPE_MAILA = 254; //
  81.   QTYPE_ALL = 255; //
  82.  
  83. type
  84.   TDNSSend = class(TObject)
  85.   private
  86.     FTimeout: Integer;
  87.     FDNSHost: string;
  88.     FRCode: Integer;
  89.     FBuffer: string;
  90.     FSock: TUDPBlockSocket;
  91.     function CompressName(const Value: string): string;
  92.     function CodeHeader: string;
  93.     function CodeQuery(const Name: string; QType: Integer): string;
  94.     function DecodeLabels(var From: Integer): string;
  95.     function DecodeResource(var i: Integer; const Name: string;
  96.       QType: Integer): string;
  97.   public
  98.     constructor Create;
  99.     destructor Destroy; override;
  100.     function DNSQuery(Name: string; QType: Integer;
  101.       const Reply: TStrings): Boolean;
  102.   published
  103.     property Timeout: Integer read FTimeout Write FTimeout;
  104.     property DNSHost: string read FDNSHost Write FDNSHost;
  105.     property RCode: Integer read FRCode;
  106.     property Sock: TUDPBlockSocket read FSock;
  107.   end;
  108.  
  109. function GetMailServers(const DNSHost, Domain: string;
  110.   const Servers: TStrings): Boolean;
  111.  
  112. implementation
  113.  
  114. constructor TDNSSend.Create;
  115. begin
  116.   inherited Create;
  117.   FSock := TUDPBlockSocket.Create;
  118.   FSock.CreateSocket;
  119.   FTimeout := 5000;
  120.   FDNSHost := cLocalhost;
  121. end;
  122.  
  123. destructor TDNSSend.Destroy;
  124. begin
  125.   FSock.Free;
  126.   inherited Destroy;
  127. end;
  128.  
  129. function TDNSSend.CompressName(const Value: string): string;
  130. var
  131.   n: Integer;
  132.   s: string;
  133. begin
  134.   Result := '';
  135.   if Value = '' then
  136.     Result := #0
  137.   else
  138.   begin
  139.     s := '';
  140.     for n := 1 to Length(Value) do
  141.       if Value[n] = '.' then
  142.       begin
  143.         Result := Result + Char(Length(s)) + s;
  144.         s := '';
  145.       end
  146.       else
  147.         s := s + Value[n];
  148.     if s <> '' then
  149.       Result := Result + Char(Length(s)) + s;
  150.     Result := Result + #0;
  151.   end;
  152. end;
  153.  
  154. function TDNSSend.CodeHeader: string;
  155. begin
  156.   Randomize;
  157.   Result := CodeInt(Random(32767)); // ID
  158.   Result := Result + CodeInt($0100); // flags
  159.   Result := Result + CodeInt(1); // QDCount
  160.   Result := Result + CodeInt(0); // ANCount
  161.   Result := Result + CodeInt(0); // NSCount
  162.   Result := Result + CodeInt(0); // ARCount
  163. end;
  164.  
  165. function TDNSSend.CodeQuery(const Name: string; QType: Integer): string;
  166. begin
  167.   Result := CompressName(Name);
  168.   Result := Result + CodeInt(QType);
  169.   Result := Result + CodeInt(1); // Type INTERNET
  170. end;
  171.  
  172. function TDNSSend.DecodeLabels(var From: Integer): string;
  173. var
  174.   l, f: Integer;
  175. begin
  176.   Result := '';
  177.   while True do
  178.   begin
  179.     l := Ord(FBuffer[From]);
  180.     Inc(From);
  181.     if l = 0 then
  182.       Break;
  183.     if Result <> '' then
  184.       Result := Result + '.';
  185.     if (l and $C0) = $C0 then
  186.     begin
  187.       f := l and $3F;
  188.       f := f * 256 + Ord(FBuffer[From]) + 1;
  189.       Inc(From);
  190.       Result := Result + DecodeLabels(f);
  191.       Break;
  192.     end
  193.     else
  194.     begin
  195.       Result := Result + Copy(FBuffer, From, l);
  196.       Inc(From, l);
  197.     end;
  198.   end;
  199. end;
  200.  
  201. function TDNSSend.DecodeResource(var i: Integer; const Name: string;
  202.   QType: Integer): string;
  203. var
  204.   Rname: string;
  205.   RType, Len, j, x, n: Integer;
  206. begin
  207.   Result := '';
  208.   Rname := DecodeLabels(i);
  209.   RType := DecodeInt(FBuffer, i);
  210.   Inc(i, 8);
  211.   Len := DecodeInt(FBuffer, i);
  212.   Inc(i, 2); // i point to begin of data
  213.   j := i;
  214.   i := i + len; // i point to next record
  215.   if (Name = Rname) and (QType = RType) then
  216.   begin
  217.     case RType of
  218.       QTYPE_A:
  219.         begin
  220.           Result := IntToStr(Ord(FBuffer[j]));
  221.           Inc(j);
  222.           Result := Result + '.' + IntToStr(Ord(FBuffer[j]));
  223.           Inc(j);
  224.           Result := Result + '.' + IntToStr(Ord(FBuffer[j]));
  225.           Inc(j);
  226.           Result := Result + '.' + IntToStr(Ord(FBuffer[j]));
  227.         end;
  228.       QTYPE_NS, QTYPE_MD, QTYPE_MF, QTYPE_CNAME, QTYPE_MB,
  229.         QTYPE_MG, QTYPE_MR, QTYPE_PTR, QTYPE_X25, QTYPE_NSAP,
  230.         QTYPE_NSAPPTR:
  231.         Result := DecodeLabels(j);
  232.       QTYPE_SOA:
  233.         begin
  234.           Result := DecodeLabels(j);
  235.           Result := Result + ',' + DecodeLabels(j);
  236.           for n := 1 to 5 do
  237.           begin
  238.             x := DecodeInt(FBuffer, j) * 65536 + DecodeInt(FBuffer, j + 2);
  239.             Inc(j, 4);
  240.             Result := Result + ',' + IntToStr(x);
  241.           end;
  242.         end;
  243.       QTYPE_NULL:
  244.         begin
  245.         end;
  246.       QTYPE_WKS:
  247.         begin
  248.         end;
  249.       QTYPE_HINFO, QTYPE_MINFO, QTYPE_RP, QTYPE_ISDN:
  250.         begin
  251.           Result := DecodeLabels(j);
  252.           Result := Result + ',' + DecodeLabels(j);
  253.         end;
  254.       QTYPE_MX, QTYPE_AFSDB, QTYPE_RT, QTYPE_KX:
  255.         begin
  256.           x := DecodeInt(FBuffer, j);
  257.           Inc(j, 2);
  258.           Result := IntToStr(x);
  259.           Result := Result + ',' + DecodeLabels(j);
  260.         end;
  261.       QTYPE_TXT:
  262.         Result := DecodeLabels(j);
  263.       QTYPE_GPOS:
  264.         begin
  265.           Result := DecodeLabels(j);
  266.           Result := Result + ',' + DecodeLabels(j);
  267.           Result := Result + ',' + DecodeLabels(j);
  268.         end;
  269.       QTYPE_PX:
  270.         begin
  271.           x := DecodeInt(FBuffer, j);
  272.           Inc(j, 2);
  273.           Result := IntToStr(x);
  274.           Result := Result + ',' + DecodeLabels(j);
  275.           Result := Result + ',' + DecodeLabels(j);
  276.         end;
  277.     end;
  278.   end;
  279. end;
  280.  
  281. function TDNSSend.DNSQuery(Name: string; QType: Integer;
  282.   const Reply: TStrings): Boolean;
  283. var
  284.   n, i: Integer;
  285.   flag, qdcount, ancount, nscount, arcount: Integer;
  286.   s: string;
  287. begin
  288.   Result := False;
  289.   Reply.Clear;
  290.   if IsIP(Name) then
  291.     Name := ReverseIP(Name) + '.in-addr.arpa';
  292.   FBuffer := CodeHeader + CodeQuery(Name, QType);
  293.   FSock.Connect(FDNSHost, cDnsProtocol);
  294.   FSock.SendString(FBuffer);
  295.   FBuffer := FSock.RecvPacket(FTimeout);
  296.   if (FSock.LastError = 0) and (Length(FBuffer) > 13) then
  297.   begin
  298.     flag := DecodeInt(FBuffer, 3);
  299.     FRCode := Flag and $000F;
  300.     if FRCode = 0 then
  301.     begin
  302.       qdcount := DecodeInt(FBuffer, 5);
  303.       ancount := DecodeInt(FBuffer, 7);
  304.       nscount := DecodeInt(FBuffer, 9);
  305.       arcount := DecodeInt(FBuffer, 11);
  306.       i := 13; //begin of body
  307.       if qdcount > 0 then //skip questions
  308.         for n := 1 to qdcount do
  309.         begin
  310.           while (FBuffer[i] <> #0) and ((Ord(FBuffer[i]) and $C0) <> $C0) do
  311.             Inc(i);
  312.           Inc(i, 5);
  313.         end;
  314.       if ancount > 0 then
  315.         for n := 1 to ancount do
  316.         begin
  317.           s := DecodeResource(i, Name, QType);
  318.           if s <> '' then
  319.             Reply.Add(s);
  320.         end;
  321.       Result := True;
  322.     end;
  323.   end;
  324. end;
  325.  
  326. {==============================================================================}
  327.  
  328. function GetMailServers(const DNSHost, Domain: string;
  329.   const Servers: TStrings): Boolean;
  330. var
  331.   DNS: TDNSSend;
  332.   t: TStringList;
  333.   n, m, x: Integer;
  334. begin
  335.   Result := False;
  336.   Servers.Clear;
  337.   t := TStringList.Create;
  338.   DNS := TDNSSend.Create;
  339.   try
  340.     DNS.DNSHost := DNSHost;
  341.     if DNS.DNSQuery(Domain, QType_MX, t) then
  342.     begin
  343.       { normalize preference number to 5 digits }
  344.       for n := 0 to t.Count - 1 do
  345.       begin
  346.         x := Pos(',', t[n]);
  347.         if x > 0 then
  348.           for m := 1 to 6 - x do
  349.             t[n] := '0' + t[n];
  350.       end;
  351.       { sort server list }
  352.       t.Sorted := True;
  353.       { result is sorted list without preference numbers }
  354.       for n := 0 to t.Count - 1 do
  355.       begin
  356.         x := Pos(',', t[n]);
  357.         Servers.Add(Copy(t[n], x + 1, Length(t[n]) - x));
  358.       end;
  359.       Result := True;
  360.     end;
  361.   finally
  362.     DNS.Free;
  363.     t.Free;
  364.   end;
  365. end;
  366.  
  367. end.
  368.