* fixed NT services not working. app must now call lcoreinit() at some point before...
[lcore.git] / dnsasync.pas
index 7a10bbfdc7cc0466942906c68617712309317e22..8c3ce3a01d4afca44a754a3f268ca826fb6452ed 100755 (executable)
@@ -15,7 +15,9 @@ uses
     dnswin,\r
   {$endif}\r
   lsocket,lcore,\r
-  classes,binipstuff,dnscore,btime;\r
+  classes,binipstuff,dnscore,btime,lcorernd;\r
+\r
+{$include lcoreconfig.inc}\r
 \r
 const\r
   numsock=1{$ifdef ipv6}+1{$endif};\r
@@ -33,6 +35,8 @@ type
 \r
     states: array[0..numsock-1] of tdnsstate;\r
 \r
+    destinations: array[0..numsock-1] of tbinip;\r
+\r
     dnsserverids : array[0..numsock-1] of integer;\r
     startts:double;\r
     {$ifdef win32}\r
@@ -60,11 +64,6 @@ type
 \r
     overrideaf : integer;\r
 \r
-    //A family value of AF_INET6 will give only\r
-    //ipv6 results. Any other value will give ipv4 results in preference and ipv6\r
-    //results if ipv4 results are not available;\r
-    forwardfamily:integer;\r
-\r
     procedure cancel;//cancel an outstanding dns request\r
     function dnsresult:string; //get result of dnslookup as a string\r
     procedure dnsresultbin(var binip:tbinip); //get result of dnslookup as a tbinip\r
@@ -72,6 +71,7 @@ type
     procedure forwardlookup(const name:string); //start forward lookup,\r
                                                 //preffering ipv4\r
     procedure reverselookup(const binip:tbinip); //start reverse lookup\r
+    procedure customlookup(const name:string;querytype:integer); //start custom type lookup\r
 \r
     constructor create(aowner:tcomponent); override;\r
     destructor destroy; override;\r
@@ -113,16 +113,31 @@ end;
 procedure tdnsasync.receivehandler(sender:tobject;error:word);\r
 var\r
   socketno : integer;\r
+  Src    : TInetSockAddrV;\r
+  SrcLen : Integer;\r
+  fromip:tbinip;\r
+  fromport:string;\r
 begin\r
   socketno := tlsocket(sender).tag;\r
   //writeln('got a reply on socket number ',socketno);\r
   fillchar(states[socketno].recvpacket,sizeof(states[socketno].recvpacket),0);\r
-  states[socketno].recvpacketlen := twsocket(sender).Receive(@(states[socketno].recvpacket), SizeOf(states[socketno].recvpacket));\r
+\r
+  SrcLen := SizeOf(Src);\r
+  states[socketno].recvpacketlen := twsocket(sender).ReceiveFrom(@(states[socketno].recvpacket), SizeOf(states[socketno].recvpacket), Src, SrcLen);\r
+\r
+  fromip := inaddrvtobinip(Src);\r
+  fromport := inttostr(htons(src.InAddr.port));\r
+\r
+  if ((not comparebinip(fromip,destinations[socketno])) or (fromport <> port)) then begin\r
+   // writeln('dnsasync received from wrong IP:port ',ipbintostr(fromip),'#',fromport,', expected ',ipbintostr(destinations[socketno]),'#',port);\r
+    exit;\r
+  end;\r
+\r
   states[socketno].parsepacket := true;\r
   if states[socketno].resultaction <> action_done then begin\r
     //we ignore packets that come after we are done\r
     if dnsserverids[socketno] >= 0 then begin\r
-      reportlag(dnsserverids[socketno],trunc((unixtimefloat-startts)*1000));\r
+      reportlag(dnsserverids[socketno],trunc((unixtimefloat-startts)*1000000));\r
       dnsserverids[socketno] := -1;\r
     end;\r
   {  writeln('received reply');}\r
@@ -138,6 +153,7 @@ function tdnsasync.sendquery(socketno:integer;const packet:tdnspacket;len:intege
 var\r
   destination : string;\r
   inaddr : tinetsockaddrv;\r
+  trytolisten:integer;\r
 begin\r
 {  writeln('sendquery ',decodename(state.packet,state.packetlen,12,0,a),' ',state.requesttype);}\r
   //writeln('trying to send query on socket number ',socketno);\r
@@ -148,11 +164,20 @@ begin
     if port = '' then port := '53';\r
     sockets[socketno].Proto := 'udp';\r
     sockets[socketno].ondataavailable := receivehandler;\r
-    try\r
-      sockets[socketno].listen;\r
-    except\r
-      result := false;\r
-      exit;\r
+\r
+    {we are going to bind on a random local port for the DNS request, against the kaminsky attack\r
+    there is a small chance that we're trying to bind on an already used port, so retry a few times}\r
+    for trytolisten := 3 downto 0 do begin\r
+      try\r
+        sockets[socketno].port := inttostr(1024 + randominteger(65536 - 1024));\r
+        sockets[socketno].listen;\r
+      except\r
+        {writeln('failed to listen ',sockets[socketno].localport,' ',trytolisten);}\r
+        if (trytolisten = 0) then begin\r
+          result := false;\r
+          exit;\r
+        end;\r
+      end;\r
     end;\r
 \r
   end;\r
@@ -162,7 +187,13 @@ begin
   end else begin\r
     destination := getcurrentsystemnameserver(dnsserverids[socketno]);\r
   end;\r
-  makeinaddrv(ipstrtobinf(destination),port,inaddr);\r
+  destinations[socketno] := ipstrtobinf(destination);\r
+\r
+  {$ifdef ipv6}{$ifdef win32}\r
+  if destinations[socketno].family = AF_INET6 then if (requestaf = useaf_default) then requestaf := useaf_preferv6;\r
+  {$endif}{$endif}\r
+\r
+  makeinaddrv(destinations[socketno],port,inaddr);\r
   sockets[socketno].sendto(inaddr,sizeof(inaddr), @packet,len);\r
   result := true;\r
 \r
@@ -212,7 +243,6 @@ var
   bip : tbinip;\r
   i : integer;\r
 begin\r
-\r
   ipstrtobin(name,bip);\r
 \r
   if bip.family <> 0 then begin\r
@@ -223,22 +253,25 @@ begin
     exit;\r
   end;\r
 \r
+  if (overridednsserver <> '') and (addr = '') then addr := overridednsserver;\r
+\r
   if overrideaf = useaf_default then begin\r
-    {$ifdef linux}{$ifdef ipv6}initpreferredmode;{$endif}{$endif}\r
+    {$ifdef ipv6}\r
+      {$ifdef win32}if not (usewindns and (addr = '')) then{$endif}\r
+      initpreferredmode;\r
+    {$endif}\r
     requestaf := useaf;\r
   end else begin\r
     requestaf := overrideaf;\r
   end;\r
 \r
   {$ifdef win32}\r
-    if usewindns or (addr = '') then begin\r
+    if usewindns and (addr = '') then begin\r
       dwas := tdnswinasync.create;\r
       dwas.onrequestdone := winrequestdone;\r
-      if forwardfamily = AF_INET6 then begin\r
-        dwas.forwardlookup(name,true);\r
-      end else begin\r
-        dwas.forwardlookup(name,false);\r
-      end;\r
+\r
+      dwas.forwardlookup(name);\r
+\r
       exit;\r
     end;\r
   {$endif}\r
@@ -263,10 +296,10 @@ begin
 end;\r
 \r
 procedure tdnsasync.reverselookup;\r
-\r
 begin\r
+  if (overridednsserver <> '') and (addr = '') then addr := overridednsserver;\r
   {$ifdef win32}\r
-    if usewindns or (addr = '') then begin\r
+    if usewindns and (addr = '') then begin\r
       dwas := tdnswinasync.create;\r
       dwas.onrequestdone := winrequestdone;\r
       dwas.reverselookup(binip);\r
@@ -279,6 +312,14 @@ begin
   asyncprocess(0);\r
 end;\r
 \r
+procedure tdnsasync.customlookup;\r
+begin\r
+  if (overridednsserver <> '') and (addr = '') then addr := overridednsserver;\r
+  setstate_custom(name,querytype,states[0]);\r
+  numsockused := 1;\r
+  asyncprocess(0);\r
+end;\r
+\r
 function tdnsasync.dnsresult;\r
 begin\r
   if states[0].resultstr <> '' then result := states[0].resultstr else begin\r
@@ -322,7 +363,7 @@ end;
   procedure tdnsasync.winrequestdone(sender:tobject;error:word);\r
  \r
   begin\r
-    if dwas.reverse then begin \r
+    if dwas.reverse then begin\r
       states[0].resultstr := dwas.name;\r
     end else begin \r
 \r