X-Git-Url: http://www.lcore.org/git/lcore.git/blobdiff_plain/d53fe26eaac895d1e7a0ba2b2b8965cf77932de8..096e05689a95dc55ef9f554978c5ea3f263bc919:/dnsasync.pas?ds=inline

diff --git a/dnsasync.pas b/dnsasync.pas
old mode 100755
new mode 100644
index 7a10bbf..b6e8941
--- a/dnsasync.pas
+++ b/dnsasync.pas
@@ -15,7 +15,9 @@ uses
     dnswin,
   {$endif}
   lsocket,lcore,
-  classes,binipstuff,dnscore,btime;
+  classes,binipstuff,dnscore,btime,lcorernd;
+
+{$include lcoreconfig.inc}
 
 const
   numsock=1{$ifdef ipv6}+1{$endif};
@@ -33,6 +35,8 @@ type
 
     states: array[0..numsock-1] of tdnsstate;
 
+    destinations: array[0..numsock-1] of tbinip;
+
     dnsserverids : array[0..numsock-1] of integer;
     startts:double;
     {$ifdef win32}
@@ -56,22 +60,18 @@ type
     //for this dnsasync object. This is not a reccomended mode of operation
     //because it limits the app to one dns server but is kept for compatibility
     //and special uses.
-    addr,port:string;
+    addr,port:ansistring;
 
     overrideaf : integer;
 
-    //A family value of AF_INET6 will give only
-    //ipv6 results. Any other value will give ipv4 results in preference and ipv6
-    //results if ipv4 results are not available;
-    forwardfamily:integer;
-
     procedure cancel;//cancel an outstanding dns request
-    function dnsresult:string; //get result of dnslookup as a string
+    function dnsresult:ansistring; //get result of dnslookup as a string
     procedure dnsresultbin(var binip:tbinip); //get result of dnslookup as a tbinip
     property dnsresultlist : tbiniplist read fresultlist;
-    procedure forwardlookup(const name:string); //start forward lookup,
+    procedure forwardlookup(const name:ansistring); //start forward lookup,
                                                 //preffering ipv4
     procedure reverselookup(const binip:tbinip); //start reverse lookup
+    procedure customlookup(const name:ansistring;querytype:integer); //start custom type lookup
 
     constructor create(aowner:tcomponent); override;
     destructor destroy; override;
@@ -100,12 +100,14 @@ var
   socketno : integer;
 begin
   for socketno := 0 to numsock -1 do begin
-    if dnsserverids[socketno] >= 0 then begin
-      reportlag(dnsserverids[socketno],-1);
-      dnsserverids[socketno] := -1;
+    if assigned(sockets[socketno]) then begin
+      if dnsserverids[socketno] >= 0 then begin
+        reportlag(dnsserverids[socketno],-1);
+        dnsserverids[socketno] := -1;
+      end;
+      sockets[socketno].release;
+      setstate_request_init('',states[socketno]);
     end;
-    sockets[socketno].release;
-    setstate_request_init('',states[socketno]);
   end;
   inherited destroy;
 end;
@@ -113,16 +115,31 @@ end;
 procedure tdnsasync.receivehandler(sender:tobject;error:word);
 var
   socketno : integer;
+  Src    : TInetSockAddrV;
+  SrcLen : Integer;
+  fromip:tbinip;
+  fromport:ansistring;
 begin
   socketno := tlsocket(sender).tag;
   //writeln('got a reply on socket number ',socketno);
   fillchar(states[socketno].recvpacket,sizeof(states[socketno].recvpacket),0);
-  states[socketno].recvpacketlen := twsocket(sender).Receive(@(states[socketno].recvpacket), SizeOf(states[socketno].recvpacket));
+
+  SrcLen := SizeOf(Src);
+  states[socketno].recvpacketlen := twsocket(sender).ReceiveFrom(@(states[socketno].recvpacket), SizeOf(states[socketno].recvpacket), Src, SrcLen);
+
+  fromip := inaddrvtobinip(Src);
+  fromport := inttostr(htons(src.InAddr.port));
+
+  if ((not comparebinip(fromip,destinations[socketno])) or (fromport <> port)) then begin
+   // writeln('dnsasync received from wrong IP:port ',ipbintostr(fromip),'#',fromport,', expected ',ipbintostr(destinations[socketno]),'#',port);
+    exit;
+  end;
+
   states[socketno].parsepacket := true;
   if states[socketno].resultaction <> action_done then begin
     //we ignore packets that come after we are done
     if dnsserverids[socketno] >= 0 then begin
-      reportlag(dnsserverids[socketno],trunc((unixtimefloat-startts)*1000));
+      reportlag(dnsserverids[socketno],trunc((unixtimefloat-startts)*1000000));
       dnsserverids[socketno] := -1;
     end;
   {  writeln('received reply');}
@@ -136,8 +153,9 @@ end;
 
 function tdnsasync.sendquery(socketno:integer;const packet:tdnspacket;len:integer):boolean;
 var
-  destination : string;
+  destination : tbinip;
   inaddr : tinetsockaddrv;
+  trytolisten:integer;
 begin
 {  writeln('sendquery ',decodename(state.packet,state.packetlen,12,0,a),' ',state.requesttype);}
   //writeln('trying to send query on socket number ',socketno);
@@ -148,21 +166,36 @@ begin
     if port = '' then port := '53';
     sockets[socketno].Proto := 'udp';
     sockets[socketno].ondataavailable := receivehandler;
-    try
-      sockets[socketno].listen;
-    except
-      result := false;
-      exit;
+
+    {we are going to bind on a random local port for the DNS request, against the kaminsky attack
+    there is a small chance that we're trying to bind on an already used port, so retry a few times}
+    for trytolisten := 3 downto 0 do begin
+      try
+        sockets[socketno].port := inttostr(1024 + randominteger(65536 - 1024));
+        sockets[socketno].listen;
+      except
+        {writeln('failed to listen ',sockets[socketno].localport,' ',trytolisten);}
+        if (trytolisten = 0) then begin
+          result := false;
+          exit;
+        end;
+      end;
     end;
 
   end;
   if addr <> '' then begin
     dnsserverids[socketno] := -1;
-    destination := addr
+    destination := ipstrtobinf(addr);
   end else begin
-    destination := getcurrentsystemnameserver(dnsserverids[socketno]);
+    destination := getcurrentsystemnameserverbin(dnsserverids[socketno]);
   end;
-  makeinaddrv(ipstrtobinf(destination),port,inaddr);
+  destinations[socketno] := destination;
+
+  {$ifdef ipv6}{$ifdef win32}
+  if destinations[socketno].family = AF_INET6 then if (requestaf = useaf_default) then requestaf := useaf_preferv6;
+  {$endif}{$endif}
+
+  makeinaddrv(destinations[socketno],port,inaddr);
   sockets[socketno].sendto(inaddr,sizeof(inaddr), @packet,len);
   result := true;
 
@@ -212,7 +245,6 @@ var
   bip : tbinip;
   i : integer;
 begin
-
   ipstrtobin(name,bip);
 
   if bip.family <> 0 then begin
@@ -224,21 +256,22 @@ begin
   end;
 
   if overrideaf = useaf_default then begin
-    {$ifdef linux}{$ifdef ipv6}initpreferredmode;{$endif}{$endif}
+    {$ifdef ipv6}
+      {$ifdef win32}if not (usewindns and (addr = '')) then{$endif}
+      initpreferredmode;
+    {$endif}
     requestaf := useaf;
   end else begin
     requestaf := overrideaf;
   end;
 
   {$ifdef win32}
-    if usewindns or (addr = '') then begin
+    if usewindns and (addr = '') then begin
       dwas := tdnswinasync.create;
       dwas.onrequestdone := winrequestdone;
-      if forwardfamily = AF_INET6 then begin
-        dwas.forwardlookup(name,true);
-      end else begin
-        dwas.forwardlookup(name,false);
-      end;
+
+      dwas.forwardlookup(name);
+
       exit;
     end;
   {$endif}
@@ -256,17 +289,16 @@ begin
       inc(numsockused);
     end;
   {$endif}
+
   for i := 0 to numsockused-1 do begin
     asyncprocess(i);
   end;
-
 end;
 
 procedure tdnsasync.reverselookup;
-
 begin
   {$ifdef win32}
-    if usewindns or (addr = '') then begin
+    if usewindns and (addr = '') then begin
       dwas := tdnswinasync.create;
       dwas.onrequestdone := winrequestdone;
       dwas.reverselookup(binip);
@@ -279,6 +311,13 @@ begin
   asyncprocess(0);
 end;
 
+procedure tdnsasync.customlookup;
+begin
+  setstate_custom(name,querytype,states[0]);
+  numsockused := 1;
+  asyncprocess(0);
+end;
+
 function tdnsasync.dnsresult;
 begin
   if states[0].resultstr <> '' then result := states[0].resultstr else begin
@@ -322,7 +361,7 @@ end;
   procedure tdnsasync.winrequestdone(sender:tobject;error:word);
  
   begin
-    if dwas.reverse then begin 
+    if dwas.reverse then begin
       states[0].resultstr := dwas.name;
     end else begin