Delphi Web.HTTPApp.TWebRequest RemoteIP VS RemoteAddr - delphi

TWebRequest has two metnod for retrive the client IP Address:
RemoteIP
RemoteAddr
From docs of RemoteIP:
Specifies the IP of the remote target machine associated with the HTTP
request message. Read the RemoteIP property to obtain the IP address
of the remote target machine associated with the HTTP request message.
From docs of RemoteAddr:
Indicates the remote IP address of the client associated with the HTTP
request message. Read RemoteAddr to obtain the IP address of the
source of the Web client request.
They seem very close but RemoteIP return an empty string.
I want retrieve the client ip address, what is the right method?

If we look into source code we will find the following in the declaration of TWebRequest
property RemoteIP: string read GetRemoteIP;
property RemoteAddr: string index 21 read GetStringVariable;
Implementation:
function TWebRequest.GetRemoteIP: string;
begin
Result := EmptyStr;
end;
and GetStringVariable is a virtual method.
Let's look into one of child classes - TISAPIRequest, we will find the following:
LResult := GetFieldByNameA(ServerVariables[Index]);
ServerVariables[21] is 'REMOTE_ADDR' header, which shows IP of client or proxy server.
But there is no implementation for GetRemoteIP.
It looks like RemoteIP isn't used in requests, because TCGIRequest, TApacheRequest and TWinCGIRequest also don't implement GetRemoteIP.

Related

Indy TIdSocksServer not forwarding traffic

I am attempting to create a SOCKS 4/5 server, and I would like to use the Indy TIdSocksServer component as the foundation. It seems straight forward enough and simple to use, but I must be missing something.
I dropped a TIdSocksServer onto a new Form and configured the following:
Active: True
AllowSocks4: True
AllowSocks5: True
Bindings: 0.0.0.0:43334
Default Port: 80
Intercept: null
IOHandler: null
I added code to display 'connect' in a TMemo upon connection:
procedure TForm1.IdSocksServer1Connect(AContext: TIdContext);
begin
Memo1.Lines.Add('connect');
end;
I configured ProxyChains on a Linux host:
/etc/proxychains.conf
...
socks5 10.0.0.56 43334
When I execute the App and try to connect using ProxyChains, I get the following error:
kelly#ubuntu:~/home$ proxychains curl www.google.com
ProxyChains-3.1 (http://proxychains.sf.net)
|DNS-request| www.google.com
|S-chain|-<>-10.0.0.56:43334-<><>-4.2.2.2:53-<--timeout
|DNS-response|: www.google.com does not exist
curl: (6) Could not resolve host: www.google.com
I can confirm that the connection is established, because the text 'connect' gets added to the Memo. I also used Wireshark and observed the three-way handshake and teardown between my Ubuntu host and the Windows host.
It seems the issue is that the traffic is reaching the SOCKS server, but not getting forwarded. I acknowledge that this is absolute minimum code, but I am under the impression that the TIdSocksServer component would take care of forwarding the traffic, and I would add in supporting functions such as validating credentials for SOCKS5, etc.
Remy identified the issue with my code. In order to verify that the server was receiving connections I added a procedure which wrote to a TMemo component, which was causing a deadlock. To fix the error all I had to do was remove the procedure which was updating the TMemo component. Works as expected.

Delphi Indy https request with custom DNS resolving

example url:
https://api.binance.com/api/v1/time
Using TIdDNSResolver and cloudflare dns I can get the host IP.
direct request in the form of
https://205.251.219.20/api/v1/time
doesn't work cause as I understand the server expects to see "api.binance.com" in the url. (it doesnt work even in browser)
Using synapce and the following patch to replace request's host with resolved IP I make it working
function THTTPSend.InternalDoConnect(needssl: Boolean): Boolean;
begin
Result := False;
FSock.CloseSocket;
FSock.Bind(FIPInterface, cAnyPort);
if FSock.LastError <> 0 then
Exit;
If ResolvedIP.IsEmpty
then FSock.Connect(FTargetHost, FTargetPort)
else FSock.Connect(ResolvedIP, FTargetPort); // !!
Is there any way to do the same using Indy?
By default, TIdHTTP uses the Host:Port that is specified/inferred by the URL that is being requested. To change that behavior, you would have to alter TIdHTTP's source code, such as in the TIdCustomHTTP.SetHostAndPort() or TIdCustomHTTP.CheckAndConnect() method (which are both not virtual), and then recompile Indy.
Alternatively, you could use TIdHTTP's OnSocketAllocated or On(Before|After)Bind event (which are not promoted to published in TIdHTTP, so you would have to access them manually at runtime) to change the TIdHTTP.IOHandler.Host property to whatever IP address you want to connect to. This will not have any affect on the HTTP headers that TIdHTTP sends, such as Host, which will still be taken from the URL.
Alternatively, if you want all of Indy's Host-to-IP DNS queries to go through Cloudflare, you could derive a custom class from TIdStack (or whatever platform-specific descendant you are interested in, such as TIdStackWindows), override its virtual HostByName() method to perform whatever DNS query you want, and then pass your class type to the SetStackClass() function in the IdStack unit at program startup before any Indy classes are instantiated.

Indy HTTP: Cannot change Host header [duplicate]

This question already has an answer here:
Delphi Indy https request with custom DNS resolving
(1 answer)
Closed 3 years ago.
I'm trying to change Host header before sending get request to a website. I do that using this code:
IdHTTP1.Request.HOST := 'example.com';
memo1.Text := IdHTTP1.Get('http://stackoverflow.com');
showmessage(IdHTTP1.Request.Host); // Expected to be example.com but it's stackoverflow.com
I've got a big problem here. Even though I change Host header before getting URL, Host header will change to stackoverflow.com again. What am I doing wrong? I want to change request header to example.com.
Thanks
Unfortunately, there is no option to specify a custom Host header that specifies a different hostname than the one specified in the URL. The URL has priority. Any hostname you specify in the Request.Host or even the Request.CustomHeaders is overwritten by the hostname in the URL.
If the hostname in the URL is not registered with DNS, you will not be able to reach it with any web browser, or most HTTP libraries including TIdHTTP. While the HTTP protocol itself defines how the Host header works, current web browser technology uses the hostname from the URL, and so does TIdHTTP. So it does not make sense to have a website that uses a hostname that is not registered with DNS in the first place, as most modern client systems would not be able to retrieve it. DNS is required to convert the URL's hostname into an IP address, and then the same hostname is put into the Host header.
As Remy Lebeau said, it seems there is no way to specify a custom Host header. So I decided to modify IdHTTP codes just a little bit.
First I copied IdHTTP.pas (C:\Program Files (x86)\Embarcadero\Studio\XX.0\source\Indy10\Protocols\IdHTTP.pas) to my project directory and added it to my project. Then in TIdCustomHTTP.PrepareRequestmethod (Line 1792) I changed the code like this:
if (TextIsSame(FURI.Protocol, 'http') and (FURI.Port = IntToStr(IdPORT_HTTP))) or {do not localize}
(TextIsSame(FURI.Protocol, 'https') and (FURI.Port = IntToStr(IdPORT_https))) then {do not localize}
begin
if FURI.Host = 'stackoverflow.com' then
ARequest.Host := 'example.com'
else
ARequest.Host := FURI.Host;
end else begin
if FURI.Host = 'stackoverflow.com' then
ARequest.Host := 'example.com' + ':' + FURI.Port {do not localize}
else
ARequest.Host := FURI.Host + ':' + FURI.Port; {do not localize}
end;
I know it's not the best way and modifying libraries is not a good idea but it worked for me.
So if I change the examples above, stackoverflow.com to myblog.wordpress.com and example.com to anotherblog.wordpress.com, By IdHTTP1.Get('http://myblog.wordpress.com') we will get anotherblog.wordpress.com content.

How to filter requests on Delphi datasnap rest server?

I'm new to this delphi datasnap stuff and there are barely any useful documentations about it.
I've setup a simple rest server by following this guide. Now I want to define my own authentication protocol.
As far as I know. All requests came from remote clients will be processed through WebModule methods before invoking server class methods. So far, I was able to capture the client IP adress and the requesting URL path like this:
procedure TWebModule1.WebModuleBeforeDispatch(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
ShowMessage(request.RemoteAddr); // adress where request came from
ShowMessage(request.PathInfo); // url path
Response.SetCustomHeader('access-control-allow-origin','*');
if FServerFunctionInvokerAction <> nil then
FServerFunctionInvokerAction.Enabled := AllowServerFunctionInvoker;
end;
How am I able to:
Reject requests depend on specific IP addresses and return 401 status code to clients before they reach the class methods?
Redirect client to another methods? For example: Redirect this resquest:
request = new XMLHttpRequest();
request.open('GET', 'http://localhost:8080/datasnap/rest/TServerMethods1/ReverseString/blah', true);
To another method instead of ReverseString.
Complex redirection scenarios can be handled with an Apache HTTP server as reverse proxy with the mod_rewrite module.
For example, this answer shows that client IP addresses can be used to trigger a redirection.
https://stackoverflow.com/a/1073877/80901
RewriteCond %{REMOTE_ADDR} !^10\.0\.1\.1$
RewriteRule ^ /maintenance.html
this would send all requests with some exception to a maintenance page.
Using Apache (or a different HTTP proxy server) also allows to keep the DataSnap server running continuously, while Apache configuration changes are applied. This will remove your server down time virtually to zero.

Indy Mail server

Following is my code for the smtp client for sending email
VAR SMTP : TIdSMTP;
MSG : TIdmessage;
begin
MSG:=TIdmessage.Create(NIL);
TRY
WITH MSG.Recipients.Add DO BEGIN
Name:='me025';
Address:='me025#gmail.com'
END;
MSG.BccList.Add.Address:='me025#yahoo.com';
MSG.From.Name:='self025';
MSG.From.Address:='self025#127.0.1.1';
MSG.Body.Text:='<Message Body>';
MSG.Subject:='<Subject of message>';
SMTP:=TIdSMTP.Create(NIL);
TRY
SMTP.Host:='127.0.1.1'; // IP Address of SMTP server
// 127.0.1.1
SMTP.Port:=25; // Port address of SMTP service (usually 25)
SMTP.Connect;
TRY
SMTP.Send(MSG)
FINALLY
SMTP.Disconnect
END
FINALLY
SMTP.Free
END
FINALLY
MSG.Free
END;
end;
which will use a SMTPserver in same pc
the smtp server is a working indy 10 unofficial sample
http://indy.fulgan.com/ZIP/Indy10demo.zip
whenever i connect to the server "Socket error # 11001 Host not found " error occers
but smtp server is receiving all the parameters correctly and showing correctly on the GUI
Has your PC an address of 127.0.1.1 or are you trying to use localhost (127.0.0.1)? People should get used to DNS names... as soon as IPv6 will become mainstream at least people won't be able any longer to remember IP numbers easily :)

Resources